From 73e9f16bec8d9968297fe5f3f016572989de8924 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Thu, 8 Feb 2024 11:16:02 +0100 Subject: [PATCH] Add JSON stream progress writer Signed-off-by: Felix Fontein --- cmd/compose/compose.go | 3 ++ pkg/progress/json.go | 88 ++++++++++++++++++++++++++++++++++++++++++ pkg/progress/writer.go | 9 +++++ 3 files changed, 100 insertions(+) create mode 100644 pkg/progress/json.go diff --git a/cmd/compose/compose.go b/cmd/compose/compose.go index 17e5e071c84..504130e97ce 100644 --- a/cmd/compose/compose.go +++ b/cmd/compose/compose.go @@ -376,6 +376,8 @@ func RootCommand(dockerCli command.Cli, backend api.Service) *cobra.Command { // ui.Mode = ui.ModePlain case ui.ModeQuiet, "none": ui.Mode = ui.ModeQuiet + case ui.ModeJSON: + ui.Mode = ui.ModeJSON default: return fmt.Errorf("unsupported --progress value %q", opts.Progress) } @@ -525,5 +527,6 @@ var printerModes = []string{ ui.ModeAuto, ui.ModeTTY, ui.ModePlain, + ui.ModeJSON, ui.ModeQuiet, } diff --git a/pkg/progress/json.go b/pkg/progress/json.go new file mode 100644 index 00000000000..c2a2bd28fc0 --- /dev/null +++ b/pkg/progress/json.go @@ -0,0 +1,88 @@ +/* + Copyright 2024 Docker Compose CLI authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package progress + +import ( + "context" + "encoding/json" + "fmt" + "io" +) + +type jsonWriter struct { + out io.Writer + done chan bool + dryRun bool +} + +type jsonMessage struct { + dryRun bool `json:"dry-run,omitempty"` + tail bool `json:"tail,omitempty"` + id string `json:"id,omitempty"` + text string `json:"text,omitempty"` + status string `json:"status,omitempty"` +} + +func (p *jsonWriter) Start(ctx context.Context) error { + select { + case <-ctx.Done(): + return ctx.Err() + case <-p.done: + return nil + } +} + +func (p *jsonWriter) Event(e Event) { + var message = &jsonMessage{ + dryRun: p.dryRun, + tail: false, + id: e.ID, + text: e.Text, + status: e.StatusText, + } + marshal, err := json.Marshal(message) + if err == nil { + fmt.Fprintln(p.out, "%s", string(marshal)) + } +} + +func (p *jsonWriter) Events(events []Event) { + for _, e := range events { + p.Event(e) + } +} + +func (p *jsonWriter) TailMsgf(msg string, args ...interface{}) { + var message = &jsonMessage{ + dryRun: p.dryRun, + tail: true, + id: "", + text: fmt.Sprintf(msg, args...), + status: "", + } + marshal, err := json.Marshal(message) + if err == nil { + fmt.Fprintln(p.out, "%s", string(marshal)) + } +} + +func (p *jsonWriter) Stop() { + p.done <- true +} + +func (p *jsonWriter) HasMore(bool) { +} diff --git a/pkg/progress/writer.go b/pkg/progress/writer.go index b6d60e3da99..63a5a91ed86 100644 --- a/pkg/progress/writer.go +++ b/pkg/progress/writer.go @@ -110,6 +110,8 @@ const ( ModePlain = "plain" // ModeQuiet don't display events ModeQuiet = "quiet" + // ModeJSON outputs a machine-readable JSON stream + ModeJSON = "json" ) // 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 return newTTYWriter(f, dryRun, progressTitle) } } + if Mode == ModeJSON { + return &jsonWriter{ + out: out, + done: make(chan bool), + dryRun: dryRun, + }, nil + } return &plainWriter{ out: out, done: make(chan bool),