@@ -49,6 +49,9 @@ func topCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *
49
49
return topCmd
50
50
}
51
51
52
+ type topHeader map [string ]int // maps a proc title to its output index
53
+ type topEntries map [string ]string
54
+
52
55
func runTop (ctx context.Context , dockerCli command.Cli , backend api.Service , opts topOptions , services []string ) error {
53
56
projectName , err := opts .toProjectName (ctx , dockerCli )
54
57
if err != nil {
@@ -63,30 +66,60 @@ func runTop(ctx context.Context, dockerCli command.Cli, backend api.Service, opt
63
66
return containers [i ].Name < containers [j ].Name
64
67
})
65
68
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
+
66
81
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 }
75
84
85
+ for i , title := range container .Titles {
86
+ if _ , exists := header [title ]; ! exists {
87
+ header [title ] = len (header )
88
+ }
89
+ entry [title ] = proc [i ]
76
90
}
77
- _ , _ = fmt .Fprintln (w )
78
- },
79
- container .Titles ... )
80
- if err != nil {
81
- return err
91
+
92
+ entries = append (entries , entry )
82
93
}
83
94
}
84
- return nil
95
+ return header , entries
85
96
}
86
97
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
+
88
103
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
+ }
91
124
return w .Flush ()
92
125
}
0 commit comments