Skip to content

Commit

Permalink
Use heroku/color for our colors
Browse files Browse the repository at this point in the history
Signed-off-by: David Gageot <david@gageot.net>
  • Loading branch information
dgageot committed Feb 28, 2020
1 parent 1ca0138 commit 2c28358
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 161 deletions.
8 changes: 2 additions & 6 deletions cmd/skaffold/app/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,7 @@ func NewSkaffoldCommand(out, err io.Writer) *cobra.Command {

opts.Command = cmd.Use

// Setup colors
if forceColors {
color.ForceColors()
}
color.OverwriteDefault(color.Color(defaultColor))
color.SetupColors(out, defaultColor, forceColors)
cmd.Root().SetOutput(out)

// Setup logs
Expand Down Expand Up @@ -167,7 +163,7 @@ func NewSkaffoldCommand(out, err io.Writer) *cobra.Command {

templates.ActsAsRootCommand(rootCmd, nil, groups...)
rootCmd.PersistentFlags().StringVarP(&v, "verbosity", "v", constants.DefaultLogLevel.String(), "Log level (debug, info, warn, error, fatal, panic)")
rootCmd.PersistentFlags().IntVar(&defaultColor, "color", int(color.Default), "Specify the default output color in ANSI escape codes")
rootCmd.PersistentFlags().IntVar(&defaultColor, "color", int(color.DefaultColorCode), "Specify the default output color in ANSI escape codes")
rootCmd.PersistentFlags().BoolVar(&forceColors, "force-colors", false, "Always print color codes (hidden)")
rootCmd.PersistentFlags().MarkHidden("force-colors")

Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ require (
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484 // indirect
github.com/elazarl/goproxy/ext v0.0.0-20191011121108-aa519ddbe484 // indirect
github.com/evanphx/json-patch v4.5.0+incompatible // indirect
github.com/fatih/color v1.7.0
github.com/ghodss/yaml v1.0.0
github.com/gobuffalo/envy v1.7.1 // indirect
github.com/gogo/protobuf v1.3.1 // indirect
Expand All @@ -57,6 +58,7 @@ require (
github.com/googleapis/gnostic v0.3.1 // indirect
github.com/gophercloud/gophercloud v0.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.12.1
github.com/heroku/color v0.0.6
github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c // indirect
github.com/imdario/mergo v0.3.8
github.com/jstemmer/go-junit-report v0.9.1 // indirect
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5I
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
Expand Down
10 changes: 1 addition & 9 deletions pkg/skaffold/build/parallel.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,12 @@ func InParallel(ctx context.Context, out io.Writer, tags tag.ImageTags, artifact
for i := range artifacts {
outputs[i] = make(chan string, buffSize)
r, w := io.Pipe()
cw := setUpColorWriter(w, out)

// Run build and write output/logs to piped writer and store build result in
// sync.Map
go func(i int) {
sem <- true
runBuild(ctx, cw, tags, artifacts[i], results, buildArtifact)
runBuild(ctx, w, tags, artifacts[i], results, buildArtifact)
<-sem

wg.Done()
Expand Down Expand Up @@ -113,13 +112,6 @@ func readOutputAndWriteToChannel(r io.Reader, lines chan string) {
close(lines)
}

func setUpColorWriter(w io.WriteCloser, out io.Writer) io.WriteCloser {
if color.IsTerminal(out) {
return color.ColoredWriteCloser{WriteCloser: w}
}
return w
}

func getBuildResult(ctx context.Context, cw io.Writer, tags tag.ImageTags, artifact *latest.Artifact, build artifactBuilder) (string, error) {
color.Default.Fprintf(cw, "Building [%s]...\n", artifact.ImageName)
tag, present := tags[artifact.ImageName]
Expand Down
31 changes: 0 additions & 31 deletions pkg/skaffold/build/parallel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
"time"

"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/tag"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/color"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
"github.com/GoogleContainerTools/skaffold/testutil"
)
Expand Down Expand Up @@ -353,36 +352,6 @@ func TestInParallelForArgs(t *testing.T) {
}
}

func TestColoredOutput(t *testing.T) {
tests := []struct {
description string
isTerminal func(w io.Writer) bool
exceptedColor bool
}{
{
description: "setUpColorWriter returns color out writer for terminal",
isTerminal: func(w io.Writer) bool { return true },
exceptedColor: true,
},
{
description: "setUpColorWriter returns color out writer if not terminal",
isTerminal: func(w io.Writer) bool { return false },
exceptedColor: false,
},
}
for _, test := range tests {
testutil.Run(t, test.description, func(t *testutil.T) {
t.Override(&color.IsTerminal, test.isTerminal)

_, w := io.Pipe()
actual := setUpColorWriter(w, ioutil.Discard)

_, isColorWriter := actual.(color.ColoredWriteCloser)
t.CheckDeepEqual(test.exceptedColor, isColorWriter)
})
}
}

func setUpChannels(n int) []chan string {
outputs := make([]chan string, n)
for i := 0; i < n; i++ {
Expand Down
145 changes: 73 additions & 72 deletions pkg/skaffold/color/formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,93 +22,94 @@ import (
"strings"

"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
"github.com/heroku/color"
hc "github.com/heroku/color"
)

// IsTerminal will check if the specified output stream is a terminal. This can be changed
// for testing to an arbitrary method.
var IsTerminal = isTerminal
// Maintain compatibility with the old color coding.
// 34 is the code for blue.
const DefaultColorCode = 34

// Color can be used to format text using ANSI escape codes so it can be printed to
// the terminal in color.
type Color int
func init() {
color.Disable(true)
}

// SetupColors enables/disables coloured output.
func SetupColors(out io.Writer, defaultColor int, forceColors bool) {
_, isTerm := util.IsTerminal(out)
color.Disable(!isTerm && !forceColors)

// Maintain compatibility with the old color coding.
Default = map[int]Color{
91: LightRed,
92: LightGreen,
93: LightYellow,
94: LightBlue,
95: LightPurple,
31: Red,
32: Green,
33: Yellow,
34: Blue,
35: Purple,
36: Cyan,
37: White,
0: None,
}[defaultColor]
}

// Color can be used to format text so it can be printed to the terminal in color.
type Color struct {
color *hc.Color
}

var (
// LightRed can format text to be displayed to the terminal in light red, using ANSI escape codes.
LightRed = Color(91)
// LightGreen can format text to be displayed to the terminal in light green, using ANSI escape codes.
LightGreen = Color(92)
// LightYellow can format text to be displayed to the terminal in light yellow, using ANSI escape codes.
LightYellow = Color(93)
// LightBlue can format text to be displayed to the terminal in light blue, using ANSI escape codes.
LightBlue = Color(94)
// LightPurple can format text to be displayed to the terminal in light purple, using ANSI escape codes.
LightPurple = Color(95)
// Red can format text to be displayed to the terminal in red, using ANSI escape codes.
Red = Color(31)
// Green can format text to be displayed to the terminal in green, using ANSI escape codes.
Green = Color(32)
// Yellow can format text to be displayed to the terminal in yellow, using ANSI escape codes.
Yellow = Color(33)
// Blue can format text to be displayed to the terminal in blue, using ANSI escape codes.
Blue = Color(34)
// Purple can format text to be displayed to the terminal in purple, using ANSI escape codes.
Purple = Color(35)
// Cyan can format text to be displayed to the terminal in cyan, using ANSI escape codes.
Cyan = Color(36)
// White can format text to be displayed to the terminal in white, using ANSI escape codes.
White = Color(37)
// LightRed can format text to be displayed to the terminal in light red.
LightRed = Color{color: hc.New(hc.FgHiRed)}
// LightGreen can format text to be displayed to the terminal in light green.
LightGreen = Color{color: hc.New(hc.FgHiGreen)}
// LightYellow can format text to be displayed to the terminal in light yellow.
LightYellow = Color{color: hc.New(hc.FgHiYellow)}
// LightBlue can format text to be displayed to the terminal in light blue.
LightBlue = Color{color: hc.New(hc.FgHiBlue)}
// LightPurple can format text to be displayed to the terminal in light purple.
LightPurple = Color{color: hc.New(hc.FgHiMagenta)}
// Red can format text to be displayed to the terminal in red.
Red = Color{color: hc.New(hc.FgRed)}
// Green can format text to be displayed to the terminal in green.
Green = Color{color: hc.New(hc.FgGreen)}
// Yellow can format text to be displayed to the terminal in yellow.
Yellow = Color{color: hc.New(hc.FgYellow)}
// Blue can format text to be displayed to the terminal in blue.
Blue = Color{color: hc.New(hc.FgBlue)}
// Purple can format text to be displayed to the terminal in purple.
Purple = Color{color: hc.New(hc.FgHiMagenta)}
// Cyan can format text to be displayed to the terminal in cyan.
Cyan = Color{color: hc.New(hc.FgHiCyan)}
// White can format text to be displayed to the terminal in white.
White = Color{color: hc.New(hc.FgWhite)}
// None uses ANSI escape codes to reset all formatting.
None = Color(0)
None = Color{}

// Default default output color for output from Skaffold to the user
Default = Blue
)

// Fprintln wraps the operands in c's ANSI escape codes, and outputs the result to
// out, followed by a newline. If out is not a terminal, the escape codes will not be added.
// It returns the number of bytes written and any errors encountered.
func (c Color) Fprintln(out io.Writer, a ...interface{}) (n int, err error) {
if IsTerminal(out) {
return fmt.Fprintf(out, "\033[%dm%s\033[0m\n", c, strings.TrimSuffix(fmt.Sprintln(a...), "\n"))
// Fprintln outputs the result to out, followed by a newline.
func (c Color) Fprintln(out io.Writer, a ...interface{}) {
if c.color == nil {
fmt.Fprintln(out, a...)
return
}
return fmt.Fprintln(out, a...)
}

// Fprintf applies formats according to the format specifier (and the optional interfaces provided),
// wraps the result in c's ANSI escape codes, and outputs the result to
// out, followed by a newline. If out is not a terminal, the escape codes will not be added.
// It returns the number of bytes written and any errors encountered.
func (c Color) Fprintf(out io.Writer, format string, a ...interface{}) (n int, err error) {
if IsTerminal(out) {
return fmt.Fprintf(out, "\033[%dm%s\033[0m", c, fmt.Sprintf(format, a...))
}
return fmt.Fprintf(out, format, a...)
fmt.Fprintln(out, c.color.Sprint(strings.TrimSuffix(fmt.Sprintln(a...), "\n")))
}

// ColoredWriteCloser forces printing with colors to an io.WriteCloser.
type ColoredWriteCloser struct {
io.WriteCloser
}

// OverwriteDefault overwrites default color
func OverwriteDefault(color Color) {
Default = color
}

func isTerminal(w io.Writer) bool {
if _, ok := w.(ColoredWriteCloser); ok {
return true
// Fprintf outputs the result to out.
func (c Color) Fprintf(out io.Writer, format string, a ...interface{}) {
if c.color == nil {
fmt.Fprintf(out, format, a...)
return
}

_, isTerm := util.IsTerminal(w)
return isTerm
}

func ForceColors() func() {
IsTerminal = func(_ io.Writer) bool {
return true
}
return func() {
IsTerminal = isTerminal
}
fmt.Fprint(out, c.color.Sprintf(format, a...))
}
Loading

0 comments on commit 2c28358

Please sign in to comment.