github.com/justincormack/cli@v0.0.0-20201215022714-831ebeae9675/cli/command/container/list.go (about)

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