mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
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:
parent
efd56bbe6f
commit
de0e883331
1 changed files with 95 additions and 45 deletions
140
api/client/ps.go
140
api/client/ps.go
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue