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