Skip to content

Commit 1054792

Browse files
committed
align docker compose ps with docker CLI to support --format
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent 19f6691 commit 1054792

File tree

11 files changed

+282
-121
lines changed

11 files changed

+282
-121
lines changed

cmd/compose/compose.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ func RunningAsStandalone() bool {
275275
}
276276

277277
// RootCommand returns the compose command with its child commands
278-
func RootCommand(streams command.Cli, backend api.Service) *cobra.Command { //nolint:gocyclo
278+
func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { //nolint:gocyclo
279279
// filter out useless commandConn.CloseWrite warning message that can occur
280280
// when using a remote context that is unreachable: "commandConn.CloseWrite: commandconn: failed to wait: signal: killed"
281281
// https://github.com/docker/cli/blob/e1f24d3c93df6752d3c27c8d61d18260f141310c/cli/connhelper/commandconn/commandconn.go#L203-L215
@@ -307,7 +307,7 @@ func RootCommand(streams command.Cli, backend api.Service) *cobra.Command { //no
307307
return cmd.Help()
308308
}
309309
if version {
310-
return versionCommand(streams).Execute()
310+
return versionCommand(dockerCli).Execute()
311311
}
312312
_ = cmd.Help()
313313
return dockercli.StatusError{
@@ -345,11 +345,11 @@ func RootCommand(streams command.Cli, backend api.Service) *cobra.Command { //no
345345
ansi = v
346346
}
347347

348-
formatter.SetANSIMode(streams, ansi)
348+
formatter.SetANSIMode(dockerCli, ansi)
349349

350350
if noColor, ok := os.LookupEnv("NO_COLOR"); ok && noColor != "" {
351351
ui.NoColor()
352-
formatter.SetANSIMode(streams, formatter.Never)
352+
formatter.SetANSIMode(dockerCli, formatter.Never)
353353
}
354354

355355
switch ansi {
@@ -426,26 +426,26 @@ func RootCommand(streams command.Cli, backend api.Service) *cobra.Command { //no
426426
}
427427

428428
c.AddCommand(
429-
upCommand(&opts, streams, backend),
429+
upCommand(&opts, dockerCli, backend),
430430
downCommand(&opts, backend),
431431
startCommand(&opts, backend),
432432
restartCommand(&opts, backend),
433433
stopCommand(&opts, backend),
434-
psCommand(&opts, streams, backend),
435-
listCommand(streams, backend),
436-
logsCommand(&opts, streams, backend),
437-
configCommand(&opts, streams, backend),
434+
psCommand(&opts, dockerCli, backend),
435+
listCommand(dockerCli, backend),
436+
logsCommand(&opts, dockerCli, backend),
437+
configCommand(&opts, dockerCli, backend),
438438
killCommand(&opts, backend),
439-
runCommand(&opts, streams, backend),
439+
runCommand(&opts, dockerCli, backend),
440440
removeCommand(&opts, backend),
441-
execCommand(&opts, streams, backend),
441+
execCommand(&opts, dockerCli, backend),
442442
pauseCommand(&opts, backend),
443443
unpauseCommand(&opts, backend),
444-
topCommand(&opts, streams, backend),
445-
eventsCommand(&opts, streams, backend),
446-
portCommand(&opts, streams, backend),
447-
imagesCommand(&opts, streams, backend),
448-
versionCommand(streams),
444+
topCommand(&opts, dockerCli, backend),
445+
eventsCommand(&opts, dockerCli, backend),
446+
portCommand(&opts, dockerCli, backend),
447+
imagesCommand(&opts, dockerCli, backend),
448+
versionCommand(dockerCli),
449449
buildCommand(&opts, &progress, backend),
450450
pushCommand(&opts, backend),
451451
pullCommand(&opts, backend),

cmd/compose/ps.go

Lines changed: 21 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,18 @@ package compose
1919
import (
2020
"context"
2121
"fmt"
22-
"io"
2322
"sort"
24-
"strconv"
2523
"strings"
26-
"time"
2724

2825
"github.com/docker/compose/v2/cmd/formatter"
26+
"github.com/docker/compose/v2/pkg/api"
2927
"github.com/docker/compose/v2/pkg/utils"
30-
"github.com/docker/docker/api/types"
3128

32-
formatter2 "github.com/docker/cli/cli/command/formatter"
33-
"github.com/docker/go-units"
29+
"github.com/docker/cli/cli/command"
30+
cliformatter "github.com/docker/cli/cli/command/formatter"
31+
cliflags "github.com/docker/cli/cli/flags"
3432
"github.com/pkg/errors"
3533
"github.com/spf13/cobra"
36-
37-
"github.com/docker/compose/v2/pkg/api"
3834
)
3935

4036
type psOptions struct {
@@ -66,7 +62,7 @@ func (p *psOptions) parseFilter() error {
6662
return nil
6763
}
6864

69-
func psCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *cobra.Command {
65+
func psCommand(p *ProjectOptions, dockerCli command.Cli, backend api.Service) *cobra.Command {
7066
opts := psOptions{
7167
ProjectOptions: p,
7268
}
@@ -77,12 +73,12 @@ func psCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *cob
7773
return opts.parseFilter()
7874
},
7975
RunE: Adapt(func(ctx context.Context, args []string) error {
80-
return runPs(ctx, streams, backend, args, opts)
76+
return runPs(ctx, dockerCli, backend, args, opts)
8177
}),
8278
ValidArgsFunction: completeServiceNames(p),
8379
}
8480
flags := psCmd.Flags()
85-
flags.StringVar(&opts.Format, "format", "table", "Format the output. Values: [table | json]")
81+
flags.StringVar(&opts.Format, "format", "table", cliflags.FormatHelp)
8682
flags.StringVar(&opts.Filter, "filter", "", "Filter services by a property (supported filters: status).")
8783
flags.StringArrayVar(&opts.Status, "status", []string{}, "Filter services by status. Values: [paused | restarting | removing | running | dead | created | exited]")
8884
flags.BoolVarP(&opts.Quiet, "quiet", "q", false, "Only display IDs")
@@ -91,7 +87,7 @@ func psCommand(p *ProjectOptions, streams api.Streams, backend api.Service) *cob
9187
return psCmd
9288
}
9389

94-
func runPs(ctx context.Context, streams api.Streams, backend api.Service, services []string, opts psOptions) error {
90+
func runPs(ctx context.Context, dockerCli command.Cli, backend api.Service, services []string, opts psOptions) error {
9591
project, name, err := opts.projectOrName(services...)
9692
if err != nil {
9793
return err
@@ -125,38 +121,32 @@ func runPs(ctx context.Context, streams api.Streams, backend api.Service, servic
125121

126122
if opts.Quiet {
127123
for _, c := range containers {
128-
fmt.Fprintln(streams.Out(), c.ID)
124+
fmt.Fprintln(dockerCli.Out(), c.ID)
129125
}
130126
return nil
131127
}
132128

133129
if opts.Services {
134130
services := []string{}
135-
for _, s := range containers {
136-
if !utils.StringContains(services, s.Service) {
137-
services = append(services, s.Service)
131+
for _, c := range containers {
132+
s := c.Service
133+
if !utils.StringContains(services, s) {
134+
services = append(services, s)
138135
}
139136
}
140-
fmt.Fprintln(streams.Out(), strings.Join(services, "\n"))
137+
fmt.Fprintln(dockerCli.Out(), strings.Join(services, "\n"))
141138
return nil
142139
}
143140

144-
return formatter.Print(containers, opts.Format, streams.Out(),
145-
writer(containers),
146-
"NAME", "IMAGE", "COMMAND", "SERVICE", "CREATED", "STATUS", "PORTS")
147-
}
141+
if opts.Format == "" {
142+
opts.Format = dockerCli.ConfigFile().PsFormat
143+
}
148144

149-
func writer(containers []api.ContainerSummary) func(w io.Writer) {
150-
return func(w io.Writer) {
151-
for _, container := range containers {
152-
ports := displayablePorts(container)
153-
createdAt := time.Unix(container.Created, 0)
154-
created := units.HumanDuration(time.Now().UTC().Sub(createdAt)) + " ago"
155-
status := container.Status
156-
command := formatter2.Ellipsis(container.Command, 20)
157-
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", container.Name, container.Image, strconv.Quote(command), container.Service, created, status, ports)
158-
}
145+
containerCtx := cliformatter.Context{
146+
Output: dockerCli.Out(),
147+
Format: formatter.NewContainerFormat(opts.Format, opts.Quiet, false),
159148
}
149+
return formatter.ContainerWrite(containerCtx, containers)
160150
}
161151

162152
func filterByStatus(containers []api.ContainerSummary, statuses []string) []api.ContainerSummary {
@@ -177,21 +167,3 @@ func hasStatus(c api.ContainerSummary, statuses []string) bool {
177167
}
178168
return false
179169
}
180-
181-
func displayablePorts(c api.ContainerSummary) string {
182-
if c.Publishers == nil {
183-
return ""
184-
}
185-
186-
ports := make([]types.Port, len(c.Publishers))
187-
for i, pub := range c.Publishers {
188-
ports[i] = types.Port{
189-
IP: pub.URL,
190-
PrivatePort: uint16(pub.TargetPort),
191-
PublicPort: uint16(pub.PublishedPort),
192-
Type: pub.Protocol,
193-
}
194-
}
195-
196-
return formatter2.DisplayablePorts(ports)
197-
}

cmd/compose/ps_test.go

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ package compose
1818

1919
import (
2020
"context"
21-
"io"
2221
"os"
2322
"path/filepath"
2423
"testing"
2524

25+
"github.com/docker/cli/cli/config/configfile"
2626
"github.com/docker/cli/cli/streams"
2727
"github.com/docker/compose/v2/pkg/api"
2828
"github.com/docker/compose/v2/pkg/mocks"
@@ -69,7 +69,11 @@ func TestPsTable(t *testing.T) {
6969
}).AnyTimes()
7070

7171
opts := psOptions{ProjectOptions: &ProjectOptions{ProjectName: "test"}}
72-
err = runPs(ctx, stream{out: streams.NewOut(f)}, backend, nil, opts)
72+
stdout := streams.NewOut(f)
73+
cli := mocks.NewMockCli(ctrl)
74+
cli.EXPECT().Out().Return(stdout).AnyTimes()
75+
cli.EXPECT().ConfigFile().Return(&configfile.ConfigFile{}).AnyTimes()
76+
err = runPs(ctx, cli, backend, nil, opts)
7377
assert.NoError(t, err)
7478

7579
_, err = f.Seek(0, 0)
@@ -80,21 +84,3 @@ func TestPsTable(t *testing.T) {
8084

8185
assert.Contains(t, string(output), "8080/tcp, 8443/tcp")
8286
}
83-
84-
type stream struct {
85-
out *streams.Out
86-
err io.Writer
87-
in *streams.In
88-
}
89-
90-
func (s stream) Out() *streams.Out {
91-
return s.out
92-
}
93-
94-
func (s stream) Err() io.Writer {
95-
return s.err
96-
}
97-
98-
func (s stream) In() *streams.In {
99-
return s.in
100-
}

0 commit comments

Comments
 (0)