github.com/fabiokung/docker@v0.11.2-0.20170222101415-4534dcd49497/cli/command/container/list.go (about)

     1  package container
     2  
     3  import (
     4  	"io/ioutil"
     5  
     6  	"github.com/docker/docker/api/types"
     7  	"github.com/docker/docker/cli"
     8  	"github.com/docker/docker/cli/command"
     9  	"github.com/docker/docker/cli/command/formatter"
    10  	"github.com/docker/docker/opts"
    11  	"github.com/docker/docker/pkg/templates"
    12  	"github.com/spf13/cobra"
    13  	"golang.org/x/net/context"
    14  )
    15  
    16  type psOptions struct {
    17  	quiet   bool
    18  	size    bool
    19  	all     bool
    20  	noTrunc bool
    21  	nLatest bool
    22  	last    int
    23  	format  string
    24  	filter  opts.FilterOpt
    25  }
    26  
    27  // NewPsCommand creates a new cobra.Command for `docker ps`
    28  func NewPsCommand(dockerCli *command.DockerCli) *cobra.Command {
    29  	opts := psOptions{filter: opts.NewFilterOpt()}
    30  
    31  	cmd := &cobra.Command{
    32  		Use:   "ps [OPTIONS]",
    33  		Short: "List containers",
    34  		Args:  cli.NoArgs,
    35  		RunE: func(cmd *cobra.Command, args []string) error {
    36  			return runPs(dockerCli, &opts)
    37  		},
    38  	}
    39  
    40  	flags := cmd.Flags()
    41  
    42  	flags.BoolVarP(&opts.quiet, "quiet", "q", false, "Only display numeric IDs")
    43  	flags.BoolVarP(&opts.size, "size", "s", false, "Display total file sizes")
    44  	flags.BoolVarP(&opts.all, "all", "a", false, "Show all containers (default shows just running)")
    45  	flags.BoolVar(&opts.noTrunc, "no-trunc", false, "Don't truncate output")
    46  	flags.BoolVarP(&opts.nLatest, "latest", "l", false, "Show the latest created container (includes all states)")
    47  	flags.IntVarP(&opts.last, "last", "n", -1, "Show n last created containers (includes all states)")
    48  	flags.StringVarP(&opts.format, "format", "", "", "Pretty-print containers using a Go template")
    49  	flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided")
    50  
    51  	return cmd
    52  }
    53  
    54  func newListCommand(dockerCli *command.DockerCli) *cobra.Command {
    55  	cmd := *NewPsCommand(dockerCli)
    56  	cmd.Aliases = []string{"ps", "list"}
    57  	cmd.Use = "ls [OPTIONS]"
    58  	return &cmd
    59  }
    60  
    61  // listOptionsProcessor is used to set any container list options which may only
    62  // be embedded in the format template.
    63  // This is passed directly into tmpl.Execute in order to allow the preprocessor
    64  // to set any list options that were not provided by flags (e.g. `.Size`).
    65  // It is using a `map[string]bool` so that unknown fields passed into the
    66  // template format do not cause errors. These errors will get picked up when
    67  // running through the actual template processor.
    68  type listOptionsProcessor map[string]bool
    69  
    70  // Size sets the size of the map when called by a template execution.
    71  func (o listOptionsProcessor) Size() bool {
    72  	o["size"] = true
    73  	return true
    74  }
    75  
    76  // Label is needed here as it allows the correct pre-processing
    77  // because Label() is a method with arguments
    78  func (o listOptionsProcessor) Label(name string) string {
    79  	return ""
    80  }
    81  
    82  func buildContainerListOptions(opts *psOptions) (*types.ContainerListOptions, error) {
    83  	options := &types.ContainerListOptions{
    84  		All:     opts.all,
    85  		Limit:   opts.last,
    86  		Size:    opts.size,
    87  		Filters: opts.filter.Value(),
    88  	}
    89  
    90  	if opts.nLatest && opts.last == -1 {
    91  		options.Limit = 1
    92  	}
    93  
    94  	tmpl, err := templates.Parse(opts.format)
    95  
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	optionsProcessor := listOptionsProcessor{}
   101  	// This shouldn't error out but swallowing the error makes it harder
   102  	// to track down if preProcessor issues come up. Ref #24696
   103  	if err := tmpl.Execute(ioutil.Discard, optionsProcessor); err != nil {
   104  		return nil, err
   105  	}
   106  	// At the moment all we need is to capture .Size for preprocessor
   107  	options.Size = opts.size || optionsProcessor["size"]
   108  
   109  	return options, nil
   110  }
   111  
   112  func runPs(dockerCli *command.DockerCli, opts *psOptions) error {
   113  	ctx := context.Background()
   114  
   115  	listOptions, err := buildContainerListOptions(opts)
   116  	if err != nil {
   117  		return err
   118  	}
   119  
   120  	containers, err := dockerCli.Client().ContainerList(ctx, *listOptions)
   121  	if err != nil {
   122  		return err
   123  	}
   124  
   125  	format := opts.format
   126  	if len(format) == 0 {
   127  		if len(dockerCli.ConfigFile().PsFormat) > 0 && !opts.quiet {
   128  			format = dockerCli.ConfigFile().PsFormat
   129  		} else {
   130  			format = formatter.TableFormatKey
   131  		}
   132  	}
   133  
   134  	containerCtx := formatter.Context{
   135  		Output: dockerCli.Out(),
   136  		Format: formatter.NewContainerFormat(format, opts.quiet, listOptions.Size),
   137  		Trunc:  !opts.noTrunc,
   138  	}
   139  	return formatter.ContainerWrite(containerCtx, containers)
   140  }