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 }