Skip to content

Commit dea886c

Browse files
committed
Add JSON stream progress writer
Signed-off-by: Felix Fontein <[email protected]>
1 parent aaa7ef6 commit dea886c

File tree

6 files changed

+103
-3
lines changed

6 files changed

+103
-3
lines changed

cmd/compose/compose.go

+3
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,8 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { //
376376
ui.Mode = ui.ModePlain
377377
case ui.ModeQuiet, "none":
378378
ui.Mode = ui.ModeQuiet
379+
case ui.ModeJSON:
380+
ui.Mode = ui.ModeJSON
379381
default:
380382
return fmt.Errorf("unsupported --progress value %q", opts.Progress)
381383
}
@@ -525,5 +527,6 @@ var printerModes = []string{
525527
ui.ModeAuto,
526528
ui.ModeTTY,
527529
ui.ModePlain,
530+
ui.ModeJSON,
528531
ui.ModeQuiet,
529532
}

docs/reference/compose.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Define and run multi-container applications with Docker.
5050
| `-f`, `--file` | `stringArray` | | Compose configuration files |
5151
| `--parallel` | `int` | `-1` | Control max parallelism, -1 for unlimited |
5252
| `--profile` | `stringArray` | | Specify a profile to enable |
53-
| `--progress` | `string` | `auto` | Set type of progress output (auto, tty, plain, quiet) |
53+
| `--progress` | `string` | `auto` | Set type of progress output (auto, tty, plain, json, quiet) |
5454
| `--project-directory` | `string` | | Specify an alternate working directory<br>(default: the path of the, first specified, Compose file) |
5555
| `-p`, `--project-name` | `string` | | Project name |
5656

docs/reference/docker_compose.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ options:
293293
- option: progress
294294
value_type: string
295295
default_value: auto
296-
description: Set type of progress output (auto, tty, plain, quiet)
296+
description: Set type of progress output (auto, tty, plain, json, quiet)
297297
deprecated: false
298298
hidden: false
299299
experimental: false

docs/reference/docker_compose_build.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ options:
9999
- option: progress
100100
value_type: string
101101
default_value: auto
102-
description: Set type of ui output (auto, tty, plain, quiet)
102+
description: Set type of ui output (auto, tty, plain, json, quiet)
103103
deprecated: false
104104
hidden: true
105105
experimental: false

pkg/progress/json.go

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
Copyright 2024 Docker Compose CLI authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package progress
18+
19+
import (
20+
"context"
21+
"encoding/json"
22+
"fmt"
23+
"io"
24+
)
25+
26+
type jsonWriter struct {
27+
out io.Writer
28+
done chan bool
29+
dryRun bool
30+
}
31+
32+
type jsonMessage struct {
33+
DryRun bool `json:"dry-run,omitempty"`
34+
Tail bool `json:"tail,omitempty"`
35+
ID string `json:"id,omitempty"`
36+
Text string `json:"text,omitempty"`
37+
Status string `json:"status,omitempty"`
38+
}
39+
40+
func (p *jsonWriter) Start(ctx context.Context) error {
41+
select {
42+
case <-ctx.Done():
43+
return ctx.Err()
44+
case <-p.done:
45+
return nil
46+
}
47+
}
48+
49+
func (p *jsonWriter) Event(e Event) {
50+
var message = &jsonMessage{
51+
DryRun: p.dryRun,
52+
Tail: false,
53+
ID: e.ID,
54+
Text: e.Text,
55+
Status: e.StatusText,
56+
}
57+
marshal, err := json.Marshal(message)
58+
if err == nil {
59+
fmt.Fprintln(p.out, string(marshal))
60+
}
61+
}
62+
63+
func (p *jsonWriter) Events(events []Event) {
64+
for _, e := range events {
65+
p.Event(e)
66+
}
67+
}
68+
69+
func (p *jsonWriter) TailMsgf(msg string, args ...interface{}) {
70+
var message = &jsonMessage{
71+
DryRun: p.dryRun,
72+
Tail: true,
73+
ID: "",
74+
Text: fmt.Sprintf(msg, args...),
75+
Status: "",
76+
}
77+
marshal, err := json.Marshal(message)
78+
if err == nil {
79+
fmt.Fprintln(p.out, string(marshal))
80+
}
81+
}
82+
83+
func (p *jsonWriter) Stop() {
84+
p.done <- true
85+
}
86+
87+
func (p *jsonWriter) HasMore(bool) {
88+
}

pkg/progress/writer.go

+9
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ const (
110110
ModePlain = "plain"
111111
// ModeQuiet don't display events
112112
ModeQuiet = "quiet"
113+
// ModeJSON outputs a machine-readable JSON stream
114+
ModeJSON = "json"
113115
)
114116

115117
// Mode define how progress should be rendered, either as ModePlain or ModeTTY
@@ -136,6 +138,13 @@ func NewWriter(ctx context.Context, out io.Writer, progressTitle string) (Writer
136138
return newTTYWriter(f, dryRun, progressTitle)
137139
}
138140
}
141+
if Mode == ModeJSON {
142+
return &jsonWriter{
143+
out: out,
144+
done: make(chan bool),
145+
dryRun: dryRun,
146+
}, nil
147+
}
139148
return &plainWriter{
140149
out: out,
141150
done: make(chan bool),

0 commit comments

Comments
 (0)