Skip to content

Commit 3fec17c

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

File tree

3 files changed

+100
-0
lines changed

3 files changed

+100
-0
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
}

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)