mirror of
https://github.com/taigrr/yq
synced 2025-01-18 04:53:17 -08:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65cb472604 | ||
|
|
fbba38c9b7 | ||
|
|
e5948c4f16 | ||
|
|
4eaadf98d0 | ||
|
|
eedbb0a99f | ||
|
|
7dabc57b65 | ||
|
|
fcd3a90f67 | ||
|
|
88e99e5336 | ||
|
|
a8cfccd3af | ||
|
|
3355e80d85 | ||
|
|
f528b28938 | ||
|
|
5b7b390a33 | ||
|
|
4f12e09e78 | ||
|
|
ee732fbf0b | ||
|
|
1507f929a2 | ||
|
|
c11c3df84f | ||
|
|
06bb3ac826 | ||
|
|
778f8c6916 | ||
|
|
9f43a4a265 | ||
|
|
bb6f07d147 | ||
|
|
759456e375 | ||
|
|
5e59803037 | ||
|
|
a0cb691601 | ||
|
|
fea8510061 | ||
|
|
b380ea2892 | ||
|
|
d66a709213 | ||
|
|
2fc39b3865 | ||
|
|
ee07edbd88 | ||
|
|
b11661a1be | ||
|
|
eac218980e | ||
|
|
80e7f46538 | ||
|
|
086f0ec6b9 | ||
|
|
89cbe63343 |
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -10,6 +10,9 @@ assignees: ''
|
|||||||
**Describe the bug**
|
**Describe the bug**
|
||||||
A clear and concise description of what the bug is.
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
version of yq:
|
||||||
|
operating system:
|
||||||
|
|
||||||
**Input Yaml**
|
**Input Yaml**
|
||||||
Concise yaml document(s) (as simple as possible to show the bug)
|
Concise yaml document(s) (as simple as possible to show the bug)
|
||||||
data1.yml:
|
data1.yml:
|
||||||
|
|||||||
4
.github/workflows/go.yml
vendored
4
.github/workflows/go.yml
vendored
@@ -7,10 +7,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Set up Go 1.14
|
- name: Set up Go 1.15
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v1
|
||||||
with:
|
with:
|
||||||
go-version: 1.14
|
go-version: 1.15
|
||||||
id: go
|
id: go
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.14 as builder
|
FROM golang:1.15 as builder
|
||||||
|
|
||||||
WORKDIR /go/src/mikefarah/yq
|
WORKDIR /go/src/mikefarah/yq
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.14
|
FROM golang:1.15
|
||||||
|
|
||||||
COPY scripts/devtools.sh /opt/devtools.sh
|
COPY scripts/devtools.sh /opt/devtools.sh
|
||||||
|
|
||||||
|
|||||||
17
README.md
17
README.md
@@ -23,7 +23,16 @@ brew install yq
|
|||||||
```
|
```
|
||||||
choco install yq
|
choco install yq
|
||||||
```
|
```
|
||||||
Supported by @chillum
|
Supported by @chillum (https://chocolatey.org/packages/yq)
|
||||||
|
|
||||||
|
### Alpine Linux
|
||||||
|
- Enable community repo by adding ```$MIRROR/alpine/v$VERSION/community``` to ```/etc/apk/repositories```
|
||||||
|
- Update database index with ```apk update```
|
||||||
|
- Install yq with ```apk add yq```
|
||||||
|
|
||||||
|
Supported by Tuan Hoang
|
||||||
|
https://pkgs.alpinelinux.org/package/edge/community/x86/yq
|
||||||
|
|
||||||
|
|
||||||
### Ubuntu and other Linux distros supporting `snap` packages:
|
### Ubuntu and other Linux distros supporting `snap` packages:
|
||||||
```
|
```
|
||||||
@@ -55,7 +64,7 @@ sudo add-apt-repository ppa:rmescandon/yq
|
|||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install yq -y
|
sudo apt install yq -y
|
||||||
```
|
```
|
||||||
Supported by @rmescandon
|
Supported by @rmescandon (https://launchpad.net/~rmescandon/+archive/ubuntu/yq)
|
||||||
|
|
||||||
### Go Get:
|
### Go Get:
|
||||||
```
|
```
|
||||||
@@ -135,3 +144,7 @@ Flags:
|
|||||||
|
|
||||||
Use "yq [command] --help" for more information about a command.
|
Use "yq [command] --help" for more information about a command.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Known Issues / Missing Features
|
||||||
|
- `yq` attempts to preserve comment positions and whitespace as much as possible, but it does not handle all scenarios (see https://github.com/go-yaml/yaml/tree/v3 for details)
|
||||||
|
- You cannot (yet) select multiple paths/keys from the yaml to be printed out (https://github.com/mikefarah/yq/issues/287)
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ var defaultValue = ""
|
|||||||
var indent = 2
|
var indent = 2
|
||||||
var overwriteFlag = false
|
var overwriteFlag = false
|
||||||
var autoCreateFlag = true
|
var autoCreateFlag = true
|
||||||
var appendFlag = false
|
var arrayMergeStrategyFlag = "update"
|
||||||
|
var commentsMergeStrategyFlag = "setWhenBlank"
|
||||||
var verbose = false
|
var verbose = false
|
||||||
var version = false
|
var version = false
|
||||||
var docIndex = "0"
|
var docIndex = "0"
|
||||||
|
|||||||
66
cmd/merge.go
66
cmd/merge.go
@@ -11,14 +11,14 @@ func createMergeCmd() *cobra.Command {
|
|||||||
var cmdMerge = &cobra.Command{
|
var cmdMerge = &cobra.Command{
|
||||||
Use: "merge [initial_yaml_file] [additional_yaml_file]...",
|
Use: "merge [initial_yaml_file] [additional_yaml_file]...",
|
||||||
Aliases: []string{"m"},
|
Aliases: []string{"m"},
|
||||||
Short: "yq m [--inplace/-i] [--doc/-d index] [--overwrite/-x] [--append/-a] sample.yaml sample2.yaml",
|
Short: "yq m [--inplace/-i] [--doc/-d index] [--overwrite/-x] [--arrayMerge/-a strategy] sample.yaml sample2.yaml",
|
||||||
Example: `
|
Example: `
|
||||||
yq merge things.yaml other.yaml
|
yq merge things.yaml other.yaml
|
||||||
yq merge --inplace things.yaml other.yaml
|
yq merge --inplace things.yaml other.yaml
|
||||||
yq m -i things.yaml other.yaml
|
yq m -i things.yaml other.yaml
|
||||||
yq m --overwrite things.yaml other.yaml
|
yq m --overwrite things.yaml other.yaml
|
||||||
yq m -i -x things.yaml other.yaml
|
yq m -i -x things.yaml other.yaml
|
||||||
yq m -i -a things.yaml other.yaml
|
yq m -i -a=append things.yaml other.yaml
|
||||||
yq m -i --autocreate=false things.yaml other.yaml
|
yq m -i --autocreate=false things.yaml other.yaml
|
||||||
`,
|
`,
|
||||||
Long: `Updates the yaml file by adding/updating the path(s) and value(s) from additional yaml file(s).
|
Long: `Updates the yaml file by adding/updating the path(s) and value(s) from additional yaml file(s).
|
||||||
@@ -32,7 +32,17 @@ If append flag is set then existing arrays will be merged with the arrays from e
|
|||||||
cmdMerge.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace")
|
cmdMerge.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace")
|
||||||
cmdMerge.PersistentFlags().BoolVarP(&overwriteFlag, "overwrite", "x", false, "update the yaml file by overwriting existing values")
|
cmdMerge.PersistentFlags().BoolVarP(&overwriteFlag, "overwrite", "x", false, "update the yaml file by overwriting existing values")
|
||||||
cmdMerge.PersistentFlags().BoolVarP(&autoCreateFlag, "autocreate", "c", true, "automatically create any missing entries")
|
cmdMerge.PersistentFlags().BoolVarP(&autoCreateFlag, "autocreate", "c", true, "automatically create any missing entries")
|
||||||
cmdMerge.PersistentFlags().BoolVarP(&appendFlag, "append", "a", false, "update the yaml file by appending array values")
|
cmdMerge.PersistentFlags().StringVarP(&arrayMergeStrategyFlag, "arrays", "a", "update", `array merge strategy (update/append/overwrite)
|
||||||
|
update: recursively update arrays by their index
|
||||||
|
append: concatenate arrays together
|
||||||
|
overwrite: replace arrays
|
||||||
|
`)
|
||||||
|
cmdMerge.PersistentFlags().StringVarP(&commentsMergeStrategyFlag, "comments", "", "setWhenBlank", `comments merge strategy (setWhenBlank/ignore/append/overwrite)
|
||||||
|
setWhenBlank: set comment if the original document has no comment at that node
|
||||||
|
ignore: leave comments as-is in the original
|
||||||
|
append: append comments together
|
||||||
|
overwrite: overwrite comments completely
|
||||||
|
`)
|
||||||
cmdMerge.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
cmdMerge.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||||
return cmdMerge
|
return cmdMerge
|
||||||
}
|
}
|
||||||
@@ -41,9 +51,9 @@ If append flag is set then existing arrays will be merged with the arrays from e
|
|||||||
* We don't deeply traverse arrays when appending a merge, instead we want to
|
* We don't deeply traverse arrays when appending a merge, instead we want to
|
||||||
* append the entire array element.
|
* append the entire array element.
|
||||||
*/
|
*/
|
||||||
func createReadFunctionForMerge() func(*yaml.Node) ([]*yqlib.NodeContext, error) {
|
func createReadFunctionForMerge(arrayMergeStrategy yqlib.ArrayMergeStrategy) func(*yaml.Node) ([]*yqlib.NodeContext, error) {
|
||||||
return func(dataBucket *yaml.Node) ([]*yqlib.NodeContext, error) {
|
return func(dataBucket *yaml.Node) ([]*yqlib.NodeContext, error) {
|
||||||
return lib.Get(dataBucket, "**", !appendFlag)
|
return lib.GetForMerge(dataBucket, "**", arrayMergeStrategy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,19 +63,59 @@ func mergeProperties(cmd *cobra.Command, args []string) error {
|
|||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
return errors.New("Must provide at least 1 yaml file")
|
return errors.New("Must provide at least 1 yaml file")
|
||||||
}
|
}
|
||||||
|
var arrayMergeStrategy yqlib.ArrayMergeStrategy
|
||||||
|
|
||||||
|
switch arrayMergeStrategyFlag {
|
||||||
|
case "update":
|
||||||
|
arrayMergeStrategy = yqlib.UpdateArrayMergeStrategy
|
||||||
|
case "append":
|
||||||
|
arrayMergeStrategy = yqlib.AppendArrayMergeStrategy
|
||||||
|
case "overwrite":
|
||||||
|
arrayMergeStrategy = yqlib.OverwriteArrayMergeStrategy
|
||||||
|
default:
|
||||||
|
return errors.New("Array merge strategy must be one of: update/append/overwrite")
|
||||||
|
}
|
||||||
|
|
||||||
|
var commentsMergeStrategy yqlib.CommentsMergeStrategy
|
||||||
|
|
||||||
|
switch commentsMergeStrategyFlag {
|
||||||
|
case "setWhenBlank":
|
||||||
|
commentsMergeStrategy = yqlib.SetWhenBlankCommentsMergeStrategy
|
||||||
|
case "ignore":
|
||||||
|
commentsMergeStrategy = yqlib.IgnoreCommentsMergeStrategy
|
||||||
|
case "append":
|
||||||
|
commentsMergeStrategy = yqlib.AppendCommentsMergeStrategy
|
||||||
|
case "overwrite":
|
||||||
|
commentsMergeStrategy = yqlib.OverwriteCommentsMergeStrategy
|
||||||
|
default:
|
||||||
|
return errors.New("Comments merge strategy must be one of: setWhenBlank/ignore/append/overwrite")
|
||||||
|
}
|
||||||
|
|
||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
// first generate update commands from the file
|
// first generate update commands from the file
|
||||||
var filesToMerge = args[1:]
|
var filesToMerge = args[1:]
|
||||||
|
|
||||||
for _, fileToMerge := range filesToMerge {
|
for _, fileToMerge := range filesToMerge {
|
||||||
matchingNodes, errorProcessingFile := doReadYamlFile(fileToMerge, createReadFunctionForMerge(), false, 0)
|
matchingNodes, errorProcessingFile := doReadYamlFile(fileToMerge, createReadFunctionForMerge(arrayMergeStrategy), false, 0)
|
||||||
if errorProcessingFile != nil {
|
if errorProcessingFile != nil {
|
||||||
return errorProcessingFile
|
return errorProcessingFile
|
||||||
}
|
}
|
||||||
|
log.Debugf("finished reading for merge!")
|
||||||
for _, matchingNode := range matchingNodes {
|
for _, matchingNode := range matchingNodes {
|
||||||
mergePath := lib.MergePathStackToString(matchingNode.PathStack, appendFlag)
|
log.Debugf("matched node %v", lib.PathStackToString(matchingNode.PathStack))
|
||||||
updateCommands = append(updateCommands, yqlib.UpdateCommand{Command: "update", Path: mergePath, Value: matchingNode.Node, Overwrite: overwriteFlag})
|
yqlib.DebugNode(matchingNode.Node)
|
||||||
|
}
|
||||||
|
for _, matchingNode := range matchingNodes {
|
||||||
|
mergePath := lib.MergePathStackToString(matchingNode.PathStack, arrayMergeStrategy)
|
||||||
|
updateCommands = append(updateCommands, yqlib.UpdateCommand{
|
||||||
|
Command: "merge",
|
||||||
|
Path: mergePath,
|
||||||
|
Value: matchingNode.Node,
|
||||||
|
Overwrite: overwriteFlag,
|
||||||
|
CommentsMergeStrategy: commentsMergeStrategy,
|
||||||
|
// dont update the content for nodes midway, only leaf nodes
|
||||||
|
DontUpdateNodeContent: matchingNode.IsMiddleNode && (arrayMergeStrategy != yqlib.OverwriteArrayMergeStrategy || matchingNode.Node.Kind != yaml.SequenceNode),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func TestMergeOverwriteCmd(t *testing.T) {
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
expectedOutput := `a: other # better than the original
|
expectedOutput := `a: other # just the best
|
||||||
b: [3, 4]
|
b: [3, 4]
|
||||||
c:
|
c:
|
||||||
test: 1
|
test: 1
|
||||||
@@ -68,9 +68,36 @@ c:
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMergeOverwriteDeepExampleCmd(t *testing.T) {
|
||||||
|
content := `c:
|
||||||
|
test: 1
|
||||||
|
thing: whatever
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeContent := `c:
|
||||||
|
test: 5
|
||||||
|
`
|
||||||
|
mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||||
|
defer test.RemoveTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("merge --autocreate=false --overwrite %s %s", filename, mergeFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `c:
|
||||||
|
test: 5
|
||||||
|
thing: whatever
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestMergeAppendCmd(t *testing.T) {
|
func TestMergeAppendCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "merge --autocreate=false --append ../examples/data1.yaml ../examples/data2.yaml")
|
result := test.RunCmd(cmd, "merge --autocreate=false --arrays=append ../examples/data1.yaml ../examples/data2.yaml")
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
@@ -96,7 +123,7 @@ func TestMergeAppendArraysCmd(t *testing.T) {
|
|||||||
defer test.RemoveTempYamlFile(mergeFilename)
|
defer test.RemoveTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, fmt.Sprintf("merge --append -d* %s %s", filename, mergeFilename))
|
result := test.RunCmd(cmd, fmt.Sprintf("merge --arrays=append -d* %s %s", filename, mergeFilename))
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
@@ -109,13 +136,56 @@ func TestMergeAppendArraysCmd(t *testing.T) {
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMergeOverwriteAndAppendCmd(t *testing.T) {
|
func TestMergeAliasArraysCmd(t *testing.T) {
|
||||||
|
content := `
|
||||||
|
vars:
|
||||||
|
variable1: &var1 cat
|
||||||
|
|
||||||
|
usage:
|
||||||
|
value1: *var1
|
||||||
|
valueAnother: *var1
|
||||||
|
valuePlain: thing
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeContent := `
|
||||||
|
vars:
|
||||||
|
variable2: &var2 puppy
|
||||||
|
|
||||||
|
usage:
|
||||||
|
value2: *var2
|
||||||
|
valueAnother: *var2
|
||||||
|
valuePlain: *var2
|
||||||
|
`
|
||||||
|
|
||||||
|
mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||||
|
defer test.RemoveTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "merge --autocreate=false --append --overwrite ../examples/data1.yaml ../examples/data2.yaml")
|
result := test.RunCmd(cmd, fmt.Sprintf("merge -x %s %s", filename, mergeFilename))
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
expectedOutput := `a: other # better than the original
|
expectedOutput := `vars:
|
||||||
|
variable1: &var1 cat
|
||||||
|
variable2: &var2 puppy
|
||||||
|
usage:
|
||||||
|
value1: *var1
|
||||||
|
valueAnother: *var2
|
||||||
|
valuePlain: *var2
|
||||||
|
value2: *var2
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeOverwriteAndAppendCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge --autocreate=false --arrays=append --overwrite ../examples/data1.yaml ../examples/data2.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `a: other # just the best
|
||||||
b: [1, 2, 3, 4]
|
b: [1, 2, 3, 4]
|
||||||
c:
|
c:
|
||||||
test: 1
|
test: 1
|
||||||
@@ -123,13 +193,161 @@ c:
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMergeArraysCmd(t *testing.T) {
|
var commentContentA = `
|
||||||
|
a: valueA1 # commentA1
|
||||||
|
b: valueB1
|
||||||
|
`
|
||||||
|
|
||||||
|
var commentContentB = `
|
||||||
|
a: valueA2 # commentA2
|
||||||
|
b: valueB2 # commentB2
|
||||||
|
c: valueC2 # commentC2
|
||||||
|
`
|
||||||
|
|
||||||
|
func TestMergeCommentsSetWhenBlankCmd(t *testing.T) {
|
||||||
|
filename := test.WriteTempYamlFile(commentContentA)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeFilename := test.WriteTempYamlFile(commentContentB)
|
||||||
|
defer test.RemoveTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "merge --append ../examples/sample_array.yaml ../examples/sample_array_2.yaml")
|
result := test.RunCmd(cmd, fmt.Sprintf("merge --comments=setWhenBlank %s %s", filename, mergeFilename))
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
expectedOutput := `[1, 2, 3, 4, 5]
|
|
||||||
|
expectedOutput := `a: valueA1 # commentA1
|
||||||
|
b: valueB1 # commentB2
|
||||||
|
c: valueC2 # commentC2
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeCommentsIgnoreCmd(t *testing.T) {
|
||||||
|
filename := test.WriteTempYamlFile(commentContentA)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeFilename := test.WriteTempYamlFile(commentContentB)
|
||||||
|
defer test.RemoveTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("merge --comments=ignore %s %s", filename, mergeFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `a: valueA1 # commentA1
|
||||||
|
b: valueB1
|
||||||
|
c: valueC2
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeCommentsAppendCmd(t *testing.T) {
|
||||||
|
filename := test.WriteTempYamlFile(commentContentA)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeFilename := test.WriteTempYamlFile(commentContentB)
|
||||||
|
defer test.RemoveTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("merge --comments=append %s %s", filename, mergeFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `a: valueA1 # commentA1 # commentA2
|
||||||
|
b: valueB1 # commentB2
|
||||||
|
c: valueC2 # commentC2
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeCommentsOverwriteCmd(t *testing.T) {
|
||||||
|
filename := test.WriteTempYamlFile(commentContentA)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeFilename := test.WriteTempYamlFile(commentContentB)
|
||||||
|
defer test.RemoveTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("merge --comments=overwrite %s %s", filename, mergeFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `a: valueA1 # commentA2
|
||||||
|
b: valueB1 # commentB2
|
||||||
|
c: valueC2 # commentC2
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeOverwriteArraysTooCmd(t *testing.T) {
|
||||||
|
content := `a: simple # just the best
|
||||||
|
b: [1, 2]
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeContent := `a: things
|
||||||
|
b: [6]`
|
||||||
|
mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||||
|
defer test.RemoveTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("merge --autocreate=false --arrays=overwrite --overwrite %s %s", filename, mergeFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `a: things # just the best
|
||||||
|
b: [6]
|
||||||
|
c:
|
||||||
|
test: 1
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeRootArraysCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge --arrays=append ../examples/sample_array.yaml ../examples/sample_array_2.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `- 1
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
- 4
|
||||||
|
- 5
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeOverwriteArraysCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge --arrays=overwrite ../examples/sample_array.yaml ../examples/sample_array_2.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `- 4
|
||||||
|
- 5
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeUpdateArraysCmd(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, "merge -x --arrays=update ../examples/sample_array.yaml ../examples/sample_array_2.yaml")
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `- 4
|
||||||
|
- 5
|
||||||
|
- 3
|
||||||
`
|
`
|
||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
@@ -145,9 +363,7 @@ func TestMergeCmd_Multi(t *testing.T) {
|
|||||||
another:
|
another:
|
||||||
document: here
|
document: here
|
||||||
a: simple # just the best
|
a: simple # just the best
|
||||||
b:
|
b: [1, 2]
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
c:
|
c:
|
||||||
test: 1
|
test: 1
|
||||||
---
|
---
|
||||||
@@ -316,9 +532,7 @@ func TestMergeAllowEmptyTargetCmd(t *testing.T) {
|
|||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
expectedOutput := `a: simple # just the best
|
expectedOutput := `a: simple # just the best
|
||||||
b:
|
b: [1, 2]
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
c:
|
c:
|
||||||
test: 1
|
test: 1
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/mikefarah/yq/v3/pkg/yqlib"
|
"github.com/mikefarah/yq/v3/pkg/yqlib"
|
||||||
errors "github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -36,11 +35,7 @@ Note that you can give a create script to perform more sophisticated yaml. This
|
|||||||
|
|
||||||
func newProperty(cmd *cobra.Command, args []string) error {
|
func newProperty(cmd *cobra.Command, args []string) error {
|
||||||
var badArgsMessage = "Must provide <path_to_update> <value>"
|
var badArgsMessage = "Must provide <path_to_update> <value>"
|
||||||
if len(args) != 2 {
|
var updateCommands, updateCommandsError = readUpdateCommands(args, 2, badArgsMessage, false)
|
||||||
return errors.New(badArgsMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
var updateCommands, updateCommandsError = readUpdateCommands(args, 2, badArgsMessage)
|
|
||||||
if updateCommandsError != nil {
|
if updateCommandsError != nil {
|
||||||
return updateCommandsError
|
return updateCommandsError
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/mikefarah/yq/v3/test"
|
"github.com/mikefarah/yq/v3/test"
|
||||||
@@ -18,6 +19,24 @@ func TestNewCmd(t *testing.T) {
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNewCmdScript(t *testing.T) {
|
||||||
|
updateScript := `- command: update
|
||||||
|
path: b.c
|
||||||
|
value: 7`
|
||||||
|
scriptFilename := test.WriteTempYamlFile(updateScript)
|
||||||
|
defer test.RemoveTempYamlFile(scriptFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("new --script %s", scriptFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 7
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewAnchorCmd(t *testing.T) {
|
func TestNewAnchorCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "new b.c 3 --anchorName=fred")
|
result := test.RunCmd(cmd, "new b.c 3 --anchorName=fred")
|
||||||
|
|||||||
@@ -94,6 +94,28 @@ func TestReadUnwrapJsonByDefaultCmd(t *testing.T) {
|
|||||||
test.AssertResult(t, "\"frog\"\n", result.Output)
|
test.AssertResult(t, "\"frog\"\n", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReadOutputJsonNonStringKeysCmd(t *testing.T) {
|
||||||
|
|
||||||
|
content := `
|
||||||
|
true: true
|
||||||
|
5:
|
||||||
|
null:
|
||||||
|
0.1: deeply
|
||||||
|
false: things`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("read %s -j", filename))
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `{"5":{"null":{"0.1":"deeply","false":"things"}},"true":true}
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestReadWithAdvancedFilterCmd(t *testing.T) {
|
func TestReadWithAdvancedFilterCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "read ../examples/sample.yaml b.e(name==sam).value")
|
result := test.RunCmd(cmd, "read ../examples/sample.yaml b.e(name==sam).value")
|
||||||
@@ -595,6 +617,44 @@ pointer: *value-pointer`
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReadMergeAnchorsExplodeMissingCmd(t *testing.T) {
|
||||||
|
content := `a:
|
||||||
|
<<: &anchor
|
||||||
|
c: d
|
||||||
|
e: f
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("read -X %s", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `a:
|
||||||
|
c: d
|
||||||
|
e: f
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReadMergeAnchorsExplodeKeyCmd(t *testing.T) {
|
||||||
|
content := `name: &nameField Mike
|
||||||
|
*nameField: Great Guy`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("read -X %s", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `name: Mike
|
||||||
|
Mike: Great Guy
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestReadMergeAnchorsExplodeSimpleArrayCmd(t *testing.T) {
|
func TestReadMergeAnchorsExplodeSimpleArrayCmd(t *testing.T) {
|
||||||
content := `- things`
|
content := `- things`
|
||||||
filename := test.WriteTempYamlFile(content)
|
filename := test.WriteTempYamlFile(content)
|
||||||
@@ -1207,6 +1267,26 @@ func TestReadBadDataCmd(t *testing.T) {
|
|||||||
test.AssertResult(t, expectedOutput, result.Error.Error())
|
test.AssertResult(t, expectedOutput, result.Error.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReadDeepFromRootCmd(t *testing.T) {
|
||||||
|
content := `state:
|
||||||
|
country:
|
||||||
|
city: foo
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("read %s (**.city==foo)", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedOutput := `country:
|
||||||
|
city: foo
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestReadSplatPrefixCmd(t *testing.T) {
|
func TestReadSplatPrefixCmd(t *testing.T) {
|
||||||
content := `a: 2
|
content := `a: 2
|
||||||
b:
|
b:
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ func New() *cobra.Command {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||||
|
cmd.SetOut(cmd.OutOrStdout())
|
||||||
var format = logging.MustStringFormatter(
|
var format = logging.MustStringFormatter(
|
||||||
`%{color}%{time:15:04:05} %{shortfunc} [%{level:.4s}]%{color:reset} %{message}`,
|
`%{color}%{time:15:04:05} %{shortfunc} [%{level:.4s}]%{color:reset} %{message}`,
|
||||||
)
|
)
|
||||||
|
|||||||
30
cmd/utils.go
30
cmd/utils.go
@@ -17,7 +17,7 @@ type readDataFn func(dataBucket *yaml.Node) ([]*yqlib.NodeContext, error)
|
|||||||
|
|
||||||
func createReadFunction(path string) func(*yaml.Node) ([]*yqlib.NodeContext, error) {
|
func createReadFunction(path string) func(*yaml.Node) ([]*yqlib.NodeContext, error) {
|
||||||
return func(dataBucket *yaml.Node) ([]*yqlib.NodeContext, error) {
|
return func(dataBucket *yaml.Node) ([]*yqlib.NodeContext, error) {
|
||||||
return lib.Get(dataBucket, path, true)
|
return lib.Get(dataBucket, path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,6 +163,9 @@ func setIfNotThere(node *yaml.Node, key string, value *yaml.Node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func applyAlias(node *yaml.Node, alias *yaml.Node) {
|
func applyAlias(node *yaml.Node, alias *yaml.Node) {
|
||||||
|
if alias == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
for index := 0; index < len(alias.Content); index = index + 2 {
|
for index := 0; index < len(alias.Content); index = index + 2 {
|
||||||
keyNode := alias.Content[index]
|
keyNode := alias.Content[index]
|
||||||
log.Debugf("applying alias key %v", keyNode.Value)
|
log.Debugf("applying alias key %v", keyNode.Value)
|
||||||
@@ -185,12 +188,14 @@ func explodeNode(node *yaml.Node) error {
|
|||||||
return nil
|
return nil
|
||||||
case yaml.AliasNode:
|
case yaml.AliasNode:
|
||||||
log.Debugf("its an alias!")
|
log.Debugf("its an alias!")
|
||||||
node.Kind = node.Alias.Kind
|
if node.Alias != nil {
|
||||||
node.Style = node.Alias.Style
|
node.Kind = node.Alias.Kind
|
||||||
node.Tag = node.Alias.Tag
|
node.Style = node.Alias.Style
|
||||||
node.Content = node.Alias.Content
|
node.Tag = node.Alias.Tag
|
||||||
node.Value = node.Alias.Value
|
node.Content = node.Alias.Content
|
||||||
node.Alias = nil
|
node.Value = node.Alias.Value
|
||||||
|
node.Alias = nil
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
case yaml.MappingNode:
|
case yaml.MappingNode:
|
||||||
for index := 0; index < len(node.Content); index = index + 2 {
|
for index := 0; index < len(node.Content); index = index + 2 {
|
||||||
@@ -202,6 +207,10 @@ func explodeNode(node *yaml.Node) error {
|
|||||||
if errorInContent != nil {
|
if errorInContent != nil {
|
||||||
return errorInContent
|
return errorInContent
|
||||||
}
|
}
|
||||||
|
errorInContent = explodeNode(keyNode)
|
||||||
|
if errorInContent != nil {
|
||||||
|
return errorInContent
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if valueNode.Kind == yaml.SequenceNode {
|
if valueNode.Kind == yaml.SequenceNode {
|
||||||
log.Debugf("an alias merge list!")
|
log.Debugf("an alias merge list!")
|
||||||
@@ -477,7 +486,7 @@ type updateCommandParsed struct {
|
|||||||
Value yaml.Node
|
Value yaml.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func readUpdateCommands(args []string, expectedArgs int, badArgsMessage string) ([]yqlib.UpdateCommand, error) {
|
func readUpdateCommands(args []string, expectedArgs int, badArgsMessage string, allowNoValue bool) ([]yqlib.UpdateCommand, error) {
|
||||||
var updateCommands []yqlib.UpdateCommand = make([]yqlib.UpdateCommand, 0)
|
var updateCommands []yqlib.UpdateCommand = make([]yqlib.UpdateCommand, 0)
|
||||||
if writeScript != "" {
|
if writeScript != "" {
|
||||||
var parsedCommands = make([]updateCommandParsed, 0)
|
var parsedCommands = make([]updateCommandParsed, 0)
|
||||||
@@ -511,8 +520,9 @@ func readUpdateCommands(args []string, expectedArgs int, badArgsMessage string)
|
|||||||
log.Debug("args %v", args)
|
log.Debug("args %v", args)
|
||||||
log.Debug("path %v", args[expectedArgs-2])
|
log.Debug("path %v", args[expectedArgs-2])
|
||||||
log.Debug("Value %v", args[expectedArgs-1])
|
log.Debug("Value %v", args[expectedArgs-1])
|
||||||
updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: valueParser.Parse(args[expectedArgs-1], customTag, customStyle, anchorName, makeAlias), Overwrite: true}
|
value := valueParser.Parse(args[expectedArgs-1], customTag, customStyle, anchorName, makeAlias)
|
||||||
} else if len(args) == expectedArgs-1 {
|
updateCommands[0] = yqlib.UpdateCommand{Command: "update", Path: args[expectedArgs-2], Value: value, Overwrite: true, CommentsMergeStrategy: yqlib.IgnoreCommentsMergeStrategy}
|
||||||
|
} else if len(args) == expectedArgs-1 && allowNoValue {
|
||||||
// don't update the value
|
// don't update the value
|
||||||
updateCommands = make([]yqlib.UpdateCommand, 1)
|
updateCommands = make([]yqlib.UpdateCommand, 1)
|
||||||
log.Debug("args %v", args)
|
log.Debug("args %v", args)
|
||||||
|
|||||||
@@ -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 = "3.3.2"
|
Version = "3.4.0"
|
||||||
|
|
||||||
// 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
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ format is list of update commands (update or delete) like so:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func writeProperty(cmd *cobra.Command, args []string) error {
|
func writeProperty(cmd *cobra.Command, args []string) error {
|
||||||
var updateCommands, updateCommandsError = readUpdateCommands(args, 3, "Must provide <filename> <path_to_update> <value>")
|
var updateCommands, updateCommandsError = readUpdateCommands(args, 3, "Must provide <filename> <path_to_update> <value>", true)
|
||||||
if updateCommandsError != nil {
|
if updateCommandsError != nil {
|
||||||
return updateCommandsError
|
return updateCommandsError
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,24 @@ func TestWriteCmd(t *testing.T) {
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWriteKeepCommentsCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3 # comment
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c 7", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 7 # comment
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestWriteWithTaggedStyleCmd(t *testing.T) {
|
func TestWriteWithTaggedStyleCmd(t *testing.T) {
|
||||||
content := `b:
|
content := `b:
|
||||||
c: dog
|
c: dog
|
||||||
|
|||||||
7
debian/changelog
vendored
7
debian/changelog
vendored
@@ -1,3 +1,10 @@
|
|||||||
|
yq (3.3.2) focal; urgency=medium
|
||||||
|
|
||||||
|
* Bug fix: existStatus bug (#459)
|
||||||
|
* Automatically makes a os temp directory if it does not exist (#461)
|
||||||
|
|
||||||
|
-- Roberto Mier Escandon <rmescandon@gmail.com> Fri, 07 Aug 2020 18:53:01 +0200
|
||||||
|
|
||||||
yq (3.3-0) focal; urgency=medium
|
yq (3.3-0) focal; urgency=medium
|
||||||
|
|
||||||
* You can control string styles (quotes) using the new --style flag
|
* You can control string styles (quotes) using the new --style flag
|
||||||
|
|||||||
12
go.mod
12
go.mod
@@ -2,16 +2,16 @@ module github.com/mikefarah/yq/v3
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/fatih/color v1.9.0
|
github.com/fatih/color v1.9.0
|
||||||
github.com/goccy/go-yaml v1.7.5
|
github.com/goccy/go-yaml v1.8.1
|
||||||
github.com/kylelemons/godebug v1.1.0
|
github.com/kylelemons/godebug v1.1.0
|
||||||
github.com/mattn/go-colorable v0.1.6 // indirect
|
github.com/mattn/go-colorable v0.1.7 // indirect
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/spf13/cobra v1.0.0
|
github.com/spf13/cobra v1.0.0
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 // indirect
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
|
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.14
|
go 1.15
|
||||||
|
|||||||
21
go.sum
21
go.sum
@@ -29,8 +29,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
|
|||||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/goccy/go-yaml v1.7.5 h1:dWvj+p3BG11S/GlUzwzt1WZz0lhBTzTIDtmXT/ZOaPY=
|
github.com/goccy/go-yaml v1.8.1 h1:JuZRFlqLM5cWF6A+waL8AKVuCcqvKOuhJtUQI+L3ez0=
|
||||||
github.com/goccy/go-yaml v1.7.5/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y=
|
github.com/goccy/go-yaml v1.8.1/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
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/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=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
@@ -64,8 +64,8 @@ github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgx
|
|||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
|
||||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
||||||
@@ -144,19 +144,20 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193
|
|||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y=
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f h1:Fqb3ao1hUmOR3GkUOg/Y+BadLwykBIzs5q8Ez2SbHyc=
|
||||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||||
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=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
@@ -175,6 +176,6 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
|
|||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|||||||
@@ -22,13 +22,8 @@ func NewDataNavigator(NavigationStrategy NavigationStrategy) DataNavigator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *navigator) Traverse(value *yaml.Node, path []interface{}) error {
|
func (n *navigator) Traverse(value *yaml.Node, path []interface{}) error {
|
||||||
realValue := value
|
|
||||||
emptyArray := make([]interface{}, 0)
|
emptyArray := make([]interface{}, 0)
|
||||||
log.Debugf("Traversing path %v", pathStackToString(path))
|
log.Debugf("Traversing path %v", pathStackToString(path))
|
||||||
if realValue.Kind == yaml.DocumentNode {
|
|
||||||
log.Debugf("its a document! returning the first child")
|
|
||||||
return n.doTraverse(value.Content[0], "", path, emptyArray)
|
|
||||||
}
|
|
||||||
return n.doTraverse(value, "", path, emptyArray)
|
return n.doTraverse(value, "", path, emptyArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +34,8 @@ func (n *navigator) doTraverse(value *yaml.Node, head interface{}, tail []interf
|
|||||||
var nodeContext = NewNodeContext(value, head, tail, pathStack)
|
var nodeContext = NewNodeContext(value, head, tail, pathStack)
|
||||||
|
|
||||||
var errorDeepSplatting error
|
var errorDeepSplatting error
|
||||||
if head == "**" && value.Kind != yaml.ScalarNode && n.navigationStrategy.ShouldDeeplyTraverse(nodeContext) {
|
// no need to deeply traverse the DocumentNode, as it's already covered by its first child.
|
||||||
|
if head == "**" && value.Kind != yaml.DocumentNode && value.Kind != yaml.ScalarNode && n.navigationStrategy.ShouldDeeplyTraverse(nodeContext) {
|
||||||
if len(pathStack) == 0 || pathStack[len(pathStack)-1] != "<<" {
|
if len(pathStack) == 0 || pathStack[len(pathStack)-1] != "<<" {
|
||||||
errorDeepSplatting = n.recurse(value, head, tail, pathStack)
|
errorDeepSplatting = n.recurse(value, head, tail, pathStack)
|
||||||
}
|
}
|
||||||
@@ -51,7 +47,11 @@ func (n *navigator) doTraverse(value *yaml.Node, head interface{}, tail []interf
|
|||||||
return errorDeepSplatting
|
return errorDeepSplatting
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(tail) > 0 && value.Kind != yaml.ScalarNode {
|
if value.Kind == yaml.DocumentNode {
|
||||||
|
log.Debugf("its a document, diving into %v", head)
|
||||||
|
DebugNode(value)
|
||||||
|
return n.recurse(value, head, tail, pathStack)
|
||||||
|
} else if len(tail) > 0 && value.Kind != yaml.ScalarNode {
|
||||||
log.Debugf("diving into %v", tail[0])
|
log.Debugf("diving into %v", tail[0])
|
||||||
DebugNode(value)
|
DebugNode(value)
|
||||||
return n.recurse(value, tail[0], tail[1:], pathStack)
|
return n.recurse(value, tail[0], tail[1:], pathStack)
|
||||||
@@ -73,6 +73,7 @@ func (n *navigator) recurse(value *yaml.Node, head interface{}, tail []interface
|
|||||||
nodeContext := NewNodeContext(value, head, tail, pathStack)
|
nodeContext := NewNodeContext(value, head, tail, pathStack)
|
||||||
|
|
||||||
if head == "**" && !n.navigationStrategy.ShouldOnlyDeeplyVisitLeaves(nodeContext) {
|
if head == "**" && !n.navigationStrategy.ShouldOnlyDeeplyVisitLeaves(nodeContext) {
|
||||||
|
nodeContext.IsMiddleNode = true
|
||||||
errorVisitingDeeply := n.navigationStrategy.Visit(nodeContext)
|
errorVisitingDeeply := n.navigationStrategy.Visit(nodeContext)
|
||||||
if errorVisitingDeeply != nil {
|
if errorVisitingDeeply != nil {
|
||||||
return errorVisitingDeeply
|
return errorVisitingDeeply
|
||||||
@@ -108,6 +109,8 @@ func (n *navigator) recurse(value *yaml.Node, head interface{}, tail []interface
|
|||||||
return n.recurse(value.Alias, head, tail, pathStack)
|
return n.recurse(value.Alias, head, tail, pathStack)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
case yaml.DocumentNode:
|
||||||
|
return n.doTraverse(value.Content[0], head, tail, pathStack)
|
||||||
default:
|
default:
|
||||||
return n.navigationStrategy.Visit(nodeContext)
|
return n.navigationStrategy.Visit(nodeContext)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,12 +12,6 @@ func DeleteNavigationStrategy(pathElementToDelete interface{}) NavigationStrateg
|
|||||||
followAlias: func(nodeContext NodeContext) bool {
|
followAlias: func(nodeContext NodeContext) bool {
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
autoCreateMap: func(nodeContext NodeContext) bool {
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
shouldDeeplyTraverse: func(nodeContext NodeContext) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
shouldOnlyDeeplyVisitLeaves: func(nodeContext NodeContext) bool {
|
shouldOnlyDeeplyVisitLeaves: func(nodeContext NodeContext) bool {
|
||||||
return false
|
return false
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -58,6 +58,21 @@ type jsonEncoder struct {
|
|||||||
encoder *json.Encoder
|
encoder *json.Encoder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mapKeysToStrings(node *yaml.Node) {
|
||||||
|
|
||||||
|
if node.Kind == yaml.MappingNode {
|
||||||
|
for index, child := range node.Content {
|
||||||
|
if index%2 == 0 { // its a map key
|
||||||
|
child.Tag = "!!str"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, child := range node.Content {
|
||||||
|
mapKeysToStrings(child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func NewJsonEncoder(destination io.Writer, prettyPrint bool, indent int) Encoder {
|
func NewJsonEncoder(destination io.Writer, prettyPrint bool, indent int) Encoder {
|
||||||
var encoder = json.NewEncoder(destination)
|
var encoder = json.NewEncoder(destination)
|
||||||
var indentString = ""
|
var indentString = ""
|
||||||
@@ -73,6 +88,8 @@ func NewJsonEncoder(destination io.Writer, prettyPrint bool, indent int) Encoder
|
|||||||
|
|
||||||
func (je *jsonEncoder) Encode(node *yaml.Node) error {
|
func (je *jsonEncoder) Encode(node *yaml.Node) error {
|
||||||
var dataBucket interface{}
|
var dataBucket interface{}
|
||||||
|
// firstly, convert all map keys to strings
|
||||||
|
mapKeysToStrings(node)
|
||||||
errorDecoding := node.Decode(&dataBucket)
|
errorDecoding := node.Decode(&dataBucket)
|
||||||
if errorDecoding != nil {
|
if errorDecoding != nil {
|
||||||
return errorDecoding
|
return errorDecoding
|
||||||
|
|||||||
@@ -4,12 +4,6 @@ func FilterMatchingNodesNavigationStrategy(value string) NavigationStrategy {
|
|||||||
return &NavigationStrategyImpl{
|
return &NavigationStrategyImpl{
|
||||||
visitedNodes: []*NodeContext{},
|
visitedNodes: []*NodeContext{},
|
||||||
pathParser: NewPathParser(),
|
pathParser: NewPathParser(),
|
||||||
followAlias: func(nodeContext NodeContext) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
autoCreateMap: func(nodeContext NodeContext) bool {
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
visit: func(nodeContext NodeContext) error {
|
visit: func(nodeContext NodeContext) error {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,11 +13,13 @@ import (
|
|||||||
var log = logging.MustGetLogger("yq")
|
var log = logging.MustGetLogger("yq")
|
||||||
|
|
||||||
type UpdateCommand struct {
|
type UpdateCommand struct {
|
||||||
Command string
|
Command string
|
||||||
Path string
|
Path string
|
||||||
Value *yaml.Node
|
Value *yaml.Node
|
||||||
Overwrite bool
|
Overwrite bool
|
||||||
DontUpdateNodeValue bool
|
DontUpdateNodeValue bool
|
||||||
|
DontUpdateNodeContent bool
|
||||||
|
CommentsMergeStrategy CommentsMergeStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
func KindString(kind yaml.Kind) string {
|
func KindString(kind yaml.Kind) string {
|
||||||
@@ -49,20 +51,23 @@ func DebugNode(value *yaml.Node) {
|
|||||||
}
|
}
|
||||||
encoder.Close()
|
encoder.Close()
|
||||||
log.Debug("Tag: %v, Kind: %v, Anchor: %v", value.Tag, KindString(value.Kind), value.Anchor)
|
log.Debug("Tag: %v, Kind: %v, Anchor: %v", value.Tag, KindString(value.Kind), value.Anchor)
|
||||||
log.Debug("%v", buf.String())
|
log.Debug("Head Comment: %v", value.HeadComment)
|
||||||
|
log.Debug("Line Comment: %v", value.LineComment)
|
||||||
|
log.Debug("FootComment Comment: %v", value.FootComment)
|
||||||
|
log.Debug("\n%v", buf.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func pathStackToString(pathStack []interface{}) string {
|
func pathStackToString(pathStack []interface{}) string {
|
||||||
return mergePathStackToString(pathStack, false)
|
return mergePathStackToString(pathStack, UpdateArrayMergeStrategy)
|
||||||
}
|
}
|
||||||
|
|
||||||
func mergePathStackToString(pathStack []interface{}, appendArrays bool) string {
|
func mergePathStackToString(pathStack []interface{}, arrayMergeStrategy ArrayMergeStrategy) string {
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
for index, path := range pathStack {
|
for index, path := range pathStack {
|
||||||
switch path.(type) {
|
switch path.(type) {
|
||||||
case int, int64:
|
case int, int64:
|
||||||
if appendArrays {
|
if arrayMergeStrategy == AppendArrayMergeStrategy {
|
||||||
sb.WriteString("[+]")
|
sb.WriteString("[+]")
|
||||||
} else {
|
} else {
|
||||||
sb.WriteString(fmt.Sprintf("[%v]", path))
|
sb.WriteString(fmt.Sprintf("[%v]", path))
|
||||||
@@ -93,9 +98,7 @@ func mergePathStackToString(pathStack []interface{}, appendArrays bool) string {
|
|||||||
sb.WriteString(".")
|
sb.WriteString(".")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var pathString = sb.String()
|
return sb.String()
|
||||||
log.Debug("got a path string: %v", pathString)
|
|
||||||
return pathString
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func guessKind(head interface{}, tail []interface{}, guess yaml.Kind) yaml.Kind {
|
func guessKind(head interface{}, tail []interface{}, guess yaml.Kind) yaml.Kind {
|
||||||
@@ -133,12 +136,13 @@ func guessKind(head interface{}, tail []interface{}, guess yaml.Kind) yaml.Kind
|
|||||||
}
|
}
|
||||||
|
|
||||||
type YqLib interface {
|
type YqLib interface {
|
||||||
Get(rootNode *yaml.Node, path string, deeplyTraverseArrays bool) ([]*NodeContext, error)
|
Get(rootNode *yaml.Node, path string) ([]*NodeContext, error)
|
||||||
|
GetForMerge(rootNode *yaml.Node, path string, arrayMergeStrategy ArrayMergeStrategy) ([]*NodeContext, error)
|
||||||
Update(rootNode *yaml.Node, updateCommand UpdateCommand, autoCreate bool) error
|
Update(rootNode *yaml.Node, updateCommand UpdateCommand, autoCreate bool) error
|
||||||
New(path string) yaml.Node
|
New(path string) yaml.Node
|
||||||
|
|
||||||
PathStackToString(pathStack []interface{}) string
|
PathStackToString(pathStack []interface{}) string
|
||||||
MergePathStackToString(pathStack []interface{}, appendArrays bool) string
|
MergePathStackToString(pathStack []interface{}, arrayMergeStrategy ArrayMergeStrategy) string
|
||||||
}
|
}
|
||||||
|
|
||||||
type lib struct {
|
type lib struct {
|
||||||
@@ -151,21 +155,28 @@ func NewYqLib() YqLib {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lib) Get(rootNode *yaml.Node, path string, deeplyTraverseArrays bool) ([]*NodeContext, error) {
|
func (l *lib) Get(rootNode *yaml.Node, path string) ([]*NodeContext, error) {
|
||||||
var paths = l.parser.ParsePath(path)
|
var paths = l.parser.ParsePath(path)
|
||||||
navigationStrategy := ReadNavigationStrategy(deeplyTraverseArrays)
|
navigationStrategy := ReadNavigationStrategy()
|
||||||
navigator := NewDataNavigator(navigationStrategy)
|
navigator := NewDataNavigator(navigationStrategy)
|
||||||
error := navigator.Traverse(rootNode, paths)
|
error := navigator.Traverse(rootNode, paths)
|
||||||
return navigationStrategy.GetVisitedNodes(), error
|
return navigationStrategy.GetVisitedNodes(), error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *lib) GetForMerge(rootNode *yaml.Node, path string, arrayMergeStrategy ArrayMergeStrategy) ([]*NodeContext, error) {
|
||||||
|
var paths = l.parser.ParsePath(path)
|
||||||
|
navigationStrategy := ReadForMergeNavigationStrategy(arrayMergeStrategy)
|
||||||
|
navigator := NewDataNavigator(navigationStrategy)
|
||||||
|
error := navigator.Traverse(rootNode, paths)
|
||||||
|
return navigationStrategy.GetVisitedNodes(), error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lib) PathStackToString(pathStack []interface{}) string {
|
func (l *lib) PathStackToString(pathStack []interface{}) string {
|
||||||
return pathStackToString(pathStack)
|
return pathStackToString(pathStack)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lib) MergePathStackToString(pathStack []interface{}, appendArrays bool) string {
|
func (l *lib) MergePathStackToString(pathStack []interface{}, arrayMergeStrategy ArrayMergeStrategy) string {
|
||||||
return mergePathStackToString(pathStack, appendArrays)
|
return mergePathStackToString(pathStack, arrayMergeStrategy)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lib) New(path string) yaml.Node {
|
func (l *lib) New(path string) yaml.Node {
|
||||||
@@ -181,6 +192,10 @@ func (l *lib) Update(rootNode *yaml.Node, updateCommand UpdateCommand, autoCreat
|
|||||||
var paths = l.parser.ParsePath(updateCommand.Path)
|
var paths = l.parser.ParsePath(updateCommand.Path)
|
||||||
navigator := NewDataNavigator(UpdateNavigationStrategy(updateCommand, autoCreate))
|
navigator := NewDataNavigator(UpdateNavigationStrategy(updateCommand, autoCreate))
|
||||||
return navigator.Traverse(rootNode, paths)
|
return navigator.Traverse(rootNode, paths)
|
||||||
|
case "merge":
|
||||||
|
var paths = l.parser.ParsePath(updateCommand.Path)
|
||||||
|
navigator := NewDataNavigator(MergeNavigationStrategy(updateCommand, autoCreate))
|
||||||
|
return navigator.Traverse(rootNode, paths)
|
||||||
case "delete":
|
case "delete":
|
||||||
var paths = l.parser.ParsePath(updateCommand.Path)
|
var paths = l.parser.ParsePath(updateCommand.Path)
|
||||||
lastBit, newTail := paths[len(paths)-1], paths[:len(paths)-1]
|
lastBit, newTail := paths[len(paths)-1], paths[:len(paths)-1]
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func TestLib(t *testing.T) {
|
|||||||
array[0] = "a"
|
array[0] = "a"
|
||||||
array[1] = 0
|
array[1] = 0
|
||||||
array[2] = "b"
|
array[2] = "b"
|
||||||
got := subject.MergePathStackToString(array, true)
|
got := subject.MergePathStackToString(array, AppendArrayMergeStrategy)
|
||||||
test.AssertResult(t, `a.[+].b`, got)
|
test.AssertResult(t, `a.[+].b`, got)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
103
pkg/yqlib/merge_navigation_strategy.go
Normal file
103
pkg/yqlib/merge_navigation_strategy.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import "gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
type ArrayMergeStrategy uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
UpdateArrayMergeStrategy ArrayMergeStrategy = 1 << iota
|
||||||
|
OverwriteArrayMergeStrategy
|
||||||
|
AppendArrayMergeStrategy
|
||||||
|
)
|
||||||
|
|
||||||
|
type CommentsMergeStrategy uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
SetWhenBlankCommentsMergeStrategy CommentsMergeStrategy = 1 << iota
|
||||||
|
IgnoreCommentsMergeStrategy
|
||||||
|
OverwriteCommentsMergeStrategy
|
||||||
|
AppendCommentsMergeStrategy
|
||||||
|
)
|
||||||
|
|
||||||
|
func MergeNavigationStrategy(updateCommand UpdateCommand, autoCreate bool) NavigationStrategy {
|
||||||
|
return &NavigationStrategyImpl{
|
||||||
|
visitedNodes: []*NodeContext{},
|
||||||
|
pathParser: NewPathParser(),
|
||||||
|
followAlias: func(nodeContext NodeContext) bool {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
autoCreateMap: func(nodeContext NodeContext) bool {
|
||||||
|
return autoCreate
|
||||||
|
},
|
||||||
|
visit: func(nodeContext NodeContext) error {
|
||||||
|
node := nodeContext.Node
|
||||||
|
changesToApply := updateCommand.Value
|
||||||
|
|
||||||
|
if node.Kind == yaml.DocumentNode && changesToApply.Kind != yaml.DocumentNode {
|
||||||
|
// when the path is empty, it matches both the top level pseudo document node
|
||||||
|
// and the actual top level node (e.g. map/sequence/whatever)
|
||||||
|
// so when we are updating with no path, make sure we update the right node.
|
||||||
|
node = node.Content[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("going to update")
|
||||||
|
DebugNode(node)
|
||||||
|
log.Debug("with")
|
||||||
|
DebugNode(changesToApply)
|
||||||
|
|
||||||
|
if updateCommand.Overwrite || node.Value == "" {
|
||||||
|
node.Value = changesToApply.Value
|
||||||
|
node.Tag = changesToApply.Tag
|
||||||
|
node.Kind = changesToApply.Kind
|
||||||
|
node.Style = changesToApply.Style
|
||||||
|
node.Anchor = changesToApply.Anchor
|
||||||
|
node.Alias = changesToApply.Alias
|
||||||
|
|
||||||
|
if !updateCommand.DontUpdateNodeContent {
|
||||||
|
node.Content = changesToApply.Content
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Debug("skipping update as node already has value %v and overwriteFlag is ", node.Value, updateCommand.Overwrite)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch updateCommand.CommentsMergeStrategy {
|
||||||
|
case OverwriteCommentsMergeStrategy:
|
||||||
|
node.HeadComment = changesToApply.HeadComment
|
||||||
|
node.LineComment = changesToApply.LineComment
|
||||||
|
node.FootComment = changesToApply.FootComment
|
||||||
|
case SetWhenBlankCommentsMergeStrategy:
|
||||||
|
if node.HeadComment == "" {
|
||||||
|
node.HeadComment = changesToApply.HeadComment
|
||||||
|
}
|
||||||
|
if node.LineComment == "" {
|
||||||
|
node.LineComment = changesToApply.LineComment
|
||||||
|
}
|
||||||
|
if node.FootComment == "" {
|
||||||
|
node.FootComment = changesToApply.FootComment
|
||||||
|
}
|
||||||
|
case AppendCommentsMergeStrategy:
|
||||||
|
if node.HeadComment == "" {
|
||||||
|
node.HeadComment = changesToApply.HeadComment
|
||||||
|
} else {
|
||||||
|
node.HeadComment = node.HeadComment + "\n" + changesToApply.HeadComment
|
||||||
|
}
|
||||||
|
if node.LineComment == "" {
|
||||||
|
node.LineComment = changesToApply.LineComment
|
||||||
|
} else {
|
||||||
|
node.LineComment = node.LineComment + " " + changesToApply.LineComment
|
||||||
|
}
|
||||||
|
if node.FootComment == "" {
|
||||||
|
node.FootComment = changesToApply.FootComment
|
||||||
|
} else {
|
||||||
|
node.FootComment = node.FootComment + "\n" + changesToApply.FootComment
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug("result")
|
||||||
|
DebugNode(node)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,9 @@ type NodeContext struct {
|
|||||||
Head interface{}
|
Head interface{}
|
||||||
Tail []interface{}
|
Tail []interface{}
|
||||||
PathStack []interface{}
|
PathStack []interface{}
|
||||||
|
// middle nodes are nodes that match along the original path, but not a
|
||||||
|
// target match of the path. This is only relevant when ShouldOnlyDeeplyVisitLeaves is false.
|
||||||
|
IsMiddleNode bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNodeContext(node *yaml.Node, head interface{}, tail []interface{}, pathStack []interface{}) NodeContext {
|
func NewNodeContext(node *yaml.Node, head interface{}, tail []interface{}, pathStack []interface{}) NodeContext {
|
||||||
@@ -62,19 +65,32 @@ func (ns *NavigationStrategyImpl) GetVisitedNodes() []*NodeContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ns *NavigationStrategyImpl) FollowAlias(nodeContext NodeContext) bool {
|
func (ns *NavigationStrategyImpl) FollowAlias(nodeContext NodeContext) bool {
|
||||||
return ns.followAlias(nodeContext)
|
if ns.followAlias != nil {
|
||||||
|
return ns.followAlias(nodeContext)
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *NavigationStrategyImpl) AutoCreateMap(nodeContext NodeContext) bool {
|
func (ns *NavigationStrategyImpl) AutoCreateMap(nodeContext NodeContext) bool {
|
||||||
return ns.autoCreateMap(nodeContext)
|
if ns.autoCreateMap != nil {
|
||||||
|
return ns.autoCreateMap(nodeContext)
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *NavigationStrategyImpl) ShouldDeeplyTraverse(nodeContext NodeContext) bool {
|
func (ns *NavigationStrategyImpl) ShouldDeeplyTraverse(nodeContext NodeContext) bool {
|
||||||
return ns.shouldDeeplyTraverse(nodeContext)
|
if ns.shouldDeeplyTraverse != nil {
|
||||||
|
return ns.shouldDeeplyTraverse(nodeContext)
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *NavigationStrategyImpl) ShouldOnlyDeeplyVisitLeaves(nodeContext NodeContext) bool {
|
func (ns *NavigationStrategyImpl) ShouldOnlyDeeplyVisitLeaves(nodeContext NodeContext) bool {
|
||||||
return ns.shouldOnlyDeeplyVisitLeaves(nodeContext)
|
if ns.shouldOnlyDeeplyVisitLeaves != nil {
|
||||||
|
return ns.shouldOnlyDeeplyVisitLeaves(nodeContext)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ns *NavigationStrategyImpl) ShouldTraverse(nodeContext NodeContext, nodeKey string) bool {
|
func (ns *NavigationStrategyImpl) ShouldTraverse(nodeContext NodeContext, nodeKey string) bool {
|
||||||
|
|||||||
37
pkg/yqlib/read_for_merge_navigation_strategy.go
Normal file
37
pkg/yqlib/read_for_merge_navigation_strategy.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package yqlib
|
||||||
|
|
||||||
|
import "gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
func ReadForMergeNavigationStrategy(arrayMergeStrategy ArrayMergeStrategy) NavigationStrategy {
|
||||||
|
return &NavigationStrategyImpl{
|
||||||
|
visitedNodes: []*NodeContext{},
|
||||||
|
pathParser: NewPathParser(),
|
||||||
|
followAlias: func(nodeContext NodeContext) bool {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
shouldOnlyDeeplyVisitLeaves: func(nodeContext NodeContext) bool {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
visit: func(nodeContext NodeContext) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
shouldDeeplyTraverse: func(nodeContext NodeContext) bool {
|
||||||
|
if nodeContext.Node.Kind == yaml.SequenceNode && arrayMergeStrategy == OverwriteArrayMergeStrategy {
|
||||||
|
nodeContext.IsMiddleNode = false
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var isInArray = false
|
||||||
|
if len(nodeContext.PathStack) > 0 {
|
||||||
|
var lastElement = nodeContext.PathStack[len(nodeContext.PathStack)-1]
|
||||||
|
switch lastElement.(type) {
|
||||||
|
case int:
|
||||||
|
isInArray = true
|
||||||
|
default:
|
||||||
|
isInArray = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arrayMergeStrategy == UpdateArrayMergeStrategy || !isInArray
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,33 +1,11 @@
|
|||||||
package yqlib
|
package yqlib
|
||||||
|
|
||||||
func ReadNavigationStrategy(deeplyTraverseArrays bool) NavigationStrategy {
|
func ReadNavigationStrategy() NavigationStrategy {
|
||||||
return &NavigationStrategyImpl{
|
return &NavigationStrategyImpl{
|
||||||
visitedNodes: []*NodeContext{},
|
visitedNodes: []*NodeContext{},
|
||||||
pathParser: NewPathParser(),
|
pathParser: NewPathParser(),
|
||||||
followAlias: func(nodeContext NodeContext) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
autoCreateMap: func(nodeContext NodeContext) bool {
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
visit: func(nodeContext NodeContext) error {
|
visit: func(nodeContext NodeContext) error {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
shouldDeeplyTraverse: func(nodeContext NodeContext) bool {
|
|
||||||
var isInArray = false
|
|
||||||
if len(nodeContext.PathStack) > 0 {
|
|
||||||
var lastElement = nodeContext.PathStack[len(nodeContext.PathStack)-1]
|
|
||||||
switch lastElement.(type) {
|
|
||||||
case int:
|
|
||||||
isInArray = true
|
|
||||||
default:
|
|
||||||
isInArray = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return deeplyTraverseArrays || !isInArray
|
|
||||||
},
|
|
||||||
shouldOnlyDeeplyVisitLeaves: func(nodeContext NodeContext) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,6 @@ func UpdateNavigationStrategy(updateCommand UpdateCommand, autoCreate bool) Navi
|
|||||||
autoCreateMap: func(nodeContext NodeContext) bool {
|
autoCreateMap: func(nodeContext NodeContext) bool {
|
||||||
return autoCreate
|
return autoCreate
|
||||||
},
|
},
|
||||||
shouldDeeplyTraverse: func(nodeContext NodeContext) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
shouldOnlyDeeplyVisitLeaves: func(nodeContext NodeContext) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
visit: func(nodeContext NodeContext) error {
|
visit: func(nodeContext NodeContext) error {
|
||||||
node := nodeContext.Node
|
node := nodeContext.Node
|
||||||
changesToApply := updateCommand.Value
|
changesToApply := updateCommand.Value
|
||||||
@@ -30,12 +24,16 @@ func UpdateNavigationStrategy(updateCommand UpdateCommand, autoCreate bool) Navi
|
|||||||
node.Tag = changesToApply.Tag
|
node.Tag = changesToApply.Tag
|
||||||
node.Kind = changesToApply.Kind
|
node.Kind = changesToApply.Kind
|
||||||
node.Style = changesToApply.Style
|
node.Style = changesToApply.Style
|
||||||
node.Content = changesToApply.Content
|
if !updateCommand.DontUpdateNodeContent {
|
||||||
|
node.Content = changesToApply.Content
|
||||||
|
}
|
||||||
node.Anchor = changesToApply.Anchor
|
node.Anchor = changesToApply.Anchor
|
||||||
node.Alias = changesToApply.Alias
|
node.Alias = changesToApply.Alias
|
||||||
node.HeadComment = changesToApply.HeadComment
|
if updateCommand.CommentsMergeStrategy != IgnoreCommentsMergeStrategy {
|
||||||
node.LineComment = changesToApply.LineComment
|
node.HeadComment = changesToApply.HeadComment
|
||||||
node.FootComment = changesToApply.FootComment
|
node.LineComment = changesToApply.LineComment
|
||||||
|
node.FootComment = changesToApply.FootComment
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Debug("skipping update as node already has value %v and overwriteFlag is ", node.Value, updateCommand.Overwrite)
|
log.Debug("skipping update as node already has value %v and overwriteFlag is ", node.Value, updateCommand.Overwrite)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
brew install mkdocs libyaml
|
|
||||||
pip3 install markdown-include
|
|
||||||
pip3 install mkdocs-material
|
|
||||||
|
|
||||||
@@ -3,9 +3,10 @@
|
|||||||
# This assumes that gonative and gox is installed as per the 'one time setup' instructions
|
# This assumes that gonative and gox is installed as per the 'one time setup' instructions
|
||||||
# at https://github.com/inconshreveable/gonative
|
# at https://github.com/inconshreveable/gonative
|
||||||
|
|
||||||
gox -ldflags "${LDFLAGS}" -output="build/yq_{{.OS}}_{{.Arch}}"
|
|
||||||
|
CGO_ENABLED=0 gox -ldflags "${LDFLAGS}" -output="build/yq_{{.OS}}_{{.Arch}}"
|
||||||
# include non-default linux builds too
|
# include non-default linux builds too
|
||||||
gox -ldflags "${LDFLAGS}" -os=linux -output="build/yq_{{.OS}}_{{.Arch}}"
|
CGO_ENABLED=0 gox -ldflags "${LDFLAGS}" -os=linux -output="build/yq_{{.OS}}_{{.Arch}}"
|
||||||
|
|
||||||
cd build
|
cd build
|
||||||
rhash -r -a . -P -o checksums
|
rhash -r -a . -P -o checksums
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: yq
|
name: yq
|
||||||
version: '3.3.2'
|
version: '3.4.0'
|
||||||
summary: A lightweight and portable command-line YAML processor
|
summary: A lightweight and portable command-line YAML processor
|
||||||
description: |
|
description: |
|
||||||
The aim of the project is to be the jq or sed of yaml files.
|
The aim of the project is to be the jq or sed of yaml files.
|
||||||
@@ -16,7 +16,7 @@ apps:
|
|||||||
parts:
|
parts:
|
||||||
yq:
|
yq:
|
||||||
plugin: go
|
plugin: go
|
||||||
go-channel: 1.14/stable
|
go-channel: 1.15/stable
|
||||||
source: .
|
source: .
|
||||||
source-type: git
|
source-type: git
|
||||||
go-importpath: github.com/mikefarah/yq
|
go-importpath: github.com/mikefarah/yq
|
||||||
|
|||||||
Reference in New Issue
Block a user