Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.23.0
require (
github.com/cilium/stream v0.0.0-20240209152734-a0792b51812d
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/jmespath/go-jmespath v0.4.0
github.com/mitchellh/mapstructure v1.5.0
github.com/spf13/cast v1.6.0
github.com/spf13/cobra v1.8.0
Expand All @@ -13,8 +14,11 @@ require (
github.com/stretchr/testify v1.8.4
go.uber.org/dig v1.17.1
go.uber.org/goleak v1.3.0
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb
golang.org/x/sys v0.15.0
golang.org/x/term v0.15.0
golang.org/x/tools v0.16.0
sigs.k8s.io/yaml v1.6.0
)

require (
Expand All @@ -32,8 +36,7 @@ require (
github.com/spf13/afero v1.11.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // indirect
golang.org/x/sys v0.15.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
Expand Down
12 changes: 12 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
Expand Down Expand Up @@ -62,6 +66,10 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE=
go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI=
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8=
golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
Expand All @@ -79,6 +87,10 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
109 changes: 108 additions & 1 deletion script/cmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package script

import (
"encoding/json"
"errors"
"fmt"
"io/fs"
Expand All @@ -21,9 +22,12 @@ import (
"sync"
"time"

"github.com/cilium/hive/script/internal/diff"
"github.com/jmespath/go-jmespath"
"github.com/spf13/pflag"
"golang.org/x/term"
"sigs.k8s.io/yaml"

"github.com/cilium/hive/script/internal/diff"
)

// DefaultCmds returns a set of broadly useful script commands.
Expand Down Expand Up @@ -57,6 +61,8 @@ func DefaultCmds() map[string]Cmd {
"symlink": Symlink(),
"wait": Wait(),
"break": Break(),
"json": Json(),
"yaml": Yaml(),
}
}

Expand Down Expand Up @@ -1575,3 +1581,104 @@ func dirEntryIsExec(entry os.DirEntry) bool {
}
return info.Mode()&execAny != 0
}

func Json() Cmd {
return jsonOrYaml(false)
}

func Yaml() Cmd {
return jsonOrYaml(true)
}

func jsonOrYaml(yamlMode bool) Cmd {
which := "JSON"
if yamlMode {
which = "YAML"
}
return Command(
CmdUsage{
Summary: "Transform a "+which+" document with a JMESPath expression",
Args: "expression",
Detail: []string{
"See https://jmespath.org/tutorial.html for tutorial on JMESPath expressions.",
},
Flags: func(fs *pflag.FlagSet) {
fs.StringP("input", "i", "", "File to read from instead of stdout buffer")
fs.StringP("output", "o", "", "File to write to instead of stdout buffer")
fs.BoolP("quiet", "q", false, "Do not output the transformed document")
fs.BoolP("fail", "f", false, "Fail on null (no match)")
},
},
func(s *State, args ...string) (WaitFunc, error) {
if len(args) != 1 {
return nil, fmt.Errorf("%s: expected expression", ErrUsage)
}
expr := args[0]
return func(s *State) (stdout string, stderr string, err error) {
input := []byte(s.Stdout())
if inputFile, err := s.Flags.GetString("input"); err != nil {
return "", "", err
} else if inputFile != "" {
b, err := os.ReadFile(s.Path(inputFile))
if err != nil {
return "", "", err
}
input = b
}

if yamlMode {
input, err = yaml.YAMLToJSON(input)
if err != nil {
return "", "", err
}
}

var data any
if err := json.Unmarshal(input, &data); err != nil {
return "", "", err
}
result, err := jmespath.Search(expr, data)
if err != nil {
return "", "", err
}

if fail, err := s.Flags.GetBool("fail"); err != nil {
return "", "", err
} else if fail && result == nil {
return "", "", errors.New("No match")
}

if quiet, err := s.Flags.GetBool("quiet"); err != nil {
return "", "", err
} else if quiet {
return "", "", nil
}

var out []byte
if yamlMode {
out, err = yaml.Marshal(result)
if err != nil {
return "", "", err
}
} else {
out, err = json.Marshal(result)
if err != nil {
return "", "", err
}
}

if outputFile, err := s.Flags.GetString("output"); err != nil {
return "", "", err
} else if outputFile != "" {
err := os.WriteFile(s.Path(outputFile), out, 0644)
return "", "", err
}

return string(out), "", nil
}, nil

},
)
}


39 changes: 39 additions & 0 deletions script/scripttest/testdata/jmes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Tests for the json/yaml commands for transforming a JSON/YAML document using
# a JMESPath expression.

# stdout
echo '{"a": "b"}'
json a
stdout "b"

echo 'a: b'
yaml a
stdout b

# from input file
json -i test.json a
stdout ^{"aa":"foo"}$

json -i test.json a.aa
stdout "foo"

json -i test.json c[?v>`1`].v
stdout [2]

yaml -i test.yaml c[?v>`1`].v
stdout '\- 2'

# fail when no matches
! json --fail --input test.json 'c[2]'
! json --fail --input test.json 'd'

-- test.json --
{"a": {"aa": "foo"}, "b": 10, "c": [{"v": 1}, {"v": 2}]}

-- test.yaml --
a:
aa: foo
b: 10
c:
- v: 1
- v: 2