Skip to content

Commit a766e16

Browse files
dmkendeloof
authored andcommitted
condense output of compose top
This changes the output format of `compose top` and inlines the service container name into the table. Previously, `compose top` had printed something like: <service name> UID PID ... root 1 ... Now, the output looks more like this: SERVICE UID PID ... <name> root 1 ... Signed-off-by: Dominik Menke <[email protected]>
1 parent 793c6f1 commit a766e16

File tree

2 files changed

+363
-17
lines changed

2 files changed

+363
-17
lines changed

cmd/compose/top.go

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ func topCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *
4949
return topCmd
5050
}
5151

52+
type topHeader map[string]int // maps a proc title to its output index
53+
type topEntries map[string]string
54+
5255
func runTop(ctx context.Context, dockerCli command.Cli, backend api.Service, opts topOptions, services []string) error {
5356
projectName, err := opts.toProjectName(ctx, dockerCli)
5457
if err != nil {
@@ -63,30 +66,60 @@ func runTop(ctx context.Context, dockerCli command.Cli, backend api.Service, opt
6366
return containers[i].Name < containers[j].Name
6467
})
6568

69+
header, entries := collectTop(containers)
70+
return topPrint(dockerCli.Out(), header, entries)
71+
}
72+
73+
func collectTop(containers []api.ContainerProcSummary) (topHeader, []topEntries) {
74+
// map column name to its header (should keep working if backend.Top returns
75+
// varying columns for different containers)
76+
header := topHeader{"SERVICE": 0}
77+
78+
// assume one process per container and grow if needed
79+
entries := make([]topEntries, 0, len(containers))
80+
6681
for _, container := range containers {
67-
_, _ = fmt.Fprintf(dockerCli.Out(), "%s\n", container.Name)
68-
err := psPrinter(dockerCli.Out(), func(w io.Writer) {
69-
for _, proc := range container.Processes {
70-
info := []interface{}{}
71-
for _, p := range proc {
72-
info = append(info, p)
73-
}
74-
_, _ = fmt.Fprintf(w, strings.Repeat("%s\t", len(info))+"\n", info...)
82+
for _, proc := range container.Processes {
83+
entry := topEntries{"SERVICE": container.Name}
7584

85+
for i, title := range container.Titles {
86+
if _, exists := header[title]; !exists {
87+
header[title] = len(header)
88+
}
89+
entry[title] = proc[i]
7690
}
77-
_, _ = fmt.Fprintln(w)
78-
},
79-
container.Titles...)
80-
if err != nil {
81-
return err
91+
92+
entries = append(entries, entry)
8293
}
8394
}
84-
return nil
95+
return header, entries
8596
}
8697

87-
func psPrinter(out io.Writer, printer func(writer io.Writer), headers ...string) error {
98+
func topPrint(out io.Writer, headers topHeader, rows []topEntries) error {
99+
if len(rows) == 0 {
100+
return nil
101+
}
102+
88103
w := tabwriter.NewWriter(out, 5, 1, 3, ' ', 0)
89-
_, _ = fmt.Fprintln(w, strings.Join(headers, "\t"))
90-
printer(w)
104+
105+
// write headers in the order we've encountered them
106+
h := make([]string, len(headers))
107+
for title, index := range headers {
108+
h[index] = title
109+
}
110+
_, _ = fmt.Fprintln(w, strings.Join(h, "\t"))
111+
112+
for _, row := range rows {
113+
// write proc data in header order
114+
r := make([]string, len(headers))
115+
for title, index := range headers {
116+
if v, ok := row[title]; ok {
117+
r[index] = v
118+
} else {
119+
r[index] = "-"
120+
}
121+
}
122+
_, _ = fmt.Fprintln(w, strings.Join(r, "\t"))
123+
}
91124
return w.Flush()
92125
}

0 commit comments

Comments
 (0)