github.1git.de/docker/cli@v26.1.3+incompatible/cli/command/container/list.go (about) 1 package container 2 3 import ( 4 "context" 5 "io" 6 7 "github.com/docker/cli/cli" 8 "github.com/docker/cli/cli/command" 9 "github.com/docker/cli/cli/command/completion" 10 "github.com/docker/cli/cli/command/formatter" 11 flagsHelper "github.com/docker/cli/cli/flags" 12 "github.com/docker/cli/opts" 13 "github.com/docker/cli/templates" 14 "github.com/docker/docker/api/types/container" 15 "github.com/pkg/errors" 16 "github.com/spf13/cobra" 17 ) 18 19 type psOptions struct { 20 quiet bool 21 size bool 22 sizeChanged bool 23 all bool 24 noTrunc bool 25 nLatest bool 26 last int 27 format string 28 filter opts.FilterOpt 29 } 30 31 // NewPsCommand creates a new cobra.Command for `docker ps` 32 func NewPsCommand(dockerCLI command.Cli) *cobra.Command { 33 options := psOptions{filter: opts.NewFilterOpt()} 34 35 cmd := &cobra.Command{ 36 Use: "ps [OPTIONS]", 37 Short: "List containers", 38 Args: cli.NoArgs, 39 RunE: func(cmd *cobra.Command, args []string) error { 40 options.sizeChanged = cmd.Flags().Changed("size") 41 return runPs(cmd.Context(), dockerCLI, &options) 42 }, 43 Annotations: map[string]string{ 44 "category-top": "3", 45 "aliases": "docker container ls, docker container list, docker container ps, docker ps", 46 }, 47 ValidArgsFunction: completion.NoComplete, 48 } 49 50 flags := cmd.Flags() 51 52 flags.BoolVarP(&options.quiet, "quiet", "q", false, "Only display container IDs") 53 flags.BoolVarP(&options.size, "size", "s", false, "Display total file sizes") 54 flags.BoolVarP(&options.all, "all", "a", false, "Show all containers (default shows just running)") 55 flags.BoolVar(&options.noTrunc, "no-trunc", false, "Don't truncate output") 56 flags.BoolVarP(&options.nLatest, "latest", "l", false, "Show the latest created container (includes all states)") 57 flags.IntVarP(&options.last, "last", "n", -1, "Show n last created containers (includes all states)") 58 flags.StringVar(&options.format, "format", "", flagsHelper.FormatHelp) 59 flags.VarP(&options.filter, "filter", "f", "Filter output based on conditions provided") 60 61 return cmd 62 } 63 64 func newListCommand(dockerCLI command.Cli) *cobra.Command { 65 cmd := *NewPsCommand(dockerCLI) 66 cmd.Aliases = []string{"ps", "list"} 67 cmd.Use = "ls [OPTIONS]" 68 return &cmd 69 } 70 71 func buildContainerListOptions(options *psOptions) (*container.ListOptions, error) { 72 listOptions := &container.ListOptions{ 73 All: options.all, 74 Limit: options.last, 75 Size: options.size, 76 Filters: options.filter.Value(), 77 } 78 79 if options.nLatest && options.last == -1 { 80 listOptions.Limit = 1 81 } 82 83 // always validate template when `--format` is used, for consistency 84 if len(options.format) > 0 { 85 tmpl, err := templates.NewParse("", options.format) 86 if err != nil { 87 return nil, errors.Wrap(err, "failed to parse template") 88 } 89 90 optionsProcessor := formatter.NewContainerContext() 91 92 // This shouldn't error out but swallowing the error makes it harder 93 // to track down if preProcessor issues come up. 94 if err := tmpl.Execute(io.Discard, optionsProcessor); err != nil { 95 return nil, errors.Wrap(err, "failed to execute template") 96 } 97 98 // if `size` was not explicitly set to false (with `--size=false`) 99 // and `--quiet` is not set, request size if the template requires it 100 if !options.quiet && !listOptions.Size && !options.sizeChanged { 101 // The --size option isn't set, but .Size may be used in the template. 102 // Parse and execute the given template to detect if the .Size field is 103 // used. If it is, then automatically enable the --size option. See #24696 104 // 105 // Only requesting container size information when needed is an optimization, 106 // because calculating the size is a costly operation. 107 108 if _, ok := optionsProcessor.FieldsUsed["Size"]; ok { 109 listOptions.Size = true 110 } 111 } 112 } 113 114 return listOptions, nil 115 } 116 117 func runPs(ctx context.Context, dockerCLI command.Cli, options *psOptions) error { 118 if len(options.format) == 0 { 119 // load custom psFormat from CLI config (if any) 120 options.format = dockerCLI.ConfigFile().PsFormat 121 } else if options.quiet { 122 _, _ = dockerCLI.Err().Write([]byte("WARNING: Ignoring custom format, because both --format and --quiet are set.\n")) 123 } 124 125 listOptions, err := buildContainerListOptions(options) 126 if err != nil { 127 return err 128 } 129 130 containers, err := dockerCLI.Client().ContainerList(ctx, *listOptions) 131 if err != nil { 132 return err 133 } 134 135 containerCtx := formatter.Context{ 136 Output: dockerCLI.Out(), 137 Format: formatter.NewContainerFormat(options.format, options.quiet, listOptions.Size), 138 Trunc: !options.noTrunc, 139 } 140 return formatter.ContainerWrite(containerCtx, containers) 141 }