github.com/panekj/cli@v0.0.0-20230304125325-467dd2f3797e/cli/command/image/prune.go (about)

     1  package image
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/docker/cli/cli"
     9  	"github.com/docker/cli/cli/command"
    10  	"github.com/docker/cli/cli/command/completion"
    11  	"github.com/docker/cli/opts"
    12  	units "github.com/docker/go-units"
    13  	"github.com/spf13/cobra"
    14  )
    15  
    16  type pruneOptions struct {
    17  	force  bool
    18  	all    bool
    19  	filter opts.FilterOpt
    20  }
    21  
    22  // NewPruneCommand returns a new cobra prune command for images
    23  func NewPruneCommand(dockerCli command.Cli) *cobra.Command {
    24  	options := pruneOptions{filter: opts.NewFilterOpt()}
    25  
    26  	cmd := &cobra.Command{
    27  		Use:   "prune [OPTIONS]",
    28  		Short: "Remove unused images",
    29  		Args:  cli.NoArgs,
    30  		RunE: func(cmd *cobra.Command, args []string) error {
    31  			spaceReclaimed, output, err := runPrune(dockerCli, options)
    32  			if err != nil {
    33  				return err
    34  			}
    35  			if output != "" {
    36  				fmt.Fprintln(dockerCli.Out(), output)
    37  			}
    38  			fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
    39  			return nil
    40  		},
    41  		Annotations:       map[string]string{"version": "1.25"},
    42  		ValidArgsFunction: completion.NoComplete,
    43  	}
    44  
    45  	flags := cmd.Flags()
    46  	flags.BoolVarP(&options.force, "force", "f", false, "Do not prompt for confirmation")
    47  	flags.BoolVarP(&options.all, "all", "a", false, "Remove all unused images, not just dangling ones")
    48  	flags.Var(&options.filter, "filter", `Provide filter values (e.g. "until=<timestamp>")`)
    49  
    50  	return cmd
    51  }
    52  
    53  const (
    54  	allImageWarning = `WARNING! This will remove all images without at least one container associated to them.
    55  Are you sure you want to continue?`
    56  	danglingWarning = `WARNING! This will remove all dangling images.
    57  Are you sure you want to continue?`
    58  )
    59  
    60  func runPrune(dockerCli command.Cli, options pruneOptions) (spaceReclaimed uint64, output string, err error) {
    61  	pruneFilters := options.filter.Value().Clone()
    62  	pruneFilters.Add("dangling", fmt.Sprintf("%v", !options.all))
    63  	pruneFilters = command.PruneFilters(dockerCli, pruneFilters)
    64  
    65  	warning := danglingWarning
    66  	if options.all {
    67  		warning = allImageWarning
    68  	}
    69  	if !options.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
    70  		return 0, "", nil
    71  	}
    72  
    73  	report, err := dockerCli.Client().ImagesPrune(context.Background(), pruneFilters)
    74  	if err != nil {
    75  		return 0, "", err
    76  	}
    77  
    78  	if len(report.ImagesDeleted) > 0 {
    79  		var sb strings.Builder
    80  		sb.WriteString("Deleted Images:\n")
    81  		for _, st := range report.ImagesDeleted {
    82  			if st.Untagged != "" {
    83  				sb.WriteString("untagged: ")
    84  				sb.WriteString(st.Untagged)
    85  				sb.WriteByte('\n')
    86  			} else {
    87  				sb.WriteString("deleted: ")
    88  				sb.WriteString(st.Deleted)
    89  				sb.WriteByte('\n')
    90  			}
    91  		}
    92  		output = sb.String()
    93  		spaceReclaimed = report.SpaceReclaimed
    94  	}
    95  
    96  	return spaceReclaimed, output, nil
    97  }
    98  
    99  // RunPrune calls the Image Prune API
   100  // This returns the amount of space reclaimed and a detailed output string
   101  func RunPrune(dockerCli command.Cli, all bool, filter opts.FilterOpt) (uint64, string, error) {
   102  	return runPrune(dockerCli, pruneOptions{force: true, all: all, filter: filter})
   103  }