prune.go 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package image
  2. import (
  3. "fmt"
  4. "golang.org/x/net/context"
  5. "github.com/docker/docker/cli"
  6. "github.com/docker/docker/cli/command"
  7. "github.com/docker/docker/opts"
  8. units "github.com/docker/go-units"
  9. "github.com/spf13/cobra"
  10. )
  11. type pruneOptions struct {
  12. force bool
  13. all bool
  14. filter opts.FilterOpt
  15. }
  16. // NewPruneCommand returns a new cobra prune command for images
  17. func NewPruneCommand(dockerCli *command.DockerCli) *cobra.Command {
  18. opts := pruneOptions{filter: opts.NewFilterOpt()}
  19. cmd := &cobra.Command{
  20. Use: "prune [OPTIONS]",
  21. Short: "Remove unused images",
  22. Args: cli.NoArgs,
  23. RunE: func(cmd *cobra.Command, args []string) error {
  24. spaceReclaimed, output, err := runPrune(dockerCli, opts)
  25. if err != nil {
  26. return err
  27. }
  28. if output != "" {
  29. fmt.Fprintln(dockerCli.Out(), output)
  30. }
  31. fmt.Fprintln(dockerCli.Out(), "Total reclaimed space:", units.HumanSize(float64(spaceReclaimed)))
  32. return nil
  33. },
  34. Tags: map[string]string{"version": "1.25"},
  35. }
  36. flags := cmd.Flags()
  37. flags.BoolVarP(&opts.force, "force", "f", false, "Do not prompt for confirmation")
  38. flags.BoolVarP(&opts.all, "all", "a", false, "Remove all unused images, not just dangling ones")
  39. flags.Var(&opts.filter, "filter", "Provide filter values (e.g. 'until=<timestamp>')")
  40. return cmd
  41. }
  42. const (
  43. allImageWarning = `WARNING! This will remove all images without at least one container associated to them.
  44. Are you sure you want to continue?`
  45. danglingWarning = `WARNING! This will remove all dangling images.
  46. Are you sure you want to continue?`
  47. )
  48. func runPrune(dockerCli *command.DockerCli, opts pruneOptions) (spaceReclaimed uint64, output string, err error) {
  49. pruneFilters := opts.filter.Value()
  50. pruneFilters.Add("dangling", fmt.Sprintf("%v", !opts.all))
  51. warning := danglingWarning
  52. if opts.all {
  53. warning = allImageWarning
  54. }
  55. if !opts.force && !command.PromptForConfirmation(dockerCli.In(), dockerCli.Out(), warning) {
  56. return
  57. }
  58. report, err := dockerCli.Client().ImagesPrune(context.Background(), pruneFilters)
  59. if err != nil {
  60. return
  61. }
  62. if len(report.ImagesDeleted) > 0 {
  63. output = "Deleted Images:\n"
  64. for _, st := range report.ImagesDeleted {
  65. if st.Untagged != "" {
  66. output += fmt.Sprintln("untagged:", st.Untagged)
  67. } else {
  68. output += fmt.Sprintln("deleted:", st.Deleted)
  69. }
  70. }
  71. spaceReclaimed = report.SpaceReclaimed
  72. }
  73. return
  74. }
  75. // RunPrune calls the Image Prune API
  76. // This returns the amount of space reclaimed and a detailed output string
  77. func RunPrune(dockerCli *command.DockerCli, all bool, filter opts.FilterOpt) (uint64, string, error) {
  78. return runPrune(dockerCli, pruneOptions{force: true, all: all, filter: filter})
  79. }