Files
docker-cli/cli/command/container/list.go
Sebastiaan van Stijn 0adaf6be3b verify that DisableFlagsInUseLine is set for all commands
This replaces the visitAll recursive function with a test that verifies that
the option is set for all commands and subcommands, so that it doesn't have
to be modified at runtime.

We currently still have to loop over all functions for the setValidateArgs
call, but that can be looked at separately.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-09-01 09:39:46 +02:00

142 lines
4.5 KiB
Go

package container
import (
"context"
"io"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter"
flagsHelper "github.com/docker/cli/cli/flags"
"github.com/docker/cli/opts"
"github.com/docker/cli/templates"
"github.com/moby/moby/api/types/container"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
type psOptions struct {
quiet bool
size bool
sizeChanged bool
all bool
noTrunc bool
nLatest bool
last int
format string
filter opts.FilterOpt
}
// newPsCommand creates a new cobra.Command for "docker container ps"
func newPsCommand(dockerCLI command.Cli) *cobra.Command {
options := psOptions{filter: opts.NewFilterOpt()}
cmd := &cobra.Command{
Use: "ps [OPTIONS]",
Short: "List containers",
Args: cli.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
options.sizeChanged = cmd.Flags().Changed("size")
return runPs(cmd.Context(), dockerCLI, &options)
},
Annotations: map[string]string{
"category-top": "3",
"aliases": "docker container ls, docker container list, docker container ps, docker ps",
},
ValidArgsFunction: cobra.NoFileCompletions,
DisableFlagsInUseLine: true,
}
flags := cmd.Flags()
flags.BoolVarP(&options.quiet, "quiet", "q", false, "Only display container IDs")
flags.BoolVarP(&options.size, "size", "s", false, "Display total file sizes")
flags.BoolVarP(&options.all, "all", "a", false, "Show all containers (default shows just running)")
flags.BoolVar(&options.noTrunc, "no-trunc", false, "Don't truncate output")
flags.BoolVarP(&options.nLatest, "latest", "l", false, "Show the latest created container (includes all states)")
flags.IntVarP(&options.last, "last", "n", -1, "Show n last created containers (includes all states)")
flags.StringVar(&options.format, "format", "", flagsHelper.FormatHelp)
flags.VarP(&options.filter, "filter", "f", "Filter output based on conditions provided")
return cmd
}
func newListCommand(dockerCLI command.Cli) *cobra.Command {
cmd := *newPsCommand(dockerCLI)
cmd.Aliases = []string{"ps", "list"}
cmd.Use = "ls [OPTIONS]"
return &cmd
}
func buildContainerListOptions(options *psOptions) (*container.ListOptions, error) {
listOptions := &container.ListOptions{
All: options.all,
Limit: options.last,
Size: options.size,
Filters: options.filter.Value(),
}
if options.nLatest && options.last == -1 {
listOptions.Limit = 1
}
// always validate template when `--format` is used, for consistency
if len(options.format) > 0 {
tmpl, err := templates.Parse(options.format)
if err != nil {
return nil, errors.Wrap(err, "failed to parse template")
}
optionsProcessor := formatter.NewContainerContext()
// This shouldn't error out but swallowing the error makes it harder
// to track down if preProcessor issues come up.
if err := tmpl.Execute(io.Discard, optionsProcessor); err != nil {
return nil, errors.Wrap(err, "failed to execute template")
}
// if `size` was not explicitly set to false (with `--size=false`)
// and `--quiet` is not set, request size if the template requires it
if !options.quiet && !listOptions.Size && !options.sizeChanged {
// The --size option isn't set, but .Size may be used in the template.
// Parse and execute the given template to detect if the .Size field is
// used. If it is, then automatically enable the --size option. See #24696
//
// Only requesting container size information when needed is an optimization,
// because calculating the size is a costly operation.
if _, ok := optionsProcessor.FieldsUsed["Size"]; ok {
listOptions.Size = true
}
}
}
return listOptions, nil
}
func runPs(ctx context.Context, dockerCLI command.Cli, options *psOptions) error {
if len(options.format) == 0 {
// load custom psFormat from CLI config (if any)
options.format = dockerCLI.ConfigFile().PsFormat
} else if options.quiet {
_, _ = dockerCLI.Err().Write([]byte("WARNING: Ignoring custom format, because both --format and --quiet are set.\n"))
}
listOptions, err := buildContainerListOptions(options)
if err != nil {
return err
}
containers, err := dockerCLI.Client().ContainerList(ctx, *listOptions)
if err != nil {
return err
}
containerCtx := formatter.Context{
Output: dockerCLI.Out(),
Format: formatter.NewContainerFormat(options.format, options.quiet, listOptions.Size),
Trunc: !options.noTrunc,
}
return formatter.ContainerWrite(containerCtx, containers)
}