Skip to content

Commit

Permalink
Add support for defining custom colors
Browse files Browse the repository at this point in the history
  • Loading branch information
spkane committed Jul 11, 2022
1 parent 1800adb commit 730fe40
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 22 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,11 @@ By default, the build result and intermediate cache will only remain internally

> Color Output Controls
>
> `buildctl` has support for modifying the colors that are used to output information to the terminal. You can set the environment varliable `BUILDKIT_COLORS` to something like `run=blue;cancel=yellow;warn=orange;error=red` to set the colors that you would like to use. You can also set `NO_COLOR` to disable colorized output.
> `buildctl` has support for modifying the colors that are used to output information to the terminal. You can set the environment variable `BUILDKIT_COLORS` to something like `run=blue;cancel=yellow;warn=orange;error=123,12,0` to set the colors that you would like to use. You can also set `NO_COLOR` to disable colorized output.
>
> - [A list of the supported colors](https://github.com/moby/buildkit/blob/master/util/progress/progressui/colors.go).
> Parsing errors will be reported, but ignored. This will result in default color values being used where needed.
>
> - [The list of pre-defined colors](https://github.com/moby/buildkit/blob/master/util/progress/progressui/colors.go).
#### Image/Registry

Expand Down
123 changes: 103 additions & 20 deletions util/progress/progressui/colors.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package progressui

import (
"fmt"
"regexp"
"encoding/csv"
"strconv"
"strings"

"github.com/morikuni/aec"
"github.com/sirupsen/logrus"
)

var rex = regexp.MustCompile(`(\w+)=(\w+)`)

var termColorMap = map[string]aec.ANSI{
"default": aec.DefaultF,

Expand All @@ -35,25 +34,109 @@ var termColorMap = map[string]aec.ANSI{
}

func setUserDefinedTermColors(colorsEnv string) {
data := rex.FindAllStringSubmatch(colorsEnv, -1)
for _, kv := range data {
k := kv[1]
v := kv[2]
// debug
fmt.Print(k, "=", v)
fields := readBuildkitColorsEnv(colorsEnv)
if fields == nil {
return
}
for _, field := range fields {
parts := strings.SplitN(field, "=", 2)
if len(parts) != 2 {
logrus.Warnf("Could not parse BUILDKIT_COLORS component: %s", strings.Join(parts, "="))
continue
}
if strings.Contains(parts[1], "=") {
logrus.Warnf("Could not parse BUILDKIT_COLORS component: %s", strings.Join(parts, "="))
continue
}
k := strings.ToLower(parts[0])
v := parts[1]
c, ok := termColorMap[strings.ToLower(v)]
if ok {
key := strings.ToLower(k)
switch key {
case "run":
colorRun = c
case "cancel":
colorCancel = c
case "error":
colorError = c
case "warning":
colorWarning = c
parseKeys(k, c)
} else {
if strings.Contains(v, ",") {
rgbFields := readRGB(v)
if rgbFields == nil {
continue
}
ok = isValidRGB(rgbFields)
if ok {
p1, _ := strconv.Atoi(rgbFields[0])
p2, _ := strconv.Atoi(rgbFields[1])
p3, _ := strconv.Atoi(rgbFields[2])
c = aec.Color8BitF(aec.NewRGB8Bit(uint8(p1), uint8(p2), uint8(p3)))
parseKeys(k, c)
}
} else {
logrus.Warnf("Unknown color value found in BUILDKIT_COLORS: %s=%s", k, v)
}
}
}
}

func readBuildkitColorsEnv(colorsEnv string) []string {
csvReader := csv.NewReader(strings.NewReader(colorsEnv))
csvReader.Comma = ':' // Use colon instead of comma
fields, err := csvReader.Read()
if err != nil {
logrus.WithError(err).Warnf("Could not parse BUILDKIT_COLORS. Falling back to defaults.")
return nil
}
return fields
}

func readRGB(v string) []string {
csvReader := csv.NewReader(strings.NewReader(v))
csvReader.Comma = ',' // Use colon instead of comma
fields, err := csvReader.Read()
if err != nil {
logrus.WithError(err).Warnf("Could not parse value %s as valid RGB color. Ignoring.", v)
return nil
}
if len(fields) != 3 {
logrus.Warnf("Could not parse value %s as valid RGB color. Ignoring.", v)
return nil
}
return fields
}

func parseKeys(k string, c aec.ANSI) {
key := strings.ToLower(k)
switch key {
case "run":
colorRun = c
case "cancel":
colorCancel = c
case "error":
colorError = c
case "warning":
colorWarning = c
default:
logrus.Warnf("Unknown key found in BUILDKIT_COLORS (expected: run, cancel, error, or warning): %s", k)
}
}

func isValidRGB(s []string) bool {
for _, n := range s {
num, err := strconv.Atoi(n)
if err != nil {
logrus.Warnf("A field in BUILDKIT_COLORS appears to contain an RGB value that is not an integer: %s", strings.Join(s, ","))
return false
}
ok := isValidRGBValue(num)
if ok {
continue
} else {
logrus.Warnf("A field in BUILDKIT_COLORS appears to contain an RGB value that is not within the valid range of 0-255: %s", strings.Join(s, ","))
return false
}
}
return true
}

func isValidRGBValue(i int) bool {
if (i >= 0) && (i <= 255) {
return true
}
return false
}

0 comments on commit 730fe40

Please sign in to comment.