docker ps: add fields for ordering and column selection

* api/client/ps.go: Refactor CmdPs to use a fields list of
  characters to determine which columns to print on `docker ps`
  invocation.

This adds an ability for the docker command to print the columns of
output in arbitrary order.

Signed-off-by: Jeff Mickey <j@codemac.net>

Docker-DCO-1.1-Signed-off-by: Jeff Mickey <j@codemac.net>
This commit is contained in:
Jeff Mickey 2015-01-21 15:52:22 -08:00 committed by Phil Estes
parent efd56bbe6f
commit de0e883331
1 changed files with 95 additions and 45 deletions

View File

@ -38,6 +38,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
since = cmd.String([]string{"#sinceId", "#-since-id", "-since"}, "", "Show created since Id or Name, include non-running")
before = cmd.String([]string{"#beforeId", "#-before-id", "-before"}, "", "Show only container created before Id or Name")
last = cmd.Int([]string{"n"}, -1, "Show n last created containers, include non-running")
fields = cmd.String([]string{"-fields"}, "cimtspn", "Choose fields to print, and order (c,i,m,t,s,p,n,z)")
flFilter = opts.NewListOpts(nil)
)
cmd.Require(flag.Exact, 0)
@ -99,13 +100,35 @@ func (cli *DockerCli) CmdPs(args ...string) error {
}
w := tabwriter.NewWriter(cli.out, 20, 1, 3, ' ', 0)
if !*quiet {
fmt.Fprint(w, "CONTAINER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAMES")
if *quiet {
*fields = "c"
}
if *size {
fmt.Fprintln(w, "\tSIZE")
} else {
fmt.Fprint(w, "\n")
if *size {
*fields = *fields + "z"
}
if !*quiet {
headermap := map[rune]string{
'c': "CONTAINER ID",
'i': "IMAGE",
'm': "COMMAND",
's': "STATUS",
't': "CREATED",
'p': "PORTS",
'n': "NAMES",
'z': "SIZE",
}
headers := make([]string, 0)
for _, v := range *fields {
if title, ok := headermap[v]; ok {
headers = append(headers, title)
}
}
if len(headers) > 0 {
fmt.Fprint(w, strings.Join(headers, "\t")+"\n")
}
}
@ -117,63 +140,90 @@ func (cli *DockerCli) CmdPs(args ...string) error {
return ss
}
type containerMeta struct {
c string
i string
m string
t string
s string
p string
n string
z string
}
var displayPort string
if container.HostConfig.NetworkMode == "host" {
displayPort = "*/tcp, */udp"
} else {
displayPort = api.DisplayablePorts(container.Ports)
}
outp := make([]containerMeta, 0)
for _, container := range containers {
ID := container.ID
if !*noTrunc {
ID = stringid.TruncateID(ID)
next := containerMeta{
c: container.ID,
n: "",
m: strconv.Quote(container.Command),
i: container.Image,
t: units.HumanDuration(time.Now().UTC().Sub(time.Unix(int64(container.Created), 0))) + " ago",
s: container.Status,
p: displayPort,
z: fmt.Sprintf("%s", units.HumanSize(float64(container.SizeRw))),
}
if *quiet {
fmt.Fprintln(w, ID)
continue
}
var (
names = stripNamePrefix(container.Names)
command = strconv.Quote(container.Command)
displayPort string
)
// handle truncation
outNames := stripNamePrefix(container.Names)
if !*noTrunc {
command = stringutils.Truncate(command, 20)
next.c = stringid.TruncateID(next.c)
next.m = stringutils.Truncate(next.m, 20)
// only display the default name for the container with notrunc is passed
for _, name := range names {
for _, name := range outNames {
if len(strings.Split(name, "/")) == 1 {
names = []string{name}
outNames = []string{name}
break
}
}
}
next.n = strings.Join(outNames, ",")
image := container.Image
if image == "" {
image = "<no image>"
if next.i == "" {
next.i = "<no image>"
}
if container.HostConfig.NetworkMode == "host" {
displayPort = "*/tcp, */udp"
} else {
displayPort = api.DisplayablePorts(container.Ports)
// handle rootfs sizing
if container.SizeRootFs > 0 {
next.z = next.z + fmt.Sprintf(" (virtual %s)", units.HumanSize(float64(container.SizeRootFs)))
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s ago\t%s\t%s\t%s\t", ID, image, command,
units.HumanDuration(time.Now().UTC().Sub(time.Unix(int64(container.Created), 0))),
container.Status, displayPort, strings.Join(names, ","))
outp = append(outp, next)
}
for _, out := range outp {
of := make([]string, 0)
for _, v := range *fields {
switch v {
case 'c':
of = append(of, out.c)
case 'i':
of = append(of, out.i)
case 'm':
of = append(of, out.m)
case 't':
of = append(of, out.t)
case 's':
of = append(of, out.s)
case 'p':
of = append(of, out.p)
case 'n':
of = append(of, out.n)
case 'z':
of = append(of, out.z)
if *size {
if container.SizeRootFs > 0 {
fmt.Fprintf(w, "%s (virtual %s)\n", units.HumanSize(float64(container.SizeRw)), units.HumanSize(float64(container.SizeRootFs)))
} else {
fmt.Fprintf(w, "%s\n", units.HumanSize(float64(container.SizeRw)))
}
continue
}
fmt.Fprint(w, "\n")
if len(of) > 0 {
fmt.Fprintf(w, "%s\n", strings.Join(of, "\t"))
}
}
if !*quiet {