From d762f5f473668979c35abff7681454cb154f3617 Mon Sep 17 00:00:00 2001 From: Nicolas De loof Date: Tue, 4 Apr 2023 23:00:10 +0200 Subject: [PATCH] better support NO_COLOR by disabling colors, not ANSI TUI (#10434) Signed-off-by: Nicolas De Loof --- cmd/compose/compose.go | 8 ++++--- pkg/progress/colors.go | 47 ++++++++++++++++++++++++++++++++++++++++ pkg/progress/event.go | 24 ++++++++++---------- pkg/progress/tty.go | 12 +++++----- pkg/progress/tty_test.go | 6 ++--- 5 files changed, 72 insertions(+), 25 deletions(-) create mode 100644 pkg/progress/colors.go diff --git a/cmd/compose/compose.go b/cmd/compose/compose.go index 4c59666c..786bec67 100644 --- a/cmd/compose/compose.go +++ b/cmd/compose/compose.go @@ -305,11 +305,13 @@ func RootCommand(streams command.Cli, backend api.Service) *cobra.Command { //no logrus.SetLevel(logrus.TraceLevel) } - if noColor, ok := os.LookupEnv("NO_COLOR"); ok && noColor != "" && !cmd.Flags().Changed("ansi") { - ansi = "never" + formatter.SetANSIMode(streams, ansi) + + if noColor, ok := os.LookupEnv("NO_COLOR"); ok && noColor != "" { + progress.NoColor() + formatter.SetANSIMode(streams, formatter.Never) } - formatter.SetANSIMode(streams, ansi) switch ansi { case "never": progress.Mode = progress.ModePlain diff --git a/pkg/progress/colors.go b/pkg/progress/colors.go new file mode 100644 index 00000000..716171df --- /dev/null +++ b/pkg/progress/colors.go @@ -0,0 +1,47 @@ +/* + 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 ( + "github.com/morikuni/aec" +) + +type colorFunc func(string) string + +var ( + nocolor colorFunc = func(s string) string { + return s + } + + DoneColor colorFunc = aec.BlueF.Apply + TimerColor colorFunc = aec.BlueF.Apply + CountColor colorFunc = aec.YellowF.Apply + WarningColor colorFunc = aec.YellowF.With(aec.Bold).Apply + SuccessColor colorFunc = aec.GreenF.Apply + ErrorColor colorFunc = aec.RedF.With(aec.Bold).Apply + PrefixColor colorFunc = aec.CyanF.Apply +) + +func NoColor() { + DoneColor = nocolor + TimerColor = nocolor + CountColor = nocolor + WarningColor = nocolor + SuccessColor = nocolor + ErrorColor = nocolor + PrefixColor = nocolor +} diff --git a/pkg/progress/event.go b/pkg/progress/event.go index 1cd5846a..fbb85038 100644 --- a/pkg/progress/event.go +++ b/pkg/progress/event.go @@ -18,23 +18,21 @@ package progress import ( "time" - - "github.com/morikuni/aec" ) // EventStatus indicates the status of an action type EventStatus int -func (s EventStatus) color() aec.ANSI { +func (s EventStatus) colorFn() colorFunc { switch s { case Done: - return aec.GreenF + return SuccessColor case Warning: - return aec.YellowF.With(aec.Bold) + return WarningColor case Error: - return aec.RedF.With(aec.Bold) + return ErrorColor default: - return aec.DefaultF + return nocolor } } @@ -170,19 +168,19 @@ func (e *Event) stop() { } var ( - spinnerDone = aec.Apply("✔", aec.GreenF) - spinnerWarning = aec.Apply("!", aec.YellowF) - spinnerError = aec.Apply("✘", aec.RedF) + spinnerDone = "✔" + spinnerWarning = "!" + spinnerError = "✘" ) func (e *Event) Spinner() any { switch e.Status { case Done: - return spinnerDone + return SuccessColor(spinnerDone) case Warning: - return spinnerWarning + return WarningColor(spinnerWarning) case Error: - return spinnerError + return ErrorColor(spinnerError) default: return e.spinner.String() } diff --git a/pkg/progress/tty.go b/pkg/progress/tty.go index 148826a6..36c7653f 100644 --- a/pkg/progress/tty.go +++ b/pkg/progress/tty.go @@ -151,7 +151,7 @@ func (w *ttyWriter) print() { //nolint:gocyclo firstLine := fmt.Sprintf("[+] Running %d/%d", numDone(w.events), w.numLines) if w.numLines != 0 && numDone(w.events) == w.numLines { - firstLine = aec.Apply(firstLine, aec.BlueF) + firstLine = DoneColor(firstLine) } fmt.Fprintln(w.out, firstLine) @@ -210,7 +210,7 @@ func (w *ttyWriter) lineText(event Event, pad string, terminalWidth, statusPaddi } prefix := "" if dryRun { - prefix = aec.Apply(api.DRYRUN_PREFIX, aec.CyanF) + prefix = PrefixColor(api.DRYRUN_PREFIX) } elapsed := endTime.Sub(event.startTime).Seconds() @@ -234,8 +234,8 @@ func (w *ttyWriter) lineText(event Event, pad string, terminalWidth, statusPaddi if len(completion) > 0 { txt = fmt.Sprintf("%s %s [%s] %7s/%-7s %s", event.ID, - aec.Apply(fmt.Sprintf("%d layers", len(completion)), aec.YellowF), - aec.Apply(strings.Join(completion, ""), aec.GreenF, aec.Bold), + CountColor(fmt.Sprintf("%d layers", len(completion))), + SuccessColor(strings.Join(completion, "")), units.HumanSize(float64(current)), units.HumanSize(float64(total)), event.Text) } else { @@ -260,10 +260,10 @@ func (w *ttyWriter) lineText(event Event, pad string, terminalWidth, statusPaddi prefix, txt, strings.Repeat(" ", padding), - aec.Apply(status, event.Status.color()), + event.Status.colorFn()(status), ) timer := fmt.Sprintf("%.1fs ", elapsed) - o := align(text, aec.Apply(timer, aec.BlueF), terminalWidth) + o := align(text, TimerColor(timer), terminalWidth) return o } diff --git a/pkg/progress/tty_test.go b/pkg/progress/tty_test.go index bbc311f9..6ffdf2be 100644 --- a/pkg/progress/tty_test.go +++ b/pkg/progress/tty_test.go @@ -42,7 +42,7 @@ func TestLineText(t *testing.T) { lineWidth := len(fmt.Sprintf("%s %s", ev.ID, ev.Text)) out := tty().lineText(ev, "", 50, lineWidth, false) - assert.Equal(t, out, " . id Text \x1b[39mStatus\x1b[0m \x1b[34m0.0s \x1b[0m\n") + assert.Equal(t, out, " . id Text Status \x1b[34m0.0s \x1b[0m\n") ev.Status = Done out = tty().lineText(ev, "", 50, lineWidth, false) @@ -50,11 +50,11 @@ func TestLineText(t *testing.T) { ev.Status = Error out = tty().lineText(ev, "", 50, lineWidth, false) - assert.Equal(t, out, " \x1b[31m✘\x1b[0m id Text \x1b[31m\x1b[1mStatus\x1b[0m \x1b[34m0.0s \x1b[0m\n") + assert.Equal(t, out, " \x1b[31m\x1b[1m✘\x1b[0m id Text \x1b[31m\x1b[1mStatus\x1b[0m \x1b[34m0.0s \x1b[0m\n") ev.Status = Warning out = tty().lineText(ev, "", 50, lineWidth, false) - assert.Equal(t, out, " \x1b[33m!\x1b[0m id Text \x1b[33m\x1b[1mStatus\x1b[0m \x1b[34m0.0s \x1b[0m\n") + assert.Equal(t, out, " \x1b[33m\x1b[1m!\x1b[0m id Text \x1b[33m\x1b[1mStatus\x1b[0m \x1b[34m0.0s \x1b[0m\n") } func TestLineTextSingleEvent(t *testing.T) {