github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/output/color.go (about) 1 /* 2 Copyright 2020 The Skaffold 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 output 18 19 import ( 20 "context" 21 "fmt" 22 "io" 23 "strings" 24 25 colors "github.com/heroku/color" 26 "github.com/mattn/go-colorable" 27 28 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log" 29 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util/term" 30 ) 31 32 // Maintain compatibility with the old color coding. 33 // 34 is the code for blue. 34 const DefaultColorCode = 34 35 36 func init() { 37 colors.Disable(true) 38 } 39 40 var DefaultColorCodes = []Color{ 41 LightRed, 42 LightGreen, 43 LightYellow, 44 LightBlue, 45 LightPurple, 46 Red, 47 Green, 48 Yellow, 49 Blue, 50 Purple, 51 Cyan, 52 } 53 54 // SetupColors conditionally wraps the input `Writer` with a color enabled `Writer`. 55 func SetupColors(ctx context.Context, out io.Writer, defaultColor int, forceColors bool) io.Writer { 56 _, isTerm := term.IsTerminal(out) 57 supportsColor, err := term.SupportsColor(ctx) 58 if err != nil { 59 log.Entry(context.TODO()).Debugf("error checking for color support: %v", err) 60 } 61 62 useColors := (isTerm && supportsColor) || forceColors 63 if useColors { 64 // Use EnableColorsStdout to enable use of color on Windows 65 useColors = false // value is updated if color-enablement is successful 66 colorable.EnableColorsStdout(&useColors) 67 } 68 colors.Disable(!useColors) 69 70 // Maintain compatibility with the old color coding. 71 Default = map[int]Color{ 72 91: LightRed, 73 92: LightGreen, 74 93: LightYellow, 75 94: LightBlue, 76 95: LightPurple, 77 31: Red, 78 32: Green, 79 33: Yellow, 80 34: Blue, 81 35: Purple, 82 36: Cyan, 83 37: White, 84 0: None, 85 }[defaultColor] 86 87 if useColors { 88 return NewColorWriter(out) 89 } 90 return out 91 } 92 93 // Color can be used to format text so it can be printed to the terminal in color. 94 type Color struct { 95 color *colors.Color 96 } 97 98 type colorableWriter struct { 99 io.Writer 100 } 101 102 var ( 103 // LightRed can format text to be displayed to the terminal in light red. 104 LightRed = Color{color: colors.New(colors.FgHiRed)} 105 // LightGreen can format text to be displayed to the terminal in light green. 106 LightGreen = Color{color: colors.New(colors.FgHiGreen)} 107 // LightYellow can format text to be displayed to the terminal in light yellow. 108 LightYellow = Color{color: colors.New(colors.FgHiYellow)} 109 // LightBlue can format text to be displayed to the terminal in light blue. 110 LightBlue = Color{color: colors.New(colors.FgHiBlue)} 111 // LightPurple can format text to be displayed to the terminal in light purple. 112 LightPurple = Color{color: colors.New(colors.FgHiMagenta)} 113 // Red can format text to be displayed to the terminal in red. 114 Red = Color{color: colors.New(colors.FgRed)} 115 // Green can format text to be displayed to the terminal in green. 116 Green = Color{color: colors.New(colors.FgGreen)} 117 // Yellow can format text to be displayed to the terminal in yellow. 118 Yellow = Color{color: colors.New(colors.FgYellow)} 119 // Blue can format text to be displayed to the terminal in blue. 120 Blue = Color{color: colors.New(colors.FgBlue)} 121 // Purple can format text to be displayed to the terminal in purple. 122 Purple = Color{color: colors.New(colors.FgHiMagenta)} 123 // Cyan can format text to be displayed to the terminal in cyan. 124 Cyan = Color{color: colors.New(colors.FgHiCyan)} 125 // White can format text to be displayed to the terminal in white. 126 White = Color{color: colors.New(colors.FgWhite)} 127 // None uses ANSI escape codes to reset all formatting. 128 None = Color{} 129 130 // Default default output color for output from Skaffold to the user 131 Default = Blue 132 ) 133 134 // Fprintln outputs the result to out, followed by a newline. 135 func (c Color) Fprintln(out io.Writer, a ...interface{}) { 136 if c.color == nil || !IsColorable(out) { 137 fmt.Fprintln(out, a...) 138 return 139 } 140 141 fmt.Fprintln(out, c.color.Sprint(strings.TrimSuffix(fmt.Sprintln(a...), "\n"))) 142 } 143 144 // Fprintf outputs the result to out. 145 func (c Color) Fprintf(out io.Writer, format string, a ...interface{}) { 146 if c.color == nil || !IsColorable(out) { 147 fmt.Fprintf(out, format, a...) 148 return 149 } 150 151 fmt.Fprint(out, c.color.Sprintf(format, a...)) 152 } 153 154 func (c Color) Sprintf(format string, a ...interface{}) string { 155 if c.color == nil { 156 return fmt.Sprintf(format, a...) 157 } 158 159 return c.color.Sprintf(format, a...) 160 } 161 162 func NewColorWriter(out io.Writer) io.Writer { 163 return colorableWriter{out} 164 } 165 166 func IsColorable(out io.Writer) bool { 167 switch w := out.(type) { 168 case colorableWriter: 169 return true 170 case skaffoldWriter: 171 return IsColorable(w.MainWriter) 172 default: 173 return false 174 } 175 }