Merge remote-tracking branch 'source/master' into carolynvs-add-log-accessor

This commit is contained in:
Rob Ferguson 2021-11-29 11:17:26 -06:00
commit 39908ab5ae
22 changed files with 87 additions and 54 deletions

View File

@ -3,9 +3,11 @@ run:
linters: linters:
enable: enable:
- errorlint - errorlint
- gci
- gofmt - gofmt
- goimports - goimports
- gosec - gosec
- misspell
issues: issues:
exclude-rules: exclude-rules:
- linters: - linters:

1
1
View File

@ -1 +0,0 @@
Error: cannot pass files in when using null-input flag

View File

@ -220,6 +220,7 @@ Supported by @rmescandon (https://launchpad.net/~rmescandon/+archive/ubuntu/yq)
- [Update yaml inplace](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate#flags) - [Update yaml inplace](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate#flags)
- [Complex expressions to select and update](https://mikefarah.gitbook.io/yq/operators/select#select-and-update-matching-values-in-map) - [Complex expressions to select and update](https://mikefarah.gitbook.io/yq/operators/select#select-and-update-matching-values-in-map)
- Keeps yaml formatting and comments when updating (though there are issues with whitespace) - Keeps yaml formatting and comments when updating (though there are issues with whitespace)
- [Load content from other files](https://mikefarah.gitbook.io/yq/operators/load)
- [Convert to/from json](https://mikefarah.gitbook.io/yq/v/v4.x/usage/convert) - [Convert to/from json](https://mikefarah.gitbook.io/yq/v/v4.x/usage/convert)
- [Convert to properties](https://mikefarah.gitbook.io/yq/v/v4.x/usage/properties) - [Convert to properties](https://mikefarah.gitbook.io/yq/v/v4.x/usage/properties)
- [Pipe data in by using '-'](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate) - [Pipe data in by using '-'](https://mikefarah.gitbook.io/yq/v/v4.x/commands/evaluate)

View File

@ -25,7 +25,7 @@ func initCommand(cmd *cobra.Command, args []string) (firstFileIndex int, err err
firstFileIndex = 1 firstFileIndex = 1
} }
// backwards compatibilty // backwards compatibility
if outputToJSON { if outputToJSON {
outputFormat = "json" outputFormat = "json"
} }

1
go.sum
View File

@ -471,7 +471,6 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

8
merge-array-by-key.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
# ./yq ea '.[]' examples/data*.yaml
./yq ea '
((.[] | {.name: .}) as $item ireduce ({}; . * $item )) as $uniqueMap
| ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value)
' examples/data*.yaml

View File

@ -108,7 +108,7 @@ will output
a: frog a: frog
``` ```
## Two non existant keys are equal ## Two non existent keys are equal
Given a sample.yml file of: Given a sample.yml file of:
```yaml ```yaml
a: frog a: frog

View File

@ -234,23 +234,30 @@ will output
``` ```
## Merge arrays of objects together, matching on a key ## Merge arrays of objects together, matching on a key
It's a complex command, the trickyness comes from needing to have the right context in the expressions. There are several parts of the complex expression.
First we save the second array into a variable '$two' which lets us reference it later. The first part is doing the hard work, it creates a map from the arrays keyed by '.a', so that there are no duplicates.
We then need to update the first array. We will use the relative update (|=) because we need to update relative to the current element of the array in the LHS in the RHS expression. Then there's another reduce that converts that map back to an array.
We set the current element of the first array as $cur. Now we multiply (merge) $cur with the matching entry in $two, by passing $two through a select filter. Finally, we set the result of the merged array back into the first doc.
To use this, you will need to update '.myArray' to be the expression to your array (e.g. .my.array), and '.a' to be the key field of your array (e.g. '.name')
Thanks Kev from [stackoverflow](https://stackoverflow.com/a/70109529/1168223)
Given a sample.yml file of: Given a sample.yml file of:
```yaml ```yaml
myArray:
- a: apple - a: apple
b: appleB b: appleB
- a: kiwi - a: kiwi
b: kiwiB b: kiwiB
- a: banana - a: banana
b: bananaB b: bananaB
something: else
``` ```
And another sample another.yml file of: And another sample another.yml file of:
```yaml ```yaml
myArray:
- a: banana - a: banana
c: bananaC c: bananaC
- a: apple - a: apple
@ -260,10 +267,17 @@ And another sample another.yml file of:
``` ```
then then
```bash ```bash
yq eval-all '(select(fi==1) | .[]) as $two | select(fi==0) | .[] |= (. as $cur | $cur * ($two | select(.a == $cur.a)))' sample.yml another.yml yq eval-all '
(
((.myArray[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap
| ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value)
) as $mergedArray
| select(fi == 0) | .myArray = $mergedArray
' sample.yml another.yml
``` ```
will output will output
```yaml ```yaml
myArray:
- a: apple - a: apple
b: appleB2 b: appleB2
- a: kiwi - a: kiwi
@ -271,6 +285,9 @@ will output
- a: banana - a: banana
b: bananaB b: bananaB
c: bananaC c: bananaC
- a: dingo
c: dingoC
something: else
``` ```
## Merge to prefix an element ## Merge to prefix an element

View File

@ -209,7 +209,7 @@ will output
``` ```
## Test using regex ## Test using regex
Like jq'q equivalant, this works like match but only returns true/false instead of full match details Like jq'q equivalent, this works like match but only returns true/false instead of full match details
Given a sample.yml file of: Given a sample.yml file of:
```yaml ```yaml

View File

@ -68,7 +68,7 @@ func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Ope
} }
// now we should have [ as the last element on the opStack, get rid of it // now we should have [ as the last element on the opStack, get rid of it
opStack = opStack[0 : len(opStack)-1] opStack = opStack[0 : len(opStack)-1]
log.Debugf("deleteing open bracket from opstack") log.Debugf("deleting open bracket from opstack")
//and append a collect to the result //and append a collect to the result
// hack - see if there's the optional traverse flag // hack - see if there's the optional traverse flag

View File

@ -34,7 +34,7 @@ func tryRemoveFile(filename string) {
// thanks https://stackoverflow.com/questions/21060945/simple-way-to-copy-a-file-in-golang // thanks https://stackoverflow.com/questions/21060945/simple-way-to-copy-a-file-in-golang
func copyFileContents(src, dst string) (err error) { func copyFileContents(src, dst string) (err error) {
// ignore CWE-22 gosec issue - that's more targetted for http based apps that run in a public directory, // ignore CWE-22 gosec issue - that's more targeted for http based apps that run in a public directory,
// and ensuring that it's not possible to give a path to a file outside thar directory. // and ensuring that it's not possible to give a path to a file outside thar directory.
in, err := os.Open(src) // #nosec in, err := os.Open(src) // #nosec

View File

@ -2,7 +2,6 @@ package yqlib
import ( import (
"fmt" "fmt"
"strconv" "strconv"
yaml "gopkg.in/yaml.v3" yaml "gopkg.in/yaml.v3"

View File

@ -1,8 +1,6 @@
package yqlib package yqlib
import ( import (
// "bufio"
// "bytes"
"bufio" "bufio"
"bytes" "bytes"
"container/list" "container/list"

View File

@ -173,7 +173,7 @@ var equalsOperatorScenarios = []expressionScenario{
}, },
}, },
{ {
description: "Two non existant keys are equal", description: "Two non existent keys are equal",
document: "a: frog", document: "a: frog",
expression: `select(.b == .c)`, expression: `select(.b == .c)`,
expected: []string{ expected: []string{

View File

@ -15,7 +15,7 @@ type loadPrefs struct {
} }
func loadString(filename string) (*CandidateNode, error) { func loadString(filename string) (*CandidateNode, error) {
// ignore CWE-22 gosec issue - that's more targetted for http based apps that run in a public directory, // ignore CWE-22 gosec issue - that's more targeted for http based apps that run in a public directory,
// and ensuring that it's not possible to give a path to a file outside that directory. // and ensuring that it's not possible to give a path to a file outside that directory.
filebytes, err := ioutil.ReadFile(filename) // #nosec filebytes, err := ioutil.ReadFile(filename) // #nosec

View File

@ -1,11 +1,10 @@
package yqlib package yqlib
import ( import (
"container/list"
"fmt" "fmt"
"strconv" "strconv"
"container/list"
"github.com/jinzhu/copier" "github.com/jinzhu/copier"
yaml "gopkg.in/yaml.v3" yaml "gopkg.in/yaml.v3"
) )
@ -42,7 +41,7 @@ func multiply(preferences multiplyPreferences) func(d *dataTreeNavigator, contex
leadingContent, headComment, footComment := getComments(lhs, rhs) leadingContent, headComment, footComment := getComments(lhs, rhs)
lhs.Node = unwrapDoc(lhs.Node) lhs.Node = unwrapDoc(lhs.Node)
rhs.Node = unwrapDoc(rhs.Node) rhs.Node = unwrapDoc(rhs.Node)
log.Debugf("Multipling LHS: %v", lhs.Node.Tag) log.Debugf("Multiplying LHS: %v", lhs.Node.Tag)
log.Debugf("- RHS: %v", rhs.Node.Tag) log.Debugf("- RHS: %v", rhs.Node.Tag)
if lhs.Node.Kind == yaml.MappingNode && rhs.Node.Kind == yaml.MappingNode || if lhs.Node.Kind == yaml.MappingNode && rhs.Node.Kind == yaml.MappingNode ||

View File

@ -29,10 +29,22 @@ var mergeArrayWithAnchors = `sample:
- <<: *a - <<: *a
` `
var mergeArraysObjectKeysText = `It's a complex command, the trickyness comes from needing to have the right context in the expressions. var mergeArraysObjectKeysText = `There are several parts of the complex expression.
First we save the second array into a variable '$two' which lets us reference it later. The first part is doing the hard work, it creates a map from the arrays keyed by '.a', so that there are no duplicates.
We then need to update the first array. We will use the relative update (|=) because we need to update relative to the current element of the array in the LHS in the RHS expression. Then there's another reduce that converts that map back to an array.
We set the current element of the first array as $cur. Now we multiply (merge) $cur with the matching entry in $two, by passing $two through a select filter. Finally, we set the result of the merged array back into the first doc.
To use this, you will need to update '.myArray' to be the expression to your array (e.g. .my.array), and '.a' to be the key field of your array (e.g. '.name')
Thanks Kev from [stackoverflow](https://stackoverflow.com/a/70109529/1168223)
`
var mergeExpression = `
(
((.myArray[] | {.a: .}) as $item ireduce ({}; . * $item )) as $uniqueMap
| ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value)
) as $mergedArray
| select(fi == 0) | .myArray = $mergedArray
` `
var docWithHeader = `# here var docWithHeader = `# here
@ -371,11 +383,11 @@ var multiplyOperatorScenarios = []expressionScenario{
{ {
description: "Merge arrays of objects together, matching on a key", description: "Merge arrays of objects together, matching on a key",
subdescription: mergeArraysObjectKeysText, subdescription: mergeArraysObjectKeysText,
document: `[{a: apple, b: appleB}, {a: kiwi, b: kiwiB}, {a: banana, b: bananaB}]`, document: `{myArray: [{a: apple, b: appleB}, {a: kiwi, b: kiwiB}, {a: banana, b: bananaB}], something: else}`,
document2: `[{a: banana, c: bananaC}, {a: apple, b: appleB2}, {a: dingo, c: dingoC}]`, document2: `myArray: [{a: banana, c: bananaC}, {a: apple, b: appleB2}, {a: dingo, c: dingoC}]`,
expression: `(select(fi==1) | .[]) as $two | select(fi==0) | .[] |= (. as $cur | $cur * ($two | select(.a == $cur.a)))`, expression: mergeExpression,
expected: []string{ expected: []string{
"D0, P[], (doc)::[{a: apple, b: appleB2}, {a: kiwi, b: kiwiB}, {a: banana, b: bananaB, c: bananaC}]\n", "D0, P[], (doc)::{myArray: [{a: apple, b: appleB2}, {a: kiwi, b: kiwiB}, {a: banana, b: bananaB, c: bananaC}, {a: dingo, c: dingoC}], something: else}\n",
}, },
}, },
{ {

View File

@ -99,7 +99,7 @@ var stringsOperatorScenarios = []expressionScenario{
}, },
{ {
description: "Test using regex", description: "Test using regex",
subdescription: "Like jq'q equivalant, this works like match but only returns true/false instead of full match details", subdescription: "Like jq'q equivalent, this works like match but only returns true/false instead of full match details",
document: `["cat", "dog"]`, document: `["cat", "dog"]`,
expression: `.[] | test("at")`, expression: `.[] | test("at")`,
expected: []string{ expected: []string{

View File

@ -2,7 +2,6 @@ package yqlib
import ( import (
"fmt" "fmt"
"strconv" "strconv"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"

View File

@ -42,7 +42,7 @@ func traverse(d *dataTreeNavigator, context Context, matchingNode *CandidateNode
if value.Tag == "!!null" && operation.Value != "[]" { if value.Tag == "!!null" && operation.Value != "[]" {
log.Debugf("Guessing kind") log.Debugf("Guessing kind")
// we must ahve added this automatically, lets guess what it should be now // we must have added this automatically, lets guess what it should be now
switch operation.Value.(type) { switch operation.Value.(type) {
case int, int64: case int, int64:
log.Debugf("probably an array") log.Debugf("probably an array")
@ -87,7 +87,7 @@ func traverseArrayOperator(d *dataTreeNavigator, context Context, expressionNode
return Context{}, err return Context{}, err
} }
// rhs is a collect expression that will yield indexes to retreive of the arrays // rhs is a collect expression that will yield indexes to retrieve of the arrays
rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs) rhs, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.Rhs)

View File

@ -17,7 +17,7 @@ func readStream(filename string, leadingContentPreProcessing bool) (io.Reader, s
if filename == "-" { if filename == "-" {
reader = bufio.NewReader(os.Stdin) reader = bufio.NewReader(os.Stdin)
} else { } else {
// ignore CWE-22 gosec issue - that's more targetted for http based apps that run in a public directory, // ignore CWE-22 gosec issue - that's more targeted for http based apps that run in a public directory,
// and ensuring that it's not possible to give a path to a file outside thar directory. // and ensuring that it's not possible to give a path to a file outside thar directory.
file, err := os.Open(filename) // #nosec file, err := os.Open(filename) // #nosec
if err != nil { if err != nil {

View File

@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
set -ex set -ex
go mod download golang.org/x/tools go mod download golang.org/x/tools@latest
wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.37.1 wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.43.0
wget -O- -nv https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s v2.9.1 wget -O- -nv https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s v2.9.1