mirror of
https://github.com/docker/compose.git
synced 2026-07-11 02:34:25 +00:00
register TTYWritter as an Event Processor
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
ae25d27e5a
commit
fd4f2f99cf
49 changed files with 409 additions and 710 deletions
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package progress
|
||||
|
||||
import "context"
|
||||
|
||||
// EventStatus indicates the status of an action
|
||||
type EventStatus int
|
||||
|
||||
|
|
@ -159,3 +161,13 @@ func NewEvent(id string, status EventStatus, statusText string) Event {
|
|||
StatusText: statusText,
|
||||
}
|
||||
}
|
||||
|
||||
// EventProcessor is notified about Compose operations and tasks
|
||||
type EventProcessor interface {
|
||||
// Start is triggered as a Compose operation is starting with context
|
||||
Start(ctx context.Context, operation string)
|
||||
// On notify about (sub)task and progress processing operation
|
||||
On(events ...Event)
|
||||
// Done is triggered as a Compose operation completed
|
||||
Done(operation string, success bool)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,9 +23,14 @@ import (
|
|||
"io"
|
||||
)
|
||||
|
||||
func NewJSONWriter(out io.Writer) EventProcessor {
|
||||
return &jsonWriter{
|
||||
out: out,
|
||||
}
|
||||
}
|
||||
|
||||
type jsonWriter struct {
|
||||
out io.Writer
|
||||
done chan bool
|
||||
dryRun bool
|
||||
}
|
||||
|
||||
|
|
@ -41,13 +46,7 @@ type jsonMessage struct {
|
|||
Percent int `json:"percent,omitempty"`
|
||||
}
|
||||
|
||||
func (p *jsonWriter) Start(ctx context.Context) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-p.done:
|
||||
return nil
|
||||
}
|
||||
func (p *jsonWriter) Start(ctx context.Context, operation string) {
|
||||
}
|
||||
|
||||
func (p *jsonWriter) Event(e Event) {
|
||||
|
|
@ -68,29 +67,11 @@ func (p *jsonWriter) Event(e Event) {
|
|||
}
|
||||
}
|
||||
|
||||
func (p *jsonWriter) Events(events []Event) {
|
||||
func (p *jsonWriter) On(events ...Event) {
|
||||
for _, e := range events {
|
||||
p.Event(e)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *jsonWriter) TailMsgf(msg string, args ...interface{}) {
|
||||
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, string(marshal))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *jsonWriter) Stop() {
|
||||
p.done <- true
|
||||
}
|
||||
|
||||
func (p *jsonWriter) HasMore(bool) {
|
||||
func (p *jsonWriter) Done(_ string, _ bool) {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package progress
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
|
|
@ -29,7 +28,6 @@ func TestJsonWriter_Event(t *testing.T) {
|
|||
var out bytes.Buffer
|
||||
w := &jsonWriter{
|
||||
out: &out,
|
||||
done: make(chan bool),
|
||||
dryRun: true,
|
||||
}
|
||||
|
||||
|
|
@ -60,30 +58,3 @@ func TestJsonWriter_Event(t *testing.T) {
|
|||
}
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestJsonWriter_TailMsgf(t *testing.T) {
|
||||
var out bytes.Buffer
|
||||
w := &jsonWriter{
|
||||
out: &out,
|
||||
done: make(chan bool),
|
||||
dryRun: false,
|
||||
}
|
||||
|
||||
go func() {
|
||||
_ = w.Start(context.Background())
|
||||
}()
|
||||
|
||||
w.TailMsgf("hello %s", "world")
|
||||
|
||||
w.Stop()
|
||||
|
||||
var actual jsonMessage
|
||||
err := json.Unmarshal(out.Bytes(), &actual)
|
||||
assert.NilError(t, err)
|
||||
|
||||
expected := jsonMessage{
|
||||
Tail: true,
|
||||
Text: "hello world",
|
||||
}
|
||||
assert.DeepEqual(t, expected, actual)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
Copyright 2020 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"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/cli/cli/streams"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
)
|
||||
|
||||
// NewMixedWriter creates a Writer which allows to mix output from progress.Writer with a api.LogConsumer
|
||||
func NewMixedWriter(out *streams.Out, consumer api.LogConsumer, dryRun bool) Writer {
|
||||
isTerminal := out.IsTerminal()
|
||||
if Mode != ModeAuto || !isTerminal {
|
||||
return &plainWriter{
|
||||
out: out,
|
||||
done: make(chan bool),
|
||||
dryRun: dryRun,
|
||||
}
|
||||
}
|
||||
return &mixedWriter{
|
||||
out: consumer,
|
||||
done: make(chan bool),
|
||||
dryRun: dryRun,
|
||||
}
|
||||
}
|
||||
|
||||
type mixedWriter struct {
|
||||
done chan bool
|
||||
dryRun bool
|
||||
out api.LogConsumer
|
||||
}
|
||||
|
||||
func (p *mixedWriter) Start(ctx context.Context) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-p.done:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (p *mixedWriter) Event(e Event) {
|
||||
p.out.Status("", fmt.Sprintf("%s %s %s", e.ID, e.Text, SuccessColor(e.StatusText)))
|
||||
}
|
||||
|
||||
func (p *mixedWriter) Events(events []Event) {
|
||||
for _, e := range events {
|
||||
p.Event(e)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *mixedWriter) TailMsgf(msg string, args ...interface{}) {
|
||||
msg = fmt.Sprintf(msg, args...)
|
||||
p.out.Status("", WarningColor(msg))
|
||||
}
|
||||
|
||||
func (p *mixedWriter) Stop() {
|
||||
p.done <- true
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
Copyright 2020 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"
|
||||
)
|
||||
|
||||
type noopWriter struct{}
|
||||
|
||||
func (p *noopWriter) Start(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *noopWriter) Event(Event) {
|
||||
}
|
||||
|
||||
func (p *noopWriter) Events([]Event) {
|
||||
}
|
||||
|
||||
func (p *noopWriter) TailMsgf(_ string, _ ...interface{}) {
|
||||
}
|
||||
|
||||
func (p *noopWriter) Stop() {
|
||||
}
|
||||
|
|
@ -24,19 +24,18 @@ import (
|
|||
"github.com/docker/compose/v2/pkg/api"
|
||||
)
|
||||
|
||||
func NewPlainWriter(out io.Writer) EventProcessor {
|
||||
return &plainWriter{
|
||||
out: out,
|
||||
}
|
||||
}
|
||||
|
||||
type plainWriter struct {
|
||||
out io.Writer
|
||||
done chan bool
|
||||
dryRun bool
|
||||
}
|
||||
|
||||
func (p *plainWriter) Start(ctx context.Context) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-p.done:
|
||||
return nil
|
||||
}
|
||||
func (p *plainWriter) Start(ctx context.Context, operation string) {
|
||||
}
|
||||
|
||||
func (p *plainWriter) Event(e Event) {
|
||||
|
|
@ -47,20 +46,11 @@ func (p *plainWriter) Event(e Event) {
|
|||
_, _ = fmt.Fprintln(p.out, prefix, e.ID, e.Text, e.StatusText)
|
||||
}
|
||||
|
||||
func (p *plainWriter) Events(events []Event) {
|
||||
func (p *plainWriter) On(events ...Event) {
|
||||
for _, e := range events {
|
||||
p.Event(e)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *plainWriter) TailMsgf(msg string, args ...interface{}) {
|
||||
msg = fmt.Sprintf(msg, args...)
|
||||
if p.dryRun {
|
||||
msg = api.DRYRUN_PREFIX + msg
|
||||
}
|
||||
_, _ = fmt.Fprintln(p.out, msg)
|
||||
}
|
||||
|
||||
func (p *plainWriter) Stop() {
|
||||
p.done <- true
|
||||
func (p *plainWriter) Done(_ string, _ bool) {
|
||||
}
|
||||
|
|
|
|||
53
pkg/progress/progress.go
Normal file
53
pkg/progress/progress.go
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright 2020 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"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
)
|
||||
|
||||
type progressFunc func(context.Context) error
|
||||
|
||||
func RunWithLog(ctx context.Context, pf progressFunc, operation string, bus EventProcessor, logConsumer api.LogConsumer) error {
|
||||
// FIXME(ndeloof) re-implement support for logs during stop sequence
|
||||
return pf(ctx)
|
||||
}
|
||||
|
||||
func Run(ctx context.Context, pf progressFunc, operation string, bus EventProcessor) error {
|
||||
bus.Start(ctx, operation)
|
||||
err := pf(ctx)
|
||||
bus.Done(operation, err != nil)
|
||||
return err
|
||||
}
|
||||
|
||||
const (
|
||||
// ModeAuto detect console capabilities
|
||||
ModeAuto = "auto"
|
||||
// ModeTTY use terminal capability for advanced rendering
|
||||
ModeTTY = "tty"
|
||||
// ModePlain dump raw events to output
|
||||
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
|
||||
var Mode = ModeAuto
|
||||
|
|
@ -18,20 +18,17 @@ package progress
|
|||
|
||||
import "context"
|
||||
|
||||
func NewQuiedWriter() EventProcessor {
|
||||
return &quiet{}
|
||||
}
|
||||
|
||||
type quiet struct{}
|
||||
|
||||
func (q quiet) Start(_ context.Context) error {
|
||||
return nil
|
||||
func (q *quiet) Start(_ context.Context, _ string) {
|
||||
}
|
||||
|
||||
func (q quiet) Stop() {
|
||||
func (q *quiet) Done(_ string, _ bool) {
|
||||
}
|
||||
|
||||
func (q quiet) Event(_ Event) {
|
||||
}
|
||||
|
||||
func (q quiet) Events(_ []Event) {
|
||||
}
|
||||
|
||||
func (q quiet) TailMsgf(_ string, _ ...interface{}) {
|
||||
func (q *quiet) On(_ ...Event) {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,18 @@ import (
|
|||
"github.com/morikuni/aec"
|
||||
)
|
||||
|
||||
// NewTTYWriter creates an EventProcessor that render advanced UI within a terminal.
|
||||
// On Start, TUI lists task with a progress timer
|
||||
func NewTTYWriter(out io.Writer) EventProcessor {
|
||||
return &ttyWriter{
|
||||
out: out,
|
||||
tasks: map[string]task{},
|
||||
ids: []string{},
|
||||
done: make(chan bool),
|
||||
mtx: &sync.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
type ttyWriter struct {
|
||||
out io.Writer
|
||||
tasks map[string]task
|
||||
|
|
@ -40,10 +52,10 @@ type ttyWriter struct {
|
|||
numLines int
|
||||
done chan bool
|
||||
mtx *sync.Mutex
|
||||
tailEvents []string
|
||||
dryRun bool
|
||||
dryRun bool // FIXME(ndeloof) (re)implement support for dry-run
|
||||
skipChildEvents bool
|
||||
progressTitle string
|
||||
title string
|
||||
ticker *time.Ticker
|
||||
}
|
||||
|
||||
type task struct {
|
||||
|
|
@ -69,34 +81,40 @@ func (t *task) hasMore() {
|
|||
t.spinner.Restart()
|
||||
}
|
||||
|
||||
func (w *ttyWriter) Start(ctx context.Context) error {
|
||||
ticker := time.NewTicker(100 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
w.print()
|
||||
w.printTailEvents()
|
||||
return ctx.Err()
|
||||
case <-w.done:
|
||||
w.print()
|
||||
w.printTailEvents()
|
||||
return nil
|
||||
case <-ticker.C:
|
||||
w.print()
|
||||
func (w *ttyWriter) Start(ctx context.Context, operation string) {
|
||||
w.ticker = time.NewTicker(100 * time.Millisecond)
|
||||
w.title = operation
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// interrupted
|
||||
w.ticker.Stop()
|
||||
return
|
||||
case <-w.done:
|
||||
w.print()
|
||||
w.mtx.Lock()
|
||||
w.ticker.Stop()
|
||||
w.title = ""
|
||||
w.mtx.Unlock()
|
||||
return
|
||||
case <-w.ticker.C:
|
||||
w.print()
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (w *ttyWriter) Stop() {
|
||||
func (w *ttyWriter) Done(operation string, success bool) {
|
||||
w.done <- true
|
||||
}
|
||||
|
||||
func (w *ttyWriter) Event(e Event) {
|
||||
func (w *ttyWriter) On(events ...Event) {
|
||||
w.mtx.Lock()
|
||||
defer w.mtx.Unlock()
|
||||
w.event(e)
|
||||
for _, e := range events {
|
||||
w.event(e)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *ttyWriter) event(e Event) {
|
||||
|
|
@ -149,32 +167,27 @@ func (w *ttyWriter) event(e Event) {
|
|||
}
|
||||
w.tasks[e.ID] = t
|
||||
}
|
||||
w.printEvent(e)
|
||||
}
|
||||
|
||||
func (w *ttyWriter) Events(events []Event) {
|
||||
w.mtx.Lock()
|
||||
defer w.mtx.Unlock()
|
||||
for _, e := range events {
|
||||
w.event(e)
|
||||
func (w *ttyWriter) printEvent(e Event) {
|
||||
if w.title != "" {
|
||||
// event will be displayed by progress UI on ticker's ticks
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (w *ttyWriter) TailMsgf(msg string, args ...interface{}) {
|
||||
w.mtx.Lock()
|
||||
defer w.mtx.Unlock()
|
||||
msgWithPrefix := msg
|
||||
if w.dryRun {
|
||||
msgWithPrefix = strings.TrimSpace(api.DRYRUN_PREFIX + msg)
|
||||
}
|
||||
w.tailEvents = append(w.tailEvents, fmt.Sprintf(msgWithPrefix, args...))
|
||||
}
|
||||
|
||||
func (w *ttyWriter) printTailEvents() {
|
||||
w.mtx.Lock()
|
||||
defer w.mtx.Unlock()
|
||||
for _, msg := range w.tailEvents {
|
||||
_, _ = fmt.Fprintln(w.out, msg)
|
||||
var color colorFunc
|
||||
switch e.Status {
|
||||
case Working:
|
||||
color = SuccessColor
|
||||
case Done:
|
||||
color = SuccessColor
|
||||
case Warning:
|
||||
color = WarningColor
|
||||
case Error:
|
||||
color = ErrorColor
|
||||
}
|
||||
_, _ = fmt.Fprintf(w.out, "%s %s %s\n", e.ID, e.Text, color(e.StatusText))
|
||||
}
|
||||
|
||||
func (w *ttyWriter) print() { //nolint:gocyclo
|
||||
|
|
@ -200,7 +213,7 @@ func (w *ttyWriter) print() { //nolint:gocyclo
|
|||
_, _ = fmt.Fprint(w.out, aec.Show)
|
||||
}()
|
||||
|
||||
firstLine := fmt.Sprintf("[+] %s %d/%d", w.progressTitle, numDone(w.tasks), len(w.tasks))
|
||||
firstLine := fmt.Sprintf("[+] %s %d/%d", w.title, numDone(w.tasks), len(w.tasks))
|
||||
if w.numLines != 0 && numDone(w.tasks) == w.numLines {
|
||||
firstLine = DoneColor(firstLine)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
Copyright 2020 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"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/cli/cli/streams"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
)
|
||||
|
||||
// Writer can write multiple progress events
|
||||
type Writer interface {
|
||||
Start(context.Context) error
|
||||
Stop()
|
||||
Event(Event)
|
||||
Events([]Event)
|
||||
TailMsgf(string, ...interface{})
|
||||
}
|
||||
|
||||
type writerKey struct{}
|
||||
|
||||
// WithContextWriter adds the writer to the context
|
||||
func WithContextWriter(ctx context.Context, writer Writer) context.Context {
|
||||
return context.WithValue(ctx, writerKey{}, writer)
|
||||
}
|
||||
|
||||
// ContextWriter returns the writer from the context
|
||||
func ContextWriter(ctx context.Context) Writer {
|
||||
s, ok := ctx.Value(writerKey{}).(Writer)
|
||||
if !ok {
|
||||
return &noopWriter{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type progressFunc func(context.Context) error
|
||||
|
||||
func RunWithLog(ctx context.Context, pf progressFunc, out *streams.Out, logConsumer api.LogConsumer) error {
|
||||
w := NewMixedWriter(out, logConsumer, false) // FIXME(ndeloof) re-implement dry-run
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
eg.Go(func() error {
|
||||
return w.Start(context.Background())
|
||||
})
|
||||
eg.Go(func() error {
|
||||
defer w.Stop()
|
||||
ctx = WithContextWriter(ctx, w)
|
||||
err := pf(ctx)
|
||||
return err
|
||||
})
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
func Run(ctx context.Context, pf progressFunc, out *streams.Out, progressTitle string) error {
|
||||
eg, _ := errgroup.WithContext(ctx)
|
||||
w, err := NewWriter(ctx, out, progressTitle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
eg.Go(func() error {
|
||||
return w.Start(context.Background())
|
||||
})
|
||||
|
||||
ctx = WithContextWriter(ctx, w)
|
||||
|
||||
eg.Go(func() error {
|
||||
defer w.Stop()
|
||||
err := pf(ctx)
|
||||
return err
|
||||
})
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
const (
|
||||
// ModeAuto detect console capabilities
|
||||
ModeAuto = "auto"
|
||||
// ModeTTY use terminal capability for advanced rendering
|
||||
ModeTTY = "tty"
|
||||
// ModePlain dump raw events to output
|
||||
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
|
||||
var Mode = ModeAuto
|
||||
|
||||
// NewWriter returns a new multi-progress writer
|
||||
func NewWriter(ctx context.Context, out *streams.Out, progressTitle string) (Writer, error) {
|
||||
isTerminal := out.IsTerminal()
|
||||
switch Mode {
|
||||
case ModeQuiet:
|
||||
return quiet{}, nil
|
||||
case ModeJSON:
|
||||
return &jsonWriter{
|
||||
out: out,
|
||||
done: make(chan bool),
|
||||
dryRun: false, // FIXME(ndeloof) re-implement dry-run
|
||||
}, nil
|
||||
case ModeTTY:
|
||||
return newTTYWriter(out, false, progressTitle)
|
||||
case ModeAuto, "":
|
||||
if isTerminal {
|
||||
return newTTYWriter(out, false, progressTitle)
|
||||
}
|
||||
fallthrough
|
||||
case ModePlain:
|
||||
return &plainWriter{
|
||||
out: out,
|
||||
done: make(chan bool),
|
||||
dryRun: false,
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unknown progress mode: %s", Mode)
|
||||
}
|
||||
|
||||
func newTTYWriter(out io.Writer, dryRun bool, progressTitle string) (Writer, error) {
|
||||
return &ttyWriter{
|
||||
out: out,
|
||||
ids: []string{},
|
||||
tasks: map[string]task{},
|
||||
repeated: false,
|
||||
done: make(chan bool),
|
||||
mtx: &sync.Mutex{},
|
||||
dryRun: dryRun,
|
||||
progressTitle: progressTitle,
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
Copyright 2020 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"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
)
|
||||
|
||||
func TestNoopWriter(t *testing.T) {
|
||||
todo := context.TODO()
|
||||
writer := ContextWriter(todo)
|
||||
|
||||
assert.Equal(t, writer, &noopWriter{})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue