diff --git a/components/cli/cli/command/system/prune.go b/components/cli/cli/command/system/prune.go index 11a45146a7b..43569294166 100644 --- a/components/cli/cli/command/system/prune.go +++ b/components/cli/cli/command/system/prune.go @@ -1,7 +1,9 @@ package system import ( + "bytes" "fmt" + "text/template" "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" @@ -12,9 +14,10 @@ import ( ) type pruneOptions struct { - force bool - all bool - filter opts.FilterOpt + force bool + all bool + pruneVolumes bool + filter opts.FilterOpt } // NewPruneCommand creates a new cobra.Command for `docker prune` @@ -34,6 +37,7 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command { flags := cmd.Flags() flags.BoolVarP(&options.force, "force", "f", false, "Do not prompt for confirmation") flags.BoolVarP(&options.all, "all", "a", false, "Remove all unused images not just dangling ones") + flags.BoolVar(&options.pruneVolumes, "volumes", false, "Prune volumes") flags.Var(&options.filter, "filter", "Provide filter values (e.g. 'label==')") // "filter" flag is available in 1.28 (docker 17.04) and up flags.SetAnnotation("filter", "version", []string{"1.28"}) @@ -41,38 +45,27 @@ func NewPruneCommand(dockerCli command.Cli) *cobra.Command { return cmd } -const ( - warning = `WARNING! This will remove: - - all stopped containers - - all volumes not used by at least one container - - all networks not used by at least one container - %s +const confirmationTemplate = `WARNING! This will remove: +{{- range $_, $warning := . }} + - {{ $warning }} +{{- end }} Are you sure you want to continue?` - danglingImageDesc = "- all dangling images" - allImageDesc = `- all images without at least one container associated to them` -) - func runPrune(dockerCli command.Cli, options pruneOptions) error { - var message string - - if options.all { - message = fmt.Sprintf(warning, allImageDesc) - } else { - message = fmt.Sprintf(warning, danglingImageDesc) - } - - if !options.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), message) { + if !options.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), confirmationMessage(options)) { return nil } var spaceReclaimed uint64 - - for _, pruneFn := range []func(dockerCli command.Cli, filter opts.FilterOpt) (uint64, string, error){ + pruneFuncs := []func(dockerCli command.Cli, filter opts.FilterOpt) (uint64, string, error){ prune.RunContainerPrune, - prune.RunVolumePrune, prune.RunNetworkPrune, - } { + } + if options.pruneVolumes { + pruneFuncs = append(pruneFuncs, prune.RunVolumePrune) + } + + for _, pruneFn := range pruneFuncs { spc, output, err := pruneFn(dockerCli, options.filter) if err != nil { return err @@ -96,3 +89,26 @@ func runPrune(dockerCli command.Cli, options pruneOptions) error { return nil } + +// confirmationMessage constructs a confirmation message that depends on the cli options. +func confirmationMessage(options pruneOptions) string { + t := template.Must(template.New("confirmation message").Parse(confirmationTemplate)) + + warnings := []string{ + "all stopped containers", + "all networks not used by at least one container", + } + if options.pruneVolumes { + warnings = append(warnings, "all volumes not used by at least one container") + } + if options.all { + warnings = append(warnings, "all images without at least one container associated to them") + } else { + warnings = append(warnings, "all dangling images") + } + warnings = append(warnings, "all build cache") + + var buffer bytes.Buffer + t.Execute(&buffer, &warnings) + return buffer.String() +}