Skip to content

Commit d762f5f

Browse files
authored
better support NO_COLOR by disabling colors, not ANSI TUI (docker#10434)
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent 90eda35 commit d762f5f

File tree

5 files changed

+72
-25
lines changed

5 files changed

+72
-25
lines changed

cmd/compose/compose.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,11 +305,13 @@ func RootCommand(streams command.Cli, backend api.Service) *cobra.Command { //no
305305
logrus.SetLevel(logrus.TraceLevel)
306306
}
307307

308-
if noColor, ok := os.LookupEnv("NO_COLOR"); ok && noColor != "" && !cmd.Flags().Changed("ansi") {
309-
ansi = "never"
308+
formatter.SetANSIMode(streams, ansi)
309+
310+
if noColor, ok := os.LookupEnv("NO_COLOR"); ok && noColor != "" {
311+
progress.NoColor()
312+
formatter.SetANSIMode(streams, formatter.Never)
310313
}
311314

312-
formatter.SetANSIMode(streams, ansi)
313315
switch ansi {
314316
case "never":
315317
progress.Mode = progress.ModePlain

pkg/progress/colors.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
Copyright 2020 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+
"github.com/morikuni/aec"
21+
)
22+
23+
type colorFunc func(string) string
24+
25+
var (
26+
nocolor colorFunc = func(s string) string {
27+
return s
28+
}
29+
30+
DoneColor colorFunc = aec.BlueF.Apply
31+
TimerColor colorFunc = aec.BlueF.Apply
32+
CountColor colorFunc = aec.YellowF.Apply
33+
WarningColor colorFunc = aec.YellowF.With(aec.Bold).Apply
34+
SuccessColor colorFunc = aec.GreenF.Apply
35+
ErrorColor colorFunc = aec.RedF.With(aec.Bold).Apply
36+
PrefixColor colorFunc = aec.CyanF.Apply
37+
)
38+
39+
func NoColor() {
40+
DoneColor = nocolor
41+
TimerColor = nocolor
42+
CountColor = nocolor
43+
WarningColor = nocolor
44+
SuccessColor = nocolor
45+
ErrorColor = nocolor
46+
PrefixColor = nocolor
47+
}

pkg/progress/event.go

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,21 @@ package progress
1818

1919
import (
2020
"time"
21-
22-
"github.com/morikuni/aec"
2321
)
2422

2523
// EventStatus indicates the status of an action
2624
type EventStatus int
2725

28-
func (s EventStatus) color() aec.ANSI {
26+
func (s EventStatus) colorFn() colorFunc {
2927
switch s {
3028
case Done:
31-
return aec.GreenF
29+
return SuccessColor
3230
case Warning:
33-
return aec.YellowF.With(aec.Bold)
31+
return WarningColor
3432
case Error:
35-
return aec.RedF.With(aec.Bold)
33+
return ErrorColor
3634
default:
37-
return aec.DefaultF
35+
return nocolor
3836
}
3937
}
4038

@@ -170,19 +168,19 @@ func (e *Event) stop() {
170168
}
171169

172170
var (
173-
spinnerDone = aec.Apply("✔", aec.GreenF)
174-
spinnerWarning = aec.Apply("!", aec.YellowF)
175-
spinnerError = aec.Apply("✘", aec.RedF)
171+
spinnerDone = "✔"
172+
spinnerWarning = "!"
173+
spinnerError = "✘"
176174
)
177175

178176
func (e *Event) Spinner() any {
179177
switch e.Status {
180178
case Done:
181-
return spinnerDone
179+
return SuccessColor(spinnerDone)
182180
case Warning:
183-
return spinnerWarning
181+
return WarningColor(spinnerWarning)
184182
case Error:
185-
return spinnerError
183+
return ErrorColor(spinnerError)
186184
default:
187185
return e.spinner.String()
188186
}

pkg/progress/tty.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ func (w *ttyWriter) print() { //nolint:gocyclo
151151

152152
firstLine := fmt.Sprintf("[+] Running %d/%d", numDone(w.events), w.numLines)
153153
if w.numLines != 0 && numDone(w.events) == w.numLines {
154-
firstLine = aec.Apply(firstLine, aec.BlueF)
154+
firstLine = DoneColor(firstLine)
155155
}
156156
fmt.Fprintln(w.out, firstLine)
157157

@@ -210,7 +210,7 @@ func (w *ttyWriter) lineText(event Event, pad string, terminalWidth, statusPaddi
210210
}
211211
prefix := ""
212212
if dryRun {
213-
prefix = aec.Apply(api.DRYRUN_PREFIX, aec.CyanF)
213+
prefix = PrefixColor(api.DRYRUN_PREFIX)
214214
}
215215

216216
elapsed := endTime.Sub(event.startTime).Seconds()
@@ -234,8 +234,8 @@ func (w *ttyWriter) lineText(event Event, pad string, terminalWidth, statusPaddi
234234
if len(completion) > 0 {
235235
txt = fmt.Sprintf("%s %s [%s] %7s/%-7s %s",
236236
event.ID,
237-
aec.Apply(fmt.Sprintf("%d layers", len(completion)), aec.YellowF),
238-
aec.Apply(strings.Join(completion, ""), aec.GreenF, aec.Bold),
237+
CountColor(fmt.Sprintf("%d layers", len(completion))),
238+
SuccessColor(strings.Join(completion, "")),
239239
units.HumanSize(float64(current)), units.HumanSize(float64(total)),
240240
event.Text)
241241
} else {
@@ -260,10 +260,10 @@ func (w *ttyWriter) lineText(event Event, pad string, terminalWidth, statusPaddi
260260
prefix,
261261
txt,
262262
strings.Repeat(" ", padding),
263-
aec.Apply(status, event.Status.color()),
263+
event.Status.colorFn()(status),
264264
)
265265
timer := fmt.Sprintf("%.1fs ", elapsed)
266-
o := align(text, aec.Apply(timer, aec.BlueF), terminalWidth)
266+
o := align(text, TimerColor(timer), terminalWidth)
267267

268268
return o
269269
}

pkg/progress/tty_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,19 @@ func TestLineText(t *testing.T) {
4242
lineWidth := len(fmt.Sprintf("%s %s", ev.ID, ev.Text))
4343

4444
out := tty().lineText(ev, "", 50, lineWidth, false)
45-
assert.Equal(t, out, " . id Text \x1b[39mStatus\x1b[0m \x1b[34m0.0s \x1b[0m\n")
45+
assert.Equal(t, out, " . id Text Status \x1b[34m0.0s \x1b[0m\n")
4646

4747
ev.Status = Done
4848
out = tty().lineText(ev, "", 50, lineWidth, false)
4949
assert.Equal(t, out, " \x1b[32m✔\x1b[0m id Text \x1b[32mStatus\x1b[0m \x1b[34m0.0s \x1b[0m\n")
5050

5151
ev.Status = Error
5252
out = tty().lineText(ev, "", 50, lineWidth, false)
53-
assert.Equal(t, out, " \x1b[31m✘\x1b[0m id Text \x1b[31m\x1b[1mStatus\x1b[0m \x1b[34m0.0s \x1b[0m\n")
53+
assert.Equal(t, out, " \x1b[31m\x1b[1m\x1b[0m id Text \x1b[31m\x1b[1mStatus\x1b[0m \x1b[34m0.0s \x1b[0m\n")
5454

5555
ev.Status = Warning
5656
out = tty().lineText(ev, "", 50, lineWidth, false)
57-
assert.Equal(t, out, " \x1b[33m!\x1b[0m id Text \x1b[33m\x1b[1mStatus\x1b[0m \x1b[34m0.0s \x1b[0m\n")
57+
assert.Equal(t, out, " \x1b[33m\x1b[1m!\x1b[0m id Text \x1b[33m\x1b[1mStatus\x1b[0m \x1b[34m0.0s \x1b[0m\n")
5858
}
5959

6060
func TestLineTextSingleEvent(t *testing.T) {

0 commit comments

Comments
 (0)