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