mirror of
https://github.com/taigrr/yq
synced 2025-01-18 04:53:17 -08:00
Compare commits
84 Commits
reduce
...
op-precend
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f91d30e46c | ||
|
|
07b053f040 | ||
|
|
35c97e832e | ||
|
|
8a5c47906e | ||
|
|
a366cacad3 | ||
|
|
7c8d3b9e70 | ||
|
|
ca10642e23 | ||
|
|
73518f3915 | ||
|
|
348ddb7a59 | ||
|
|
f46fe384bd | ||
|
|
071ec3c08c | ||
|
|
c2ed3a3e6d | ||
|
|
cc4c69bc89 | ||
|
|
917fd0eb6a | ||
|
|
b2056a2056 | ||
|
|
ba59201217 | ||
|
|
cfddee9101 | ||
|
|
1941bb66a5 | ||
|
|
29af9e4c63 | ||
|
|
af3a9ae846 | ||
|
|
5fb88627ca | ||
|
|
4fc3793fcb | ||
|
|
d612897e89 | ||
|
|
806f906041 | ||
|
|
e8b2f6e383 | ||
|
|
e419b5a39d | ||
|
|
a5b6e08282 | ||
|
|
2417c0ee8f | ||
|
|
d3b2e37b66 | ||
|
|
54723c1a36 | ||
|
|
0318c80d33 | ||
|
|
8980846632 | ||
|
|
0fb62d3ae1 | ||
|
|
85398727ad | ||
|
|
0bf3d781f6 | ||
|
|
5c15936bf3 | ||
|
|
b0735d8152 | ||
|
|
f17cbfd007 | ||
|
|
7b7ab70286 | ||
|
|
43165fa340 | ||
|
|
feda9f044d | ||
|
|
85629af59c | ||
|
|
5fc26e9453 | ||
|
|
07a6fa4df5 | ||
|
|
ec29ee7c14 | ||
|
|
24538c0cc7 | ||
|
|
61398bfd3a | ||
|
|
f7d95021c1 | ||
|
|
6bb8b1fb77 | ||
|
|
5e2c19cc86 | ||
|
|
30c269a66c | ||
|
|
70a1c60d7b | ||
|
|
e4d48bbc0d | ||
|
|
369ff94ad0 | ||
|
|
1c7fb14631 | ||
|
|
f4de5c4300 | ||
|
|
a72c14f06b | ||
|
|
5ed52aca66 | ||
|
|
5a5ac0dfef | ||
|
|
5a55869745 | ||
|
|
15e18bb98b | ||
|
|
644063646e | ||
|
|
aabed1a237 | ||
|
|
c12764dba8 | ||
|
|
1d5ecb244d | ||
|
|
7798a141cf | ||
|
|
b7583a538d | ||
|
|
529e88b630 | ||
|
|
658006eb93 | ||
|
|
2743a7e058 | ||
|
|
f95862fba3 | ||
|
|
3f58c4bc38 | ||
|
|
a7975df7cd | ||
|
|
3d5a5e0360 | ||
|
|
155755ae2f | ||
|
|
601c13531c | ||
|
|
69d00c89df | ||
|
|
2faff7b05f | ||
|
|
165949041d | ||
|
|
dbd7ab0f13 | ||
|
|
6d512ad718 | ||
|
|
4fef4a7ab1 | ||
|
|
dcb17b51a9 | ||
|
|
385417556d |
@@ -42,21 +42,14 @@ func evaluateAll(cmd *cobra.Command, args []string) error {
|
||||
colorsEnabled = true
|
||||
}
|
||||
|
||||
firstFileIndex := -1
|
||||
if !nullInput && len(args) == 1 {
|
||||
firstFileIndex = 0
|
||||
} else if len(args) > 1 {
|
||||
firstFileIndex = 1
|
||||
}
|
||||
|
||||
if writeInplace && (firstFileIndex == -1) {
|
||||
if writeInplace && len(args) < 2 {
|
||||
return fmt.Errorf("Write inplace flag only applicable when giving an expression and at least one file")
|
||||
}
|
||||
|
||||
if writeInplace {
|
||||
// only use colors if its forced
|
||||
colorsEnabled = forceColor
|
||||
writeInPlaceHandler := yqlib.NewWriteInPlaceHandler(args[firstFileIndex])
|
||||
writeInPlaceHandler := yqlib.NewWriteInPlaceHandler(args[1])
|
||||
out, err = writeInPlaceHandler.CreateTempFile()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -62,21 +62,14 @@ func evaluateSequence(cmd *cobra.Command, args []string) error {
|
||||
colorsEnabled = true
|
||||
}
|
||||
|
||||
firstFileIndex := -1
|
||||
if !nullInput && len(args) == 1 {
|
||||
firstFileIndex = 0
|
||||
} else if len(args) > 1 {
|
||||
firstFileIndex = 1
|
||||
}
|
||||
|
||||
if writeInplace && (firstFileIndex == -1) {
|
||||
if writeInplace && len(args) < 2 {
|
||||
return fmt.Errorf("Write inplace flag only applicable when giving an expression and at least one file")
|
||||
}
|
||||
|
||||
if writeInplace {
|
||||
// only use colors if its forced
|
||||
colorsEnabled = forceColor
|
||||
writeInPlaceHandler := yqlib.NewWriteInPlaceHandler(args[firstFileIndex])
|
||||
writeInPlaceHandler := yqlib.NewWriteInPlaceHandler(args[1])
|
||||
out, err = writeInPlaceHandler.CreateTempFile()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -109,7 +102,7 @@ func evaluateSequence(cmd *cobra.Command, args []string) error {
|
||||
err = streamEvaluator.EvaluateFiles(processExpression(""), []string{args[0]}, printer)
|
||||
}
|
||||
default:
|
||||
err = streamEvaluator.EvaluateFiles(processExpression(args[0]), args[1:], printer)
|
||||
err = streamEvaluator.EvaluateFiles(args[0], args[1:], printer)
|
||||
}
|
||||
completedSuccessfully = err == nil
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ var (
|
||||
GitDescribe string
|
||||
|
||||
// Version is main version number that is being run at the moment.
|
||||
Version = "4.5.1"
|
||||
Version = "4.4.1"
|
||||
|
||||
// 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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM mikefarah/yq:4.5.1
|
||||
FROM mikefarah/yq:4.4.1
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
|
||||
|
||||
8
go.mod
8
go.mod
@@ -1,14 +1,14 @@
|
||||
module github.com/mikefarah/yq/v4
|
||||
|
||||
require (
|
||||
github.com/elliotchance/orderedmap v1.4.0
|
||||
github.com/elliotchance/orderedmap v1.3.0
|
||||
github.com/fatih/color v1.10.0
|
||||
github.com/goccy/go-yaml v1.8.8
|
||||
github.com/jinzhu/copier v0.2.3
|
||||
github.com/goccy/go-yaml v1.8.4
|
||||
github.com/jinzhu/copier v0.1.0
|
||||
github.com/spf13/cobra v1.1.1
|
||||
github.com/timtadh/data-structures v0.5.3 // indirect
|
||||
github.com/timtadh/lexmachine v0.2.2
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
|
||||
golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 // indirect
|
||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
)
|
||||
|
||||
19
go.sum
19
go.sum
@@ -36,8 +36,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/elliotchance/orderedmap v1.4.0 h1:wZtfeEONCbx6in1CZyE6bELEt/vFayMvsxqI5SgsR+A=
|
||||
github.com/elliotchance/orderedmap v1.4.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys=
|
||||
github.com/elliotchance/orderedmap v1.3.0 h1:k6m77/d0zCXTjsk12nX40TkEBkSICq8T4s6R6bpCqU0=
|
||||
github.com/elliotchance/orderedmap v1.3.0/go.mod h1:8hdSl6jmveQw8ScByd3AaNHNk51RhbTazdqtTty+NFw=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
@@ -52,8 +52,8 @@ github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTM
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/goccy/go-yaml v1.8.8 h1:MGfRB1GeSn/hWXYWS2Pt67iC2GJNnebdIro01ddyucA=
|
||||
github.com/goccy/go-yaml v1.8.8/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
|
||||
github.com/goccy/go-yaml v1.8.4 h1:AOEdR7aQgbgwHznGe3BLkDQVujxCPUpHOZZcQcp8Y3M=
|
||||
github.com/goccy/go-yaml v1.8.4/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
@@ -101,8 +101,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jinzhu/copier v0.2.3 h1:Oe09ju+9qft7TffZ7l/04AB2f8u1+V4ZMxmp/nnqeOs=
|
||||
github.com/jinzhu/copier v0.2.3/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro=
|
||||
github.com/jinzhu/copier v0.1.0 h1:Vh8xALtH3rrKGB/XIRe5d0yCTHPZFauWPLvdpDAbi88=
|
||||
github.com/jinzhu/copier v0.1.0/go.mod h1:24xnZezI2Yqac9J61UC6/dG/k76ttpq0DdJI3QmUvro=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
@@ -182,8 +182,6 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/timtadh/data-structures v0.5.3 h1:F2tEjoG9qWIyUjbvXVgJqEOGJPMIiYn7U5W5mE+i/vQ=
|
||||
github.com/timtadh/data-structures v0.5.3/go.mod h1:9R4XODhJ8JdWFEI8P/HJKqxuJctfBQw6fDibMQny2oU=
|
||||
@@ -259,8 +257,8 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210105210732-16f7687f5001 h1:/dSxr6gT0FNI1MO5WLJo8mTmItROeOKTkDn+7OwWBos=
|
||||
golang.org/x/sys v0.0.0-20210105210732-16f7687f5001/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
@@ -326,7 +324,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
@@ -2,6 +2,8 @@ package yqlib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
@@ -16,15 +18,10 @@ type CandidateNode struct {
|
||||
// when performing op against all nodes given, this will treat all the nodes as one
|
||||
// (e.g. top level cross document merge). This property does not propegate to child nodes.
|
||||
EvaluateTogether bool
|
||||
IsMapKey bool
|
||||
}
|
||||
|
||||
func (n *CandidateNode) GetKey() string {
|
||||
keyPrefix := ""
|
||||
if n.IsMapKey {
|
||||
keyPrefix = "key-"
|
||||
}
|
||||
return fmt.Sprintf("%v%v - %v", keyPrefix, n.Document, n.Path)
|
||||
return fmt.Sprintf("%v - %v", n.Document, n.Path)
|
||||
}
|
||||
|
||||
func (n *CandidateNode) CreateChild(path interface{}, node *yaml.Node) *CandidateNode {
|
||||
@@ -66,10 +63,11 @@ func (n *CandidateNode) UpdateFrom(other *CandidateNode) {
|
||||
n.UpdateAttributesFrom(other)
|
||||
n.Node.Content = other.Node.Content
|
||||
n.Node.Value = other.Node.Value
|
||||
n.Node.Alias = other.Node.Alias
|
||||
n.Node.Anchor = other.Node.Anchor
|
||||
}
|
||||
|
||||
func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode) {
|
||||
log.Debug("UpdateAttributesFrom: n: %v other: %v", n.GetKey(), other.GetKey())
|
||||
if n.Node.Kind != other.Node.Kind {
|
||||
// clear out the contents when switching to a different type
|
||||
// e.g. map to array
|
||||
@@ -78,8 +76,6 @@ func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode) {
|
||||
}
|
||||
n.Node.Kind = other.Node.Kind
|
||||
n.Node.Tag = other.Node.Tag
|
||||
n.Node.Alias = other.Node.Alias
|
||||
n.Node.Anchor = other.Node.Anchor
|
||||
|
||||
// merge will pickup the style of the new thing
|
||||
// when autocreating nodes
|
||||
@@ -90,3 +86,46 @@ func (n *CandidateNode) UpdateAttributesFrom(other *CandidateNode) {
|
||||
n.Node.HeadComment = n.Node.HeadComment + other.Node.HeadComment
|
||||
n.Node.LineComment = n.Node.LineComment + other.Node.LineComment
|
||||
}
|
||||
|
||||
func (n *CandidateNode) PathStackToString() string {
|
||||
return mergePathStackToString(n.Path)
|
||||
}
|
||||
|
||||
func mergePathStackToString(pathStack []interface{}) string {
|
||||
var sb strings.Builder
|
||||
for index, path := range pathStack {
|
||||
switch path.(type) {
|
||||
case int, int64:
|
||||
// if arrayMergeStrategy == AppendArrayMergeStrategy {
|
||||
// sb.WriteString("[+]")
|
||||
// } else {
|
||||
sb.WriteString(fmt.Sprintf("[%v]", path))
|
||||
// }
|
||||
|
||||
default:
|
||||
s := fmt.Sprintf("%v", path)
|
||||
var _, errParsingInt = strconv.ParseInt(s, 10, 64) // nolint
|
||||
|
||||
hasSpecial := strings.Contains(s, ".") || strings.Contains(s, "[") || strings.Contains(s, "]") || strings.Contains(s, "\"")
|
||||
hasDoubleQuotes := strings.Contains(s, "\"")
|
||||
wrappingCharacterStart := "\""
|
||||
wrappingCharacterEnd := "\""
|
||||
if hasDoubleQuotes {
|
||||
wrappingCharacterStart = "("
|
||||
wrappingCharacterEnd = ")"
|
||||
}
|
||||
if hasSpecial || errParsingInt == nil {
|
||||
sb.WriteString(wrappingCharacterStart)
|
||||
}
|
||||
sb.WriteString(s)
|
||||
if hasSpecial || errParsingInt == nil {
|
||||
sb.WriteString(wrappingCharacterEnd)
|
||||
}
|
||||
}
|
||||
|
||||
if index < len(pathStack)-1 {
|
||||
sb.WriteString(".")
|
||||
}
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
@@ -42,13 +42,3 @@ func (n *Context) ChildContext(results *list.List) Context {
|
||||
clone.MatchingNodes = results
|
||||
return clone
|
||||
}
|
||||
|
||||
func (n *Context) Clone() Context {
|
||||
clone := Context{}
|
||||
err := copier.Copy(&clone, n)
|
||||
if err != nil {
|
||||
log.Error("Error cloning context :(")
|
||||
panic(err)
|
||||
}
|
||||
return clone
|
||||
}
|
||||
|
||||
@@ -29,24 +29,6 @@ true
|
||||
false
|
||||
```
|
||||
|
||||
## Don't match string
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- cat
|
||||
- goat
|
||||
- dog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] | (. != "*at")' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
false
|
||||
false
|
||||
true
|
||||
```
|
||||
|
||||
## Match number
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -65,24 +47,6 @@ true
|
||||
false
|
||||
```
|
||||
|
||||
## Dont match number
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- 3
|
||||
- 4
|
||||
- 5
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] | (. != 4)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
true
|
||||
false
|
||||
true
|
||||
```
|
||||
|
||||
## Match nulls
|
||||
Running
|
||||
```bash
|
||||
|
||||
@@ -71,6 +71,7 @@ Given a sample.yml file of:
|
||||
a: {things: great}
|
||||
b:
|
||||
also: "me"
|
||||
|
||||
```
|
||||
then
|
||||
```bash
|
||||
|
||||
@@ -33,7 +33,7 @@ c: banana
|
||||
```
|
||||
|
||||
## Special characters
|
||||
Use quotes with brackets around path elements with special characters
|
||||
Use quotes around path elements with special characters
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@@ -41,23 +41,7 @@ Given a sample.yml file of:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.["{}"]' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
frog
|
||||
```
|
||||
|
||||
## Keys with spaces
|
||||
Use quotes with brackets around path elements with special characters
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
"red rabbit": frog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.["red rabbit"]' sample.yml
|
||||
yq eval '."{}"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
@@ -1,58 +0,0 @@
|
||||
For more complex scenarios, variables can be used to hold values of expression to be used in other expressions.
|
||||
|
||||
## Single value variable
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a as $foo | $foo' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
cat
|
||||
```
|
||||
|
||||
## Multi value variable
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
- cat
|
||||
- dog
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.[] as $foo | $foo' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
cat
|
||||
dog
|
||||
```
|
||||
|
||||
## Using variables as a lookup
|
||||
Example taken from [jq](https://stedolan.github.io/jq/manual/#Variable/SymbolicBindingOperator:...as$identifier|...)
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
"posts":
|
||||
- "title": Frist psot
|
||||
"author": anon
|
||||
- "title": A well-written article
|
||||
"author": person1
|
||||
"realnames":
|
||||
"anon": Anonymous Coward
|
||||
"person1": Person McPherson
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.realnames as $names | .posts[] | {"title":.title, "author": $names[.author]}' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
title: Frist psot
|
||||
author: Anonymous Coward
|
||||
title: A well-written article
|
||||
author: Person McPherson
|
||||
```
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
For more complex scenarios, variables can be used to hold values of expression to be used in other expressions.
|
||||
@@ -12,11 +12,6 @@ var pathTests = []struct {
|
||||
expectedTokens []interface{}
|
||||
expectedPostFix []interface{}
|
||||
}{
|
||||
{
|
||||
`.a as $item ireduce (0; . + $item)`, // note - add code to shuffle reduce to this position for postfix
|
||||
append(make([]interface{}, 0), "a", "ASSIGN_VARIABLE", "GET_VARIABLE", "REDUCE", "(", "0 (int64)", "BLOCK", "SELF", "ADD", "GET_VARIABLE", ")"),
|
||||
append(make([]interface{}, 0), "a", "GET_VARIABLE", "ASSIGN_VARIABLE", "0 (int64)", "SELF", "GET_VARIABLE", "ADD", "BLOCK", "REDUCE"),
|
||||
},
|
||||
{
|
||||
`.a | .b | .c`,
|
||||
append(make([]interface{}, 0), "a", "PIPE", "b", "PIPE", "c"),
|
||||
|
||||
@@ -252,8 +252,6 @@ func initLexer() (*lex.Lexer, error) {
|
||||
lexer.Add([]byte(`or`), opToken(orOpType))
|
||||
lexer.Add([]byte(`and`), opToken(andOpType))
|
||||
lexer.Add([]byte(`not`), opToken(notOpType))
|
||||
lexer.Add([]byte(`ireduce`), opToken(reduceOpType))
|
||||
lexer.Add([]byte(`;`), opToken(blockOpType))
|
||||
lexer.Add([]byte(`\/\/`), opToken(alternativeOpType))
|
||||
|
||||
lexer.Add([]byte(`documentIndex`), opToken(getDocumentIndexOpType))
|
||||
@@ -286,7 +284,6 @@ func initLexer() (*lex.Lexer, error) {
|
||||
lexer.Add([]byte(`collect`), opToken(collectOpType))
|
||||
|
||||
lexer.Add([]byte(`\s*==\s*`), opToken(equalsOpType))
|
||||
lexer.Add([]byte(`\s*!=\s*`), opToken(notEqualsOpType))
|
||||
lexer.Add([]byte(`\s*=\s*`), assignOpToken(false))
|
||||
|
||||
lexer.Add([]byte(`del`), opToken(deleteChildOpType))
|
||||
|
||||
@@ -25,9 +25,6 @@ type operationType struct {
|
||||
|
||||
var orOpType = &operationType{Type: "OR", NumArgs: 2, Precedence: 20, Handler: orOperator}
|
||||
var andOpType = &operationType{Type: "AND", NumArgs: 2, Precedence: 20, Handler: andOperator}
|
||||
var reduceOpType = &operationType{Type: "REDUCE", NumArgs: 2, Precedence: 5, Handler: reduceOperator}
|
||||
|
||||
var blockOpType = &operationType{Type: "BLOCK", Precedence: 10, NumArgs: 2, Handler: emptyOperator}
|
||||
|
||||
var unionOpType = &operationType{Type: "UNION", NumArgs: 2, Precedence: 10, Handler: unionOperator}
|
||||
|
||||
@@ -49,7 +46,6 @@ var addOpType = &operationType{Type: "ADD", NumArgs: 2, Precedence: 42, Handler:
|
||||
var alternativeOpType = &operationType{Type: "ALTERNATIVE", NumArgs: 2, Precedence: 42, Handler: alternativeOperator}
|
||||
|
||||
var equalsOpType = &operationType{Type: "EQUALS", NumArgs: 2, Precedence: 40, Handler: equalsOperator}
|
||||
var notEqualsOpType = &operationType{Type: "EQUALS", NumArgs: 2, Precedence: 40, Handler: notEqualsOperator}
|
||||
var createMapOpType = &operationType{Type: "CREATE_MAP", NumArgs: 2, Precedence: 40, Handler: createMapOperator}
|
||||
|
||||
var shortPipeOpType = &operationType{Type: "SHORT_PIPE", NumArgs: 2, Precedence: 45, Handler: pipeOperator}
|
||||
@@ -83,7 +79,7 @@ var selfReferenceOpType = &operationType{Type: "SELF", NumArgs: 0, Precedence: 5
|
||||
var valueOpType = &operationType{Type: "VALUE", NumArgs: 0, Precedence: 50, Handler: valueOperator}
|
||||
var envOpType = &operationType{Type: "ENV", NumArgs: 0, Precedence: 50, Handler: envOperator}
|
||||
var notOpType = &operationType{Type: "NOT", NumArgs: 0, Precedence: 50, Handler: notOperator}
|
||||
var emptyOpType = &operationType{Type: "EMPTY", Precedence: 50, Handler: emptyOperator}
|
||||
var emptyOpType = &operationType{Type: "EMPTY", NumArgs: 50, Handler: emptyOperator}
|
||||
|
||||
var recursiveDescentOpType = &operationType{Type: "RECURSIVE_DESCENT", NumArgs: 0, Precedence: 50, Handler: recursiveDescentOperator}
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ func assignUpdateOperator(d *dataTreeNavigator, context Context, expressionNode
|
||||
|
||||
// does not update content or values
|
||||
func assignAttributesOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||
log.Debug("getting lhs matching nodes for update")
|
||||
lhs, err := d.GetMatchingNodes(context, expressionNode.Lhs)
|
||||
if err != nil {
|
||||
return Context{}, err
|
||||
|
||||
@@ -7,32 +7,29 @@ import (
|
||||
)
|
||||
|
||||
func deleteChildOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||
contextToUse := context.Clone()
|
||||
contextToUse.DontAutoCreate = true
|
||||
nodesToDelete, err := d.GetMatchingNodes(contextToUse, expressionNode.Rhs)
|
||||
|
||||
nodesToDelete, err := d.GetMatchingNodes(context, expressionNode.Rhs)
|
||||
|
||||
if err != nil {
|
||||
return Context{}, err
|
||||
}
|
||||
//need to iterate backwards to ensure correct indices when deleting multiple
|
||||
for el := nodesToDelete.MatchingNodes.Back(); el != nil; el = el.Prev() {
|
||||
|
||||
for el := nodesToDelete.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
|
||||
if len(candidate.Path) > 0 {
|
||||
deleteImmediateChildOp := &Operation{
|
||||
OperationType: deleteImmediateChildOpType,
|
||||
Value: candidate.Path[len(candidate.Path)-1],
|
||||
}
|
||||
deleteImmediateChildOp := &Operation{
|
||||
OperationType: deleteImmediateChildOpType,
|
||||
Value: candidate.Path[len(candidate.Path)-1],
|
||||
}
|
||||
|
||||
deleteImmediateChildOpNode := &ExpressionNode{
|
||||
Operation: deleteImmediateChildOp,
|
||||
Rhs: createTraversalTree(candidate.Path[0:len(candidate.Path)-1], traversePreferences{}, false),
|
||||
}
|
||||
deleteImmediateChildOpNode := &ExpressionNode{
|
||||
Operation: deleteImmediateChildOp,
|
||||
Rhs: createTraversalTree(candidate.Path[0:len(candidate.Path)-1], traversePreferences{}),
|
||||
}
|
||||
|
||||
_, err := d.GetMatchingNodes(contextToUse, deleteImmediateChildOpNode)
|
||||
if err != nil {
|
||||
return Context{}, err
|
||||
}
|
||||
_, err := d.GetMatchingNodes(context, deleteImmediateChildOpNode)
|
||||
if err != nil {
|
||||
return Context{}, err
|
||||
}
|
||||
}
|
||||
return context, nil
|
||||
|
||||
@@ -37,38 +37,6 @@ var deleteOperatorScenarios = []expressionScenario{
|
||||
"D0, P[], (doc)::[1, 3]\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `a: [1,2,3]`,
|
||||
expression: `del(.a[])`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::a: []\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `a: [10,x,10, 10, x, 10]`,
|
||||
expression: `del(.a[] | select(. == 10))`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::a: [x, x]\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `a: {thing1: yep, thing2: cool, thing3: hi, b: {thing1: cool, great: huh}}`,
|
||||
expression: `del(..)`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `a: {thing1: yep, thing2: cool, thing3: hi, b: {thing1: cool, great: huh}}`,
|
||||
expression: `del(.. | select(tag == "!!map") | (.b.thing1,.thing2))`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::a: {thing1: yep, thing3: hi, b: {great: huh}}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Delete nested entry in array",
|
||||
document: `[{a: cat, b: dog}]`,
|
||||
|
||||
@@ -1,33 +1,21 @@
|
||||
package yqlib
|
||||
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
func equalsOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||
log.Debugf("-- equalsOperation")
|
||||
return crossFunction(d, context, expressionNode, isEquals(false))
|
||||
return crossFunction(d, context, expressionNode, isEquals)
|
||||
}
|
||||
|
||||
func isEquals(flip bool) func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||
return func(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||
value := false
|
||||
func isEquals(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
|
||||
value := false
|
||||
|
||||
lhsNode := unwrapDoc(lhs.Node)
|
||||
rhsNode := unwrapDoc(rhs.Node)
|
||||
lhsNode := unwrapDoc(lhs.Node)
|
||||
rhsNode := unwrapDoc(rhs.Node)
|
||||
|
||||
if lhsNode.Tag == "!!null" {
|
||||
value = (rhsNode.Tag == "!!null")
|
||||
} else if lhsNode.Kind == yaml.ScalarNode && rhsNode.Kind == yaml.ScalarNode {
|
||||
value = matchKey(lhsNode.Value, rhsNode.Value)
|
||||
}
|
||||
log.Debugf("%v == %v ? %v", NodeToString(lhs), NodeToString(rhs), value)
|
||||
if flip {
|
||||
value = !value
|
||||
}
|
||||
return createBooleanCandidate(lhs, value), nil
|
||||
if lhsNode.Tag == "!!null" {
|
||||
value = (rhsNode.Tag == "!!null")
|
||||
} else {
|
||||
value = matchKey(lhsNode.Value, rhsNode.Value)
|
||||
}
|
||||
}
|
||||
|
||||
func notEqualsOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||
log.Debugf("-- equalsOperation")
|
||||
return crossFunction(d, context, expressionNode, isEquals(true))
|
||||
log.Debugf("%v == %v ? %v", NodeToString(lhs), NodeToString(rhs), value)
|
||||
return createBooleanCandidate(lhs, value), nil
|
||||
}
|
||||
|
||||
@@ -14,14 +14,6 @@ var equalsOperatorScenarios = []expressionScenario{
|
||||
"D0, P[], (!!bool)::false\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: "{a: { b: {things: \"\"}, f: [1], g: [] }}",
|
||||
expression: ".. | select(. == \"\")",
|
||||
expected: []string{
|
||||
"D0, P[a b things], (!!str)::\"\"\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Match string",
|
||||
document: `[cat,goat,dog]`,
|
||||
@@ -31,18 +23,7 @@ var equalsOperatorScenarios = []expressionScenario{
|
||||
"D0, P[1], (!!bool)::true\n",
|
||||
"D0, P[2], (!!bool)::false\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Don't match string",
|
||||
document: `[cat,goat,dog]`,
|
||||
expression: `.[] | (. != "*at")`,
|
||||
expected: []string{
|
||||
"D0, P[0], (!!bool)::false\n",
|
||||
"D0, P[1], (!!bool)::false\n",
|
||||
"D0, P[2], (!!bool)::true\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
}, {
|
||||
description: "Match number",
|
||||
document: `[3, 4, 5]`,
|
||||
expression: `.[] | (. == 4)`,
|
||||
@@ -51,18 +32,7 @@ var equalsOperatorScenarios = []expressionScenario{
|
||||
"D0, P[1], (!!bool)::true\n",
|
||||
"D0, P[2], (!!bool)::false\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Dont match number",
|
||||
document: `[3, 4, 5]`,
|
||||
expression: `.[] | (. != 4)`,
|
||||
expected: []string{
|
||||
"D0, P[0], (!!bool)::true\n",
|
||||
"D0, P[1], (!!bool)::false\n",
|
||||
"D0, P[2], (!!bool)::true\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
}, {
|
||||
skipDoc: true,
|
||||
document: `a: { cat: {b: apple, c: whatever}, pat: {b: banana} }`,
|
||||
expression: `.a | (.[].b == "apple")`,
|
||||
|
||||
@@ -66,7 +66,7 @@ func mergeObjects(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs
|
||||
|
||||
// shouldn't recurse arrays if appending
|
||||
prefs := recursiveDescentPreferences{RecurseArray: !shouldAppendArrays,
|
||||
TraversePreferences: traversePreferences{DontFollowAlias: true, IncludeMapKeys: true}}
|
||||
TraversePreferences: traversePreferences{DontFollowAlias: true}}
|
||||
err := recursiveDecent(d, results, context.SingleChildContext(rhs), prefs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -78,12 +78,7 @@ func mergeObjects(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs
|
||||
}
|
||||
|
||||
for el := results.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
if candidate.Node.Tag == "!!merge" {
|
||||
continue
|
||||
}
|
||||
|
||||
err := applyAssignment(d, context, pathIndexToStartFrom, lhs, candidate, preferences)
|
||||
err := applyAssignment(d, context, pathIndexToStartFrom, lhs, el.Value.(*CandidateNode), preferences)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -93,7 +88,7 @@ func mergeObjects(d *dataTreeNavigator, context Context, lhs *CandidateNode, rhs
|
||||
|
||||
func applyAssignment(d *dataTreeNavigator, context Context, pathIndexToStartFrom int, lhs *CandidateNode, rhs *CandidateNode, preferences multiplyPreferences) error {
|
||||
shouldAppendArrays := preferences.AppendArrays
|
||||
log.Debugf("merge - applyAssignment lhs %v, rhs: %v", lhs.GetKey(), rhs.GetKey())
|
||||
log.Debugf("merge - applyAssignment lhs %v, rhs: %v", NodeToString(lhs), NodeToString(rhs))
|
||||
|
||||
lhsPath := rhs.Path[pathIndexToStartFrom:]
|
||||
|
||||
@@ -106,7 +101,7 @@ func applyAssignment(d *dataTreeNavigator, context Context, pathIndexToStartFrom
|
||||
}
|
||||
rhsOp := &Operation{OperationType: valueOpType, CandidateNode: rhs}
|
||||
|
||||
assignmentOpNode := &ExpressionNode{Operation: assignmentOp, Lhs: createTraversalTree(lhsPath, preferences.TraversePrefs, rhs.IsMapKey), Rhs: &ExpressionNode{Operation: rhsOp}}
|
||||
assignmentOpNode := &ExpressionNode{Operation: assignmentOp, Lhs: createTraversalTree(lhsPath, preferences.TraversePrefs), Rhs: &ExpressionNode{Operation: rhsOp}}
|
||||
|
||||
_, err := d.GetMatchingNodes(context.SingleChildContext(lhs), assignmentOpNode)
|
||||
|
||||
|
||||
@@ -13,30 +13,6 @@ var multiplyOperatorScenarios = []expressionScenario{
|
||||
"D0, P[], (!!map)::{a: {also: me}, b: {also: me}}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: "# b\nb:\n # a\n a: cat",
|
||||
expression: "{} * .",
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::# b\nb:\n # a\n a: cat\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: "# b\nb:\n # a\n a: cat",
|
||||
expression: ". * {}",
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::# b\nb:\n # a\n a: cat\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `{a: &a { b: &b { c: &c cat } } }`,
|
||||
expression: `{} * .`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: &a {b: &b {c: &c cat}}}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `{a: 2, b: 5}`,
|
||||
@@ -116,7 +92,7 @@ var multiplyOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `{a: {things: great}, b: {also: me}}`,
|
||||
expression: `. * {"a": .b}`,
|
||||
expression: `. * {"a":.b}`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::{a: {things: great, also: me}, b: {also: me}}\n",
|
||||
},
|
||||
@@ -124,10 +100,16 @@ var multiplyOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
description: "Merge keeps style of LHS",
|
||||
dontFormatInputForDoc: true,
|
||||
document: "a: {things: great}\nb:\n also: \"me\"",
|
||||
expression: `. * {"a":.b}`,
|
||||
document: `a: {things: great}
|
||||
b:
|
||||
also: "me"
|
||||
`,
|
||||
expression: `. * {"a":.b}`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::a: {things: great, also: \"me\"}\nb:\n also: \"me\"\n",
|
||||
`D0, P[], (!!map)::a: {things: great, also: "me"}
|
||||
b:
|
||||
also: "me"
|
||||
`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func reduceOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) {
|
||||
log.Debugf("-- reduceOp")
|
||||
//.a as $var reduce (0; . + $var)
|
||||
//lhs is the assignment operator
|
||||
//rhs is the reduce block
|
||||
// '.' refers to the current accumulator, initialised to 0
|
||||
// $var references a single element from the .a
|
||||
|
||||
//ensure lhs is actually an assignment
|
||||
//and rhs is a block (empty)
|
||||
if expressionNode.Lhs.Operation.OperationType != assignVariableOpType {
|
||||
return Context{}, fmt.Errorf("reduce must be given a variables assignment, got %v instead", expressionNode.Lhs.Operation.OperationType.Type)
|
||||
} else if expressionNode.Rhs.Operation.OperationType != blockOpType {
|
||||
return Context{}, fmt.Errorf("reduce must be given a block, got %v instead", expressionNode.Rhs.Operation.OperationType.Type)
|
||||
}
|
||||
|
||||
arrayExpNode := expressionNode.Lhs.Lhs
|
||||
array, err := d.GetMatchingNodes(context, arrayExpNode)
|
||||
|
||||
log.Debugf("array of %v things", array.MatchingNodes.Len())
|
||||
|
||||
if err != nil {
|
||||
return Context{}, err
|
||||
}
|
||||
|
||||
variableName := expressionNode.Lhs.Rhs.Operation.StringValue
|
||||
|
||||
initExp := expressionNode.Rhs.Lhs
|
||||
|
||||
accum, err := d.GetMatchingNodes(context, initExp)
|
||||
if err != nil {
|
||||
return Context{}, err
|
||||
}
|
||||
|
||||
log.Debugf("with variable %v", variableName)
|
||||
|
||||
blockExp := expressionNode.Rhs.Rhs
|
||||
for el := array.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
log.Debugf("REDUCING WITH %v", NodeToString(candidate))
|
||||
l := list.New()
|
||||
l.PushBack(candidate)
|
||||
accum.SetVariable(variableName, l)
|
||||
|
||||
accum, err = d.GetMatchingNodes(accum, blockExp)
|
||||
if err != nil {
|
||||
return Context{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return accum, nil
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var reduceOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
document: `[10,2, 5, 3]`,
|
||||
expression: `.[] as $item ireduce (0; . + $item)`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!int)::20\n",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestReduceOperatorScenarios(t *testing.T) {
|
||||
for _, tt := range reduceOperatorScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
// documentScenarios(t, "Reduce", reduceOperatorScenarios)
|
||||
}
|
||||
@@ -10,10 +10,9 @@ import (
|
||||
)
|
||||
|
||||
type traversePreferences struct {
|
||||
DontFollowAlias bool
|
||||
IncludeMapKeys bool
|
||||
DontAutoCreate bool // by default, we automatically create entries on the fly.
|
||||
DontIncludeMapValues bool
|
||||
DontFollowAlias bool
|
||||
IncludeMapKeys bool
|
||||
DontAutoCreate bool // by default, we automatically create entries on the fly.
|
||||
}
|
||||
|
||||
func splat(d *dataTreeNavigator, context Context, prefs traversePreferences) (Context, error) {
|
||||
@@ -215,21 +214,10 @@ func traverseMap(context Context, matchingNode *CandidateNode, key string, prefs
|
||||
if !prefs.DontAutoCreate && !context.DontAutoCreate && newMatches.Len() == 0 {
|
||||
//no matches, create one automagically
|
||||
valueNode := &yaml.Node{Tag: "!!null", Kind: yaml.ScalarNode, Value: "null"}
|
||||
keyNode := &yaml.Node{Kind: yaml.ScalarNode, Value: key}
|
||||
node := matchingNode.Node
|
||||
node.Content = append(node.Content, keyNode, valueNode)
|
||||
|
||||
if prefs.IncludeMapKeys {
|
||||
log.Debug("including key")
|
||||
candidateNode := matchingNode.CreateChild(key, keyNode)
|
||||
candidateNode.IsMapKey = true
|
||||
newMatches.Set(fmt.Sprintf("keyOf-%v", candidateNode.GetKey()), candidateNode)
|
||||
}
|
||||
if !prefs.DontIncludeMapValues {
|
||||
log.Debug("including value")
|
||||
candidateNode := matchingNode.CreateChild(key, valueNode)
|
||||
newMatches.Set(candidateNode.GetKey(), candidateNode)
|
||||
}
|
||||
node.Content = append(node.Content, &yaml.Node{Kind: yaml.ScalarNode, Value: key}, valueNode)
|
||||
candidateNode := matchingNode.CreateChild(key, valueNode)
|
||||
newMatches.Set(candidateNode.GetKey(), candidateNode)
|
||||
}
|
||||
|
||||
results := list.New()
|
||||
@@ -265,16 +253,11 @@ func doTraverseMap(newMatches *orderedmap.OrderedMap, candidate *CandidateNode,
|
||||
} else if splat || keyMatches(key, wantedKey) {
|
||||
log.Debug("MATCHED")
|
||||
if prefs.IncludeMapKeys {
|
||||
log.Debug("including key")
|
||||
candidateNode := candidate.CreateChild(key.Value, key)
|
||||
candidateNode.IsMapKey = true
|
||||
newMatches.Set(fmt.Sprintf("keyOf-%v", candidateNode.GetKey()), candidateNode)
|
||||
}
|
||||
if !prefs.DontIncludeMapValues {
|
||||
log.Debug("including value")
|
||||
candidateNode := candidate.CreateChild(key.Value, value)
|
||||
newMatches.Set(candidateNode.GetKey(), candidateNode)
|
||||
}
|
||||
candidateNode := candidate.CreateChild(key.Value, value)
|
||||
newMatches.Set(candidateNode.GetKey(), candidateNode)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,30 +47,13 @@ var traversePathOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
{
|
||||
description: "Special characters",
|
||||
subdescription: "Use quotes with brackets around path elements with special characters",
|
||||
subdescription: "Use quotes around path elements with special characters",
|
||||
document: `{"{}": frog}`,
|
||||
expression: `.["{}"]`,
|
||||
expression: `."{}"`,
|
||||
expected: []string{
|
||||
"D0, P[{}], (!!str)::frog\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Keys with spaces",
|
||||
subdescription: "Use quotes with brackets around path elements with special characters",
|
||||
document: `{"red rabbit": frog}`,
|
||||
expression: `.["red rabbit"]`,
|
||||
expected: []string{
|
||||
"D0, P[red rabbit], (!!str)::frog\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
document: `{"flying fox": frog}`,
|
||||
expression: `.["flying fox"]`,
|
||||
expected: []string{
|
||||
"D0, P[flying fox], (!!str)::frog\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Dynamic keys",
|
||||
subdescription: `Expressions within [] can be used to dynamically lookup / calculate keys`,
|
||||
@@ -443,5 +426,5 @@ func TestTraversePathOperatorScenarios(t *testing.T) {
|
||||
for _, tt := range traversePathOperatorScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
documentScenarios(t, "Traverse (Read)", traversePathOperatorScenarios)
|
||||
documentScenarios(t, "Traverse", traversePathOperatorScenarios)
|
||||
}
|
||||
|
||||
@@ -23,8 +23,7 @@ var variableOperatorScenarios = []expressionScenario{
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Using variables as a lookup",
|
||||
subdescription: "Example taken from [jq](https://stedolan.github.io/jq/manual/#Variable/SymbolicBindingOperator:...as$identifier|...)",
|
||||
description: "Using variables as a lookup",
|
||||
document: `{"posts": [{"title": "Frist psot", "author": "anon"},
|
||||
{"title": "A well-written article", "author": "person1"}],
|
||||
"realnames": {"anon": "Anonymous Coward",
|
||||
@@ -41,5 +40,4 @@ func TestVariableOperatorScenarios(t *testing.T) {
|
||||
for _, tt := range variableOperatorScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
documentScenarios(t, "Variable Operators", variableOperatorScenarios)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
@@ -89,25 +88,16 @@ func createBooleanCandidate(owner *CandidateNode, value bool) *CandidateNode {
|
||||
return owner.CreateChild(nil, node)
|
||||
}
|
||||
|
||||
func createTraversalTree(path []interface{}, traversePrefs traversePreferences, targetKey bool) *ExpressionNode {
|
||||
func createTraversalTree(path []interface{}, traversePrefs traversePreferences) *ExpressionNode {
|
||||
if len(path) == 0 {
|
||||
return &ExpressionNode{Operation: &Operation{OperationType: selfReferenceOpType}}
|
||||
} else if len(path) == 1 {
|
||||
lastPrefs := traversePrefs
|
||||
if targetKey {
|
||||
err := copier.Copy(&lastPrefs, traversePrefs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
lastPrefs.IncludeMapKeys = true
|
||||
lastPrefs.DontIncludeMapValues = true
|
||||
}
|
||||
return &ExpressionNode{Operation: &Operation{OperationType: traversePathOpType, Preferences: lastPrefs, Value: path[0], StringValue: fmt.Sprintf("%v", path[0])}}
|
||||
return &ExpressionNode{Operation: &Operation{OperationType: traversePathOpType, Preferences: traversePrefs, Value: path[0], StringValue: fmt.Sprintf("%v", path[0])}}
|
||||
}
|
||||
|
||||
return &ExpressionNode{
|
||||
Operation: &Operation{OperationType: shortPipeOpType},
|
||||
Lhs: createTraversalTree(path[0:1], traversePrefs, false),
|
||||
Rhs: createTraversalTree(path[1:], traversePrefs, targetKey),
|
||||
Lhs: createTraversalTree(path[0:1], traversePrefs),
|
||||
Rhs: createTraversalTree(path[1:], traversePrefs),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
- increment version in snapcraft.yaml
|
||||
- increment version in github-action/Dockerfile
|
||||
- make sure local build passes
|
||||
- commit version update changes
|
||||
- tag git with same version number
|
||||
- commit vX tag - this will trigger github actions
|
||||
- use github actions to publish docker and make github release
|
||||
- check github updated yq action in marketplace
|
||||
|
||||
|
||||
- snapcraft
|
||||
- will auto create a candidate, test it works then promote
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: yq
|
||||
version: '4.5.1'
|
||||
version: '4.4.1'
|
||||
summary: A lightweight and portable command-line YAML processor
|
||||
description: |
|
||||
The aim of the project is to be the jq or sed of yaml files.
|
||||
|
||||
BIN
yq_linux_amd64.tar.gz
Normal file
BIN
yq_linux_amd64.tar.gz
Normal file
Binary file not shown.
Reference in New Issue
Block a user