Compare commits

..

2 Commits

Author SHA1 Message Date
Mark
d1aad0293a
Merge 6f90af1569 into e89001156a 2025-09-04 17:01:20 +02:00
mark.barzali
6f90af1569 feat: configure colors of output with env variables
Signed-off-by: mark.barzali <mark.barzali@heureka.group>
2025-09-01 10:54:50 +02:00
10 changed files with 82 additions and 93 deletions

View File

@ -438,7 +438,7 @@ You can customize the colors used in YAML output by setting these environment va
- `YQ_COLOR_STRING` - Color for string values (default: green) - `YQ_COLOR_STRING` - Color for string values (default: green)
- `YQ_COLOR_COMMENT` - Color for comments (default: hi-black) - `YQ_COLOR_COMMENT` - Color for comments (default: hi-black)
Supported color values: `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`, and their `hi-` prefixed variants (e.g., `hi-red`). Supported color values: `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`, and their `hi-` prefixed variants (e.g., `hi-red`). Numeric color codes are also supported.
Example: Example:
```bash ```bash

View File

@ -11,7 +11,7 @@ var (
GitDescribe string GitDescribe string
// Version is main version number that is being run at the moment. // Version is main version number that is being run at the moment.
Version = "v4.47.2" Version = "v4.47.1"
// VersionPrerelease is a pre-release marker for the version. If this is "" (empty string) // VersionPrerelease is a pre-release marker for the version. If this is "" (empty string)
// then it means that it is a final release. Otherwise, this is a pre-release // then it means that it is a final release. Otherwise, this is a pre-release

4
go.mod
View File

@ -14,8 +14,8 @@ require (
github.com/magiconair/properties v1.8.10 github.com/magiconair/properties v1.8.10
github.com/pelletier/go-toml/v2 v2.2.4 github.com/pelletier/go-toml/v2 v2.2.4
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e
github.com/spf13/cobra v1.10.1 github.com/spf13/cobra v1.9.1
github.com/spf13/pflag v1.0.10 github.com/spf13/pflag v1.0.7
github.com/yuin/gopher-lua v1.1.1 github.com/yuin/gopher-lua v1.1.1
go.yaml.in/yaml/v3 v3.0.4 go.yaml.in/yaml/v3 v3.0.4
golang.org/x/net v0.43.0 golang.org/x/net v0.43.0

10
go.sum
View File

@ -40,11 +40,11 @@ github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsK
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=

View File

@ -2,57 +2,78 @@ package yqlib
import ( import (
"fmt" "fmt"
"github.com/fatih/color"
"os" "os"
"strconv"
"github.com/fatih/color"
) )
type ColorConfig struct { type ColorConfig struct {
Bool color.Attribute BoolColor color.Attribute
Number color.Attribute NumberColor color.Attribute
MapKey color.Attribute MapKeyColor color.Attribute
Anchor color.Attribute AnchorColor color.Attribute
Alias color.Attribute AliasColor color.Attribute
String color.Attribute StringColor color.Attribute
Comment color.Attribute CommentColor color.Attribute
} }
func NewColorConfig() *ColorConfig { func NewColorConfig() *ColorConfig {
config := &ColorConfig{ config := &ColorConfig{
Bool: color.FgHiMagenta, BoolColor: color.FgHiMagenta,
Number: color.FgHiMagenta, NumberColor: color.FgHiMagenta,
MapKey: color.FgCyan, MapKeyColor: color.FgCyan,
Anchor: color.FgHiYellow, AnchorColor: color.FgHiYellow,
Alias: color.FgHiYellow, AliasColor: color.FgHiYellow,
String: color.FgGreen, StringColor: color.FgGreen,
Comment: color.FgHiBlack, CommentColor: color.FgHiBlack,
} }
colorMappings := map[string]*color.Attribute{ if colorStr := os.Getenv("YQ_COLOR_BOOL"); colorStr != "" {
"YQ_COLOR_BOOL": &config.Bool, if attr, err := parseColorAttribute(colorStr); err == nil {
"YQ_COLOR_NUMBER": &config.Number, config.BoolColor = attr
"YQ_COLOR_MAP_KEY": &config.MapKey, }
"YQ_COLOR_ANCHOR": &config.Anchor,
"YQ_COLOR_ALIAS": &config.Alias,
"YQ_COLOR_STRING": &config.String,
"YQ_COLOR_COMMENT": &config.Comment,
} }
for envVar, configField := range colorMappings { if colorStr := os.Getenv("YQ_COLOR_NUMBER"); colorStr != "" {
if colorStr := os.Getenv(envVar); colorStr != "" { if attr, err := parseColorAttribute(colorStr); err == nil {
if attr, err := parseColorAttribute(colorStr); err == nil { config.NumberColor = attr
*configField = attr }
} }
if colorStr := os.Getenv("YQ_COLOR_MAP_KEY"); colorStr != "" {
if attr, err := parseColorAttribute(colorStr); err == nil {
config.MapKeyColor = attr
}
}
if colorStr := os.Getenv("YQ_COLOR_ANCHOR"); colorStr != "" {
if attr, err := parseColorAttribute(colorStr); err == nil {
config.AnchorColor = attr
}
}
if colorStr := os.Getenv("YQ_COLOR_ALIAS"); colorStr != "" {
if attr, err := parseColorAttribute(colorStr); err == nil {
config.AliasColor = attr
}
}
if colorStr := os.Getenv("YQ_COLOR_STRING"); colorStr != "" {
if attr, err := parseColorAttribute(colorStr); err == nil {
config.StringColor = attr
}
}
if colorStr := os.Getenv("YQ_COLOR_COMMENT"); colorStr != "" {
if attr, err := parseColorAttribute(colorStr); err == nil {
config.CommentColor = attr
} }
} }
return config return config
} }
// parseColorAttribute converts a color string to a color.Attribute.
//
// Supports three types of color specifications:
// 1. Standard color names: "red", "green", "blue", "yellow", "magenta", "cyan", "white", "black"
// 2. High-intensity variants: "hi-red", "hi-green", "hi-blue", etc.
func parseColorAttribute(colorStr string) (color.Attribute, error) { func parseColorAttribute(colorStr string) (color.Attribute, error) {
switch colorStr { switch colorStr {
case "black": case "black":
@ -88,6 +109,9 @@ func parseColorAttribute(colorStr string) (color.Attribute, error) {
case "hi-white": case "hi-white":
return color.FgHiWhite, nil return color.FgHiWhite, nil
default: default:
if num, err := strconv.Atoi(colorStr); err == nil {
return color.Attribute(num), nil
}
return color.Reset, fmt.Errorf("unknown color: %s", colorStr) return color.Reset, fmt.Errorf("unknown color: %s", colorStr)
} }
} }

View File

@ -23,43 +23,43 @@ func colorizeAndPrint(yamlBytes []byte, writer io.Writer) error {
var p printer.Printer var p printer.Printer
p.Bool = func() *printer.Property { p.Bool = func() *printer.Property {
return &printer.Property{ return &printer.Property{
Prefix: format(config.Bool), Prefix: format(config.BoolColor),
Suffix: format(color.Reset), Suffix: format(color.Reset),
} }
} }
p.Number = func() *printer.Property { p.Number = func() *printer.Property {
return &printer.Property{ return &printer.Property{
Prefix: format(config.Number), Prefix: format(config.NumberColor),
Suffix: format(color.Reset), Suffix: format(color.Reset),
} }
} }
p.MapKey = func() *printer.Property { p.MapKey = func() *printer.Property {
return &printer.Property{ return &printer.Property{
Prefix: format(config.MapKey), Prefix: format(config.MapKeyColor),
Suffix: format(color.Reset), Suffix: format(color.Reset),
} }
} }
p.Anchor = func() *printer.Property { p.Anchor = func() *printer.Property {
return &printer.Property{ return &printer.Property{
Prefix: format(config.Anchor), Prefix: format(config.AnchorColor),
Suffix: format(color.Reset), Suffix: format(color.Reset),
} }
} }
p.Alias = func() *printer.Property { p.Alias = func() *printer.Property {
return &printer.Property{ return &printer.Property{
Prefix: format(config.Alias), Prefix: format(config.AliasColor),
Suffix: format(color.Reset), Suffix: format(color.Reset),
} }
} }
p.String = func() *printer.Property { p.String = func() *printer.Property {
return &printer.Property{ return &printer.Property{
Prefix: format(config.String), Prefix: format(config.StringColor),
Suffix: format(color.Reset), Suffix: format(color.Reset),
} }
} }
p.Comment = func() *printer.Property { p.Comment = func() *printer.Property {
return &printer.Property{ return &printer.Property{
Prefix: format(config.Comment), Prefix: format(config.CommentColor),
Suffix: format(color.Reset), Suffix: format(color.Reset),
} }
} }

View File

@ -282,13 +282,13 @@ func (dec *tomlDecoder) processTable(currentNode *toml.Node) (bool, error) {
tableValue = dec.parser.Expression() tableValue = dec.parser.Expression()
// next expression is not table data, so we are done // next expression is not table data, so we are done
if tableValue.Kind != toml.KeyValue { if tableValue.Kind != toml.KeyValue {
log.Debug("got an empty table") log.Debug("got an empty table, returning")
runAgainstCurrentExp = true return true, nil
} else { }
runAgainstCurrentExp, err = dec.decodeKeyValuesIntoMap(tableNodeValue, tableValue)
if err != nil && !errors.Is(err, io.EOF) { runAgainstCurrentExp, err = dec.decodeKeyValuesIntoMap(tableNodeValue, tableValue)
return false, err if err != nil && !errors.Is(err, io.EOF) {
} return false, err
} }
} }

View File

@ -23,7 +23,6 @@ street = "first street"
[owner] [owner]
name = "Tom Preston-Werner" name = "Tom Preston-Werner"
` `
var expectedTableArrayBeforeOwners = `owner: var expectedTableArrayBeforeOwners = `owner:
addresses: addresses:
- street: first street - street: first street
@ -68,29 +67,6 @@ var emptyTable = `
var emptyTableExpected = "dependencies: {}\n" var emptyTableExpected = "dependencies: {}\n"
var multipleEmptyTables = `
[firstEmptyTable]
[firstTableWithContent]
key = "value"
[secondEmptyTable]
[thirdEmptyTable]
[secondTableWithContent]
key = "value"
[fourthEmptyTable]
[fifthEmptyTable]
`
var expectedMultipleEmptyTables = `firstEmptyTable: {}
firstTableWithContent:
key: value
secondEmptyTable: {}
thirdEmptyTable: {}
secondTableWithContent:
key: value
fourthEmptyTable: {}
fifthEmptyTable: {}
`
var sampleWithHeader = ` var sampleWithHeader = `
[servers] [servers]
@ -262,13 +238,6 @@ var tomlScenarios = []formatScenario{
expected: expectedSampleWithHeader, expected: expectedSampleWithHeader,
scenarioType: "decode", scenarioType: "decode",
}, },
{
description: "Parse: multiple empty tables",
skipDoc: true,
input: multipleEmptyTables,
expected: expectedMultipleEmptyTables,
scenarioType: "decode",
},
} }
func testTomlScenario(t *testing.T, s formatScenario) { func testTomlScenario(t *testing.T, s formatScenario) {

View File

@ -1,7 +1,3 @@
4.47.2:
- Conversion from TOML to JSON no longer omits empty tables #2459 (thanks @louislouislouislouis)
- Bumped dependencies
4.47.1: 4.47.1:
- Fixed merge anchor behaviour (`<<`); #2404, #2110, #2386, #2178 Huge thanks to @stevenwdv! - Fixed merge anchor behaviour (`<<`); #2404, #2110, #2386, #2178 Huge thanks to @stevenwdv!
Note that you will need to set --yaml-fix-merge-anchor-to-spec to see the fixes Note that you will need to set --yaml-fix-merge-anchor-to-spec to see the fixes

View File

@ -1,5 +1,5 @@
name: yq name: yq
version: 'v4.47.2' version: 'v4.47.1'
summary: A lightweight and portable command-line data file processor summary: A lightweight and portable command-line data file processor
description: | description: |
`yq` uses [jq](https://github.com/stedolan/jq) like syntax but works with yaml, json, xml, csv, properties and TOML files. `yq` uses [jq](https://github.com/stedolan/jq) like syntax but works with yaml, json, xml, csv, properties and TOML files.
@ -27,6 +27,6 @@ parts:
build-environment: build-environment:
- CGO_ENABLED: 0 - CGO_ENABLED: 0
source: https://github.com/mikefarah/yq.git source: https://github.com/mikefarah/yq.git
source-tag: v4.47.2 source-tag: v4.47.1
build-snaps: build-snaps:
- go/latest/stable - go/latest/stable