github.com/khulnasoft/cli@v0.0.0-20240402070845-01bcad7beefa/cli/command/volume/prune.go (about) 1 package volume 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/docker/docker/api/types/versions" 8 "github.com/docker/docker/errdefs" 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/pkg/errors" 15 "github.com/spf13/cobra" 16 ) 17 18 type pruneOptions struct { 19 all bool 20 force bool 21 filter opts.FilterOpt 22 } 23 24 // NewPruneCommand returns a new cobra prune command for volumes 25 func NewPruneCommand(dockerCli command.Cli) *cobra.Command { 26 options := pruneOptions{filter: opts.NewFilterOpt()} 27 28 cmd := &cobra.Command{ 29 Use: "prune [OPTIONS]", 30 Short: "Remove unused local volumes", 31 Args: cli.NoArgs, 32 RunE: func(cmd *cobra.Command, args []string) error { 33 spaceReclaimed, output, err := runPrune(cmd.Context(), dockerCli, options) 34 if err != nil { 35 if errdefs.IsCancelled(err) { 36 fmt.Fprintln(dockerCli.Out(), output) 37 return nil 38 } 39 return err 40 } 41 if output != "" { 42 fmt.Fprintln(dockerCli.Out(), output) 43 } 44 fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed))) 45 return nil 46 }, 47 Annotations: map[string]string{"version": "1.25"}, 48 ValidArgsFunction: completion.NoComplete, 49 } 50 51 flags := cmd.Flags() 52 flags.BoolVarP(&options.all, "all", "a", false, "Remove all unused volumes, not just anonymous ones") 53 flags.SetAnnotation("all", "version", []string{"1.42"}) 54 flags.BoolVarP(&options.force, "force", "f", false, "Do not prompt for confirmation") 55 flags.Var(&options.filter, "filter", `Provide filter values (e.g. "label=<label>")`) 56 57 return cmd 58 } 59 60 const ( 61 unusedVolumesWarning = `WARNING! This will remove anonymous local volumes not used by at least one container. 62 Are you sure you want to continue?` 63 allVolumesWarning = `WARNING! This will remove all local volumes not used by at least one container. 64 Are you sure you want to continue?` 65 ) 66 67 func runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions) (spaceReclaimed uint64, output string, err error) { 68 pruneFilters := command.PruneFilters(dockerCli, options.filter.Value()) 69 70 warning := unusedVolumesWarning 71 if versions.GreaterThanOrEqualTo(dockerCli.CurrentVersion(), "1.42") { 72 if options.all { 73 if pruneFilters.Contains("all") { 74 return 0, "", errdefs.InvalidParameter(errors.New("conflicting options: cannot specify both --all and --filter all=1")) 75 } 76 pruneFilters.Add("all", "true") 77 warning = allVolumesWarning 78 } 79 } else { 80 // API < v1.42 removes all volumes (anonymous and named) by default. 81 warning = allVolumesWarning 82 } 83 if !options.force { 84 if r, err := command.PromptForConfirmation(ctx, dockerCli.In(), dockerCli.Out(), warning); !r || err != nil { 85 return 0, "", errdefs.Cancelled(errors.New("user cancelled operation")) 86 } 87 } 88 89 report, err := dockerCli.Client().VolumesPrune(ctx, pruneFilters) 90 if err != nil { 91 return 0, "", err 92 } 93 94 if len(report.VolumesDeleted) > 0 { 95 output = "Deleted Volumes:\n" 96 for _, id := range report.VolumesDeleted { 97 output += id + "\n" 98 } 99 spaceReclaimed = report.SpaceReclaimed 100 } 101 102 return spaceReclaimed, output, nil 103 } 104 105 // RunPrune calls the Volume Prune API 106 // This returns the amount of space reclaimed and a detailed output string 107 func RunPrune(ctx context.Context, dockerCli command.Cli, _ bool, filter opts.FilterOpt) (uint64, string, error) { 108 return runPrune(ctx, dockerCli, pruneOptions{force: true, filter: filter}) 109 }