mirror of
https://github.com/taigrr/yq
synced 2025-01-18 04:53:17 -08:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bd2a85a4c | ||
|
|
ceb76e5c17 | ||
|
|
44322f0248 | ||
|
|
0347516d82 | ||
|
|
a46386e093 | ||
|
|
f5c3beb159 | ||
|
|
9864afc4e7 | ||
|
|
69fae2d9cb | ||
|
|
83c13ce392 | ||
|
|
d83c46eec2 | ||
|
|
65802f9e0e |
@@ -44,7 +44,8 @@ rm /etc/myfile.tmp
|
|||||||
```
|
```
|
||||||
|
|
||||||
### On Ubuntu 16.04 or higher from Debian package:
|
### On Ubuntu 16.04 or higher from Debian package:
|
||||||
```
|
```sh
|
||||||
|
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys CC86BB64
|
||||||
sudo add-apt-repository ppa:rmescandon/yq
|
sudo add-apt-repository ppa:rmescandon/yq
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install yq -y
|
sudo apt install yq -y
|
||||||
@@ -125,8 +126,6 @@ Use "yq [command] --help" for more information about a command.
|
|||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
**Note: v3 is currently in progress - for the moment I won't be accepting new feature PRs until v3 is ready :)**
|
|
||||||
|
|
||||||
1. `scripts/devtools.sh`
|
1. `scripts/devtools.sh`
|
||||||
2. `make [local] vendor`
|
2. `make [local] vendor`
|
||||||
3. add unit tests
|
3. add unit tests
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ func TestReadCmd(t *testing.T) {
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
test.AssertResult(t, "2", result.Output)
|
test.AssertResult(t, "2\n", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompareCmd(t *testing.T) {
|
func TestCompareCmd(t *testing.T) {
|
||||||
@@ -157,7 +157,7 @@ func TestReadWithAdvancedFilterCmd(t *testing.T) {
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
test.AssertResult(t, "4", result.Output)
|
test.AssertResult(t, "4\n", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadWithAdvancedFilterMapCmd(t *testing.T) {
|
func TestReadWithAdvancedFilterMapCmd(t *testing.T) {
|
||||||
@@ -226,7 +226,7 @@ func TestReadWithKeyCmd(t *testing.T) {
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
test.AssertResult(t, "b.c", result.Output)
|
test.AssertResult(t, "b.c\n", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadAnchorsCmd(t *testing.T) {
|
func TestReadAnchorsCmd(t *testing.T) {
|
||||||
@@ -235,7 +235,7 @@ func TestReadAnchorsCmd(t *testing.T) {
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
test.AssertResult(t, "1", result.Output)
|
test.AssertResult(t, "1\n", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadAnchorsWithKeyAndValueCmd(t *testing.T) {
|
func TestReadAnchorsWithKeyAndValueCmd(t *testing.T) {
|
||||||
@@ -279,7 +279,7 @@ func TestReadMergeAnchorsOriginalCmd(t *testing.T) {
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
test.AssertResult(t, "original", result.Output)
|
test.AssertResult(t, "original\n", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadMergeAnchorsExplodeJsonCmd(t *testing.T) {
|
func TestReadMergeAnchorsExplodeJsonCmd(t *testing.T) {
|
||||||
@@ -318,7 +318,7 @@ pointer: *value-pointer`
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
expectedOutput := `the value`
|
expectedOutput := "the value\n"
|
||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,7 +378,7 @@ pointer: *value-pointer`
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
expectedOutput := `the value`
|
expectedOutput := "the value\n"
|
||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,7 +433,7 @@ func TestReadMergeAnchorsOverrideCmd(t *testing.T) {
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
test.AssertResult(t, "ice", result.Output)
|
test.AssertResult(t, "ice\n", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadMergeAnchorsPrefixMatchCmd(t *testing.T) {
|
func TestReadMergeAnchorsPrefixMatchCmd(t *testing.T) {
|
||||||
@@ -455,7 +455,7 @@ func TestReadMergeAnchorsListOriginalCmd(t *testing.T) {
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
test.AssertResult(t, "original", result.Output)
|
test.AssertResult(t, "original\n", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadMergeAnchorsListOverrideInListCmd(t *testing.T) {
|
func TestReadMergeAnchorsListOverrideInListCmd(t *testing.T) {
|
||||||
@@ -464,7 +464,7 @@ func TestReadMergeAnchorsListOverrideInListCmd(t *testing.T) {
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
test.AssertResult(t, "coconut", result.Output)
|
test.AssertResult(t, "coconut\n", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadMergeAnchorsListOverrideCmd(t *testing.T) {
|
func TestReadMergeAnchorsListOverrideCmd(t *testing.T) {
|
||||||
@@ -473,7 +473,7 @@ func TestReadMergeAnchorsListOverrideCmd(t *testing.T) {
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
test.AssertResult(t, "newbar", result.Output)
|
test.AssertResult(t, "newbar\n", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadInvalidDocumentIndexCmd(t *testing.T) {
|
func TestReadInvalidDocumentIndexCmd(t *testing.T) {
|
||||||
@@ -515,7 +515,7 @@ func TestReadMultiCmd(t *testing.T) {
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
test.AssertResult(t, "here", result.Output)
|
test.AssertResult(t, "here\n", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadMultiWithKeyAndValueCmd(t *testing.T) {
|
func TestReadMultiWithKeyAndValueCmd(t *testing.T) {
|
||||||
@@ -536,7 +536,8 @@ func TestReadMultiAllCmd(t *testing.T) {
|
|||||||
test.AssertResult(t,
|
test.AssertResult(t,
|
||||||
`first document
|
`first document
|
||||||
second document
|
second document
|
||||||
third document`, result.Output)
|
third document
|
||||||
|
`, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadMultiAllWithKeyAndValueCmd(t *testing.T) {
|
func TestReadMultiAllWithKeyAndValueCmd(t *testing.T) {
|
||||||
@@ -558,7 +559,7 @@ func TestReadCmd_ArrayYaml(t *testing.T) {
|
|||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
test.AssertResult(t, "false", result.Output)
|
test.AssertResult(t, "false\n", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReadEmptyContentCmd(t *testing.T) {
|
func TestReadEmptyContentCmd(t *testing.T) {
|
||||||
@@ -575,6 +576,28 @@ func TestReadEmptyContentCmd(t *testing.T) {
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReadEmptyNodesPrintPathCmd(t *testing.T) {
|
||||||
|
content := `map:
|
||||||
|
that: {}
|
||||||
|
array:
|
||||||
|
great: []
|
||||||
|
null:
|
||||||
|
indeed: ~`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("read %s -ppv **", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `map.that: {}
|
||||||
|
array.great: []
|
||||||
|
null.indeed: ~
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestReadEmptyContentWithDefaultValueCmd(t *testing.T) {
|
func TestReadEmptyContentWithDefaultValueCmd(t *testing.T) {
|
||||||
content := ``
|
content := ``
|
||||||
filename := test.WriteTempYamlFile(content)
|
filename := test.WriteTempYamlFile(content)
|
||||||
@@ -718,7 +741,8 @@ func TestReadCmd_ArrayYaml_SplatWithKeyCmd(t *testing.T) {
|
|||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
expectedOutput := `[0]
|
expectedOutput := `[0]
|
||||||
[1]`
|
[1]
|
||||||
|
`
|
||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -729,7 +753,8 @@ func TestReadCmd_ArrayYaml_SplatKey(t *testing.T) {
|
|||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
expectedOutput := `false
|
expectedOutput := `false
|
||||||
true`
|
true
|
||||||
|
`
|
||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -928,7 +953,8 @@ b:
|
|||||||
}
|
}
|
||||||
|
|
||||||
expectedOutput := `more things
|
expectedOutput := `more things
|
||||||
more things also`
|
more things also
|
||||||
|
`
|
||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -983,7 +1009,8 @@ b:
|
|||||||
}
|
}
|
||||||
|
|
||||||
expectedOutput := `b.there.c
|
expectedOutput := `b.there.c
|
||||||
b.there2.c`
|
b.there2.c
|
||||||
|
`
|
||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1218,6 +1245,56 @@ func TestWriteCmd(t *testing.T) {
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWriteEmptyMultiDocCmd(t *testing.T) {
|
||||||
|
content := `# this is empty
|
||||||
|
---
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s c 7", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `c: 7
|
||||||
|
|
||||||
|
# this is empty
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteSurroundingEmptyMultiDocCmd(t *testing.T) {
|
||||||
|
content := `---
|
||||||
|
# empty
|
||||||
|
---
|
||||||
|
cat: frog
|
||||||
|
---
|
||||||
|
|
||||||
|
# empty
|
||||||
|
`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s -d1 c 7", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `
|
||||||
|
|
||||||
|
# empty
|
||||||
|
---
|
||||||
|
cat: frog
|
||||||
|
c: 7
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
# empty
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestWriteFromFileCmd(t *testing.T) {
|
func TestWriteFromFileCmd(t *testing.T) {
|
||||||
content := `b:
|
content := `b:
|
||||||
c: 3
|
c: 3
|
||||||
@@ -1257,6 +1334,26 @@ func TestWriteEmptyCmd(t *testing.T) {
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWriteAutoCreateCmd(t *testing.T) {
|
||||||
|
content := `applications:
|
||||||
|
- name: app
|
||||||
|
env:`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("write %s applications[0].env.hello world", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `applications:
|
||||||
|
- name: app
|
||||||
|
env:
|
||||||
|
hello: world
|
||||||
|
`
|
||||||
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestWriteCmdScript(t *testing.T) {
|
func TestWriteCmdScript(t *testing.T) {
|
||||||
content := `b:
|
content := `b:
|
||||||
c: 3
|
c: 3
|
||||||
@@ -1559,7 +1656,7 @@ func TestWriteCmd_SplatMapEmpty(t *testing.T) {
|
|||||||
t.Error(result.Error)
|
t.Error(result.Error)
|
||||||
}
|
}
|
||||||
expectedOutput := `b:
|
expectedOutput := `b:
|
||||||
c: thing
|
c: {}
|
||||||
d: another thing
|
d: another thing
|
||||||
`
|
`
|
||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
@@ -1957,6 +2054,27 @@ apples: red
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMergeSpecialCharacterKeysCmd(t *testing.T) {
|
||||||
|
content := ``
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeContent := `key[bracket]: value
|
||||||
|
key.bracket: value
|
||||||
|
key"value": value
|
||||||
|
key'value': value
|
||||||
|
`
|
||||||
|
mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||||
|
defer test.RemoveTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("merge %s %s", filename, mergeFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
test.AssertResult(t, mergeContent, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestMergeYamlMultiAllOverwriteCmd(t *testing.T) {
|
func TestMergeYamlMultiAllOverwriteCmd(t *testing.T) {
|
||||||
content := `b:
|
content := `b:
|
||||||
c: 3
|
c: 3
|
||||||
@@ -1987,6 +2105,25 @@ apples: red
|
|||||||
test.AssertResult(t, expectedOutput, result.Output)
|
test.AssertResult(t, expectedOutput, result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMergeYamlNullMapCmd(t *testing.T) {
|
||||||
|
content := `b:`
|
||||||
|
filename := test.WriteTempYamlFile(content)
|
||||||
|
defer test.RemoveTempYamlFile(filename)
|
||||||
|
|
||||||
|
mergeContent := `b:
|
||||||
|
thing: a frog
|
||||||
|
`
|
||||||
|
mergeFilename := test.WriteTempYamlFile(mergeContent)
|
||||||
|
defer test.RemoveTempYamlFile(mergeFilename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := test.RunCmd(cmd, fmt.Sprintf("merge %s %s", filename, mergeFilename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
test.AssertResult(t, mergeContent, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
func TestMergeCmd_Error(t *testing.T) {
|
func TestMergeCmd_Error(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := test.RunCmd(cmd, "merge")
|
result := test.RunCmd(cmd, "merge")
|
||||||
|
|||||||
30
cmd/utils.go
30
cmd/utils.go
@@ -79,7 +79,7 @@ func appendDocument(originalMatchingNodes []*yqlib.NodeContext, dataBucket yaml.
|
|||||||
|
|
||||||
func printValue(node *yaml.Node, writer io.Writer) error {
|
func printValue(node *yaml.Node, writer io.Writer) error {
|
||||||
if node.Kind == yaml.ScalarNode {
|
if node.Kind == yaml.ScalarNode {
|
||||||
_, errorWriting := writer.Write([]byte(node.Value))
|
_, errorWriting := writer.Write([]byte(node.Value + "\n"))
|
||||||
return errorWriting
|
return errorWriting
|
||||||
}
|
}
|
||||||
return printNode(node, writer)
|
return printNode(node, writer)
|
||||||
@@ -160,19 +160,13 @@ func printResults(matchingNodes []*yqlib.NodeContext, writer io.Writer) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var errorWriting error
|
var errorWriting error
|
||||||
for index, mappedDoc := range matchingNodes {
|
for _, mappedDoc := range matchingNodes {
|
||||||
switch printMode {
|
switch printMode {
|
||||||
case "p":
|
case "p":
|
||||||
errorWriting = writeString(bufferedWriter, lib.PathStackToString(mappedDoc.PathStack))
|
errorWriting = writeString(bufferedWriter, lib.PathStackToString(mappedDoc.PathStack)+"\n")
|
||||||
if errorWriting != nil {
|
if errorWriting != nil {
|
||||||
return errorWriting
|
return errorWriting
|
||||||
}
|
}
|
||||||
if index < len(matchingNodes)-1 {
|
|
||||||
errorWriting = writeString(bufferedWriter, "\n")
|
|
||||||
if errorWriting != nil {
|
|
||||||
return errorWriting
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "pv", "vp":
|
case "pv", "vp":
|
||||||
// put it into a node and print that.
|
// put it into a node and print that.
|
||||||
var parentNode = yaml.Node{Kind: yaml.MappingNode}
|
var parentNode = yaml.Node{Kind: yaml.MappingNode}
|
||||||
@@ -186,14 +180,6 @@ func printResults(matchingNodes []*yqlib.NodeContext, writer io.Writer) error {
|
|||||||
if err := printValue(mappedDoc.Node, bufferedWriter); err != nil {
|
if err := printValue(mappedDoc.Node, bufferedWriter); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Printing our Scalars does not print a new line at the end
|
|
||||||
// we only want to do that if there are more values (so users can easily script extraction of values in the yaml)
|
|
||||||
if index < len(matchingNodes)-1 && mappedDoc.Node.Kind == yaml.ScalarNode {
|
|
||||||
errorWriting = writeString(bufferedWriter, "\n")
|
|
||||||
if errorWriting != nil {
|
|
||||||
return errorWriting
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,6 +199,11 @@ func parseDocumentIndex() (bool, int, error) {
|
|||||||
|
|
||||||
type updateDataFn func(dataBucket *yaml.Node, currentIndex int) error
|
type updateDataFn func(dataBucket *yaml.Node, currentIndex int) error
|
||||||
|
|
||||||
|
func isNullDocument(dataBucket *yaml.Node) bool {
|
||||||
|
return dataBucket.Kind == yaml.DocumentNode && (len(dataBucket.Content) == 0 ||
|
||||||
|
dataBucket.Content[0].Kind == yaml.ScalarNode && dataBucket.Content[0].Tag == "!!null")
|
||||||
|
}
|
||||||
|
|
||||||
func mapYamlDecoder(updateData updateDataFn, encoder yqlib.Encoder) yamlDecoderFn {
|
func mapYamlDecoder(updateData updateDataFn, encoder yqlib.Encoder) yamlDecoderFn {
|
||||||
return func(decoder *yaml.Decoder) error {
|
return func(decoder *yaml.Decoder) error {
|
||||||
var dataBucket yaml.Node
|
var dataBucket yaml.Node
|
||||||
@@ -232,8 +223,11 @@ func mapYamlDecoder(updateData updateDataFn, encoder yqlib.Encoder) yamlDecoderF
|
|||||||
|
|
||||||
if errorReading == io.EOF && docIndexInt == 0 && currentIndex == 0 {
|
if errorReading == io.EOF && docIndexInt == 0 && currentIndex == 0 {
|
||||||
//empty document, lets just make one
|
//empty document, lets just make one
|
||||||
child := yaml.Node{Kind: yaml.MappingNode}
|
|
||||||
dataBucket = yaml.Node{Kind: yaml.DocumentNode, Content: make([]*yaml.Node, 1)}
|
dataBucket = yaml.Node{Kind: yaml.DocumentNode, Content: make([]*yaml.Node, 1)}
|
||||||
|
child := yaml.Node{Kind: yaml.MappingNode}
|
||||||
|
dataBucket.Content[0] = &child
|
||||||
|
} else if isNullDocument(&dataBucket) && (updateAll || docIndexInt == currentIndex) {
|
||||||
|
child := yaml.Node{Kind: yaml.MappingNode}
|
||||||
dataBucket.Content[0] = &child
|
dataBucket.Content[0] = &child
|
||||||
} else if errorReading == io.EOF {
|
} else if errorReading == io.EOF {
|
||||||
if !updateAll && currentIndex <= docIndexInt {
|
if !updateAll && currentIndex <= docIndexInt {
|
||||||
|
|||||||
@@ -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.1.1"
|
Version = "3.1.2"
|
||||||
|
|
||||||
// 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
|
||||||
|
|||||||
13
debian/changelog
vendored
13
debian/changelog
vendored
@@ -1,3 +1,16 @@
|
|||||||
|
yq (3.1.1) eoan; urgency=medium
|
||||||
|
|
||||||
|
* Keeps yaml comments and formatting, can specify yaml tags when updating.
|
||||||
|
* Handles anchors! https://github.com/mikefarah/yq/issues/310, https://github.com/mikefarah/yq/issues/178
|
||||||
|
* Can print out matching paths and values when splatting https://github.com/mikefarah/yq/issues/20
|
||||||
|
* JSON output works for all commands! Yaml files with multiple documents are printed out as one JSON document per line.
|
||||||
|
* Deep splat (**) to match arbitrary paths
|
||||||
|
* Update scripts file format has changed to be more powerful
|
||||||
|
* Reading and splatting, matching results are printed once per line
|
||||||
|
* Bugfixing
|
||||||
|
|
||||||
|
-- Roberto Mier Escandon <rmescandon@gmail.com> Tue, 11 Feb 2020 22:18:24 +0100
|
||||||
|
|
||||||
yq (2.2-1) bionic; urgency=medium
|
yq (2.2-1) bionic; urgency=medium
|
||||||
|
|
||||||
* Added Windows support for the "--inplace" command flag
|
* Added Windows support for the "--inplace" command flag
|
||||||
|
|||||||
21
debian/control
vendored
21
debian/control
vendored
@@ -1,22 +1,23 @@
|
|||||||
Source: yq
|
Source: yq
|
||||||
Section: devel
|
Section: devel
|
||||||
Priority: extra
|
Priority: optional
|
||||||
Maintainer: Roberto Mier EscandĂłn <rmescandon@gmail.com>
|
Maintainer: Roberto Mier EscandĂłn <rmescandon@gmail.com>
|
||||||
Build-Depends: debhelper (>= 9),
|
Build-Depends: debhelper (>=10),
|
||||||
dh-golang,
|
dh-golang (>=1.34),
|
||||||
golang-1.10-go,
|
golang-1.13,
|
||||||
|
dpkg-dev,
|
||||||
rsync
|
rsync
|
||||||
Standards-Version: 3.9.6
|
Standards-Version: 3.9.6
|
||||||
Homepage: https://github.com/mikefarah/yq.git
|
Homepage: https://github.com/mikefarah/yq.git
|
||||||
Vcs-Browser: https://github.com/mikefarah/yq.git
|
Vcs-Browser: https://github.com/mikefarah/yq.git
|
||||||
Vcs-Git: https://github.com/mikefarah/yq.git
|
Vcs-Git: https://github.com/mikefarah/yq.git
|
||||||
|
XS-Go-Import-Path: github.com/mikefarah/yq
|
||||||
|
XSBC-Original-Maintainer: Roberto Mier EscandĂłn <rmescandon@gmail.com>
|
||||||
|
|
||||||
Package: yq
|
Package: yq
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Built-Using: ${misc:Built-Using}
|
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||||
Depends: ${shlibs:Depends},
|
Description: a lightweight and portable command-line YAML processor
|
||||||
${misc:Depends}
|
|
||||||
Description:
|
|
||||||
a lightweight and portable command-line YAML processor
|
|
||||||
.
|
.
|
||||||
The aim of the project is to be the [jq](https://github.com/stedolan/jq) or sed of yaml files.
|
The aim of the project is to be the
|
||||||
|
[jq](https://github.com/stedolan/jq) or sed of yaml files.
|
||||||
|
|||||||
24
debian/rules
vendored
24
debian/rules
vendored
@@ -14,46 +14,46 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
PROJECT := yq
|
PROJECT := yq
|
||||||
OWNER := mikefarah
|
OWNER := mikefarah
|
||||||
REPO := github.com
|
REPO := github.com
|
||||||
GOVERSION := 1.10
|
GOVERSION := 1.13
|
||||||
|
|
||||||
export DH_OPTIONS
|
export DH_OPTIONS
|
||||||
export DH_GOPKG := ${REPO}/${OWNER}/${PROJECT}
|
export DH_GOPKG := ${REPO}/${OWNER}/${PROJECT}
|
||||||
export GOROOT := /usr/lib/go-${GOVERSION}
|
export GOROOT := /usr/lib/go-${GOVERSION}
|
||||||
export GOPATH := ${CURDIR}/_build
|
export GOPATH := ${CURDIR}/_build
|
||||||
export GOBIN := ${GOPATH}/bin
|
export GOBIN := ${GOPATH}/bin
|
||||||
export PATH := ${GOROOT}/bin:${GOBIN}:${PATH}
|
export PATH := ${GOROOT}/bin:${GOBIN}:${PATH}
|
||||||
BLDPATH := $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
|
export GOCACHE := /tmp/gocache
|
||||||
SRCDIR := ${CURDIR}/_build/src/${DH_GOPKG}
|
export GOFLAGS := -mod=vendor
|
||||||
|
|
||||||
|
SRCDIR := ${GOPATH}/src/${DH_GOPKG}
|
||||||
DESTDIR := ${CURDIR}/debian/${PROJECT}
|
DESTDIR := ${CURDIR}/debian/${PROJECT}
|
||||||
BINDIR := /usr/bin
|
BINDIR := /usr/bin
|
||||||
ASSETSDIR := /usr/share/${PROJECT}
|
ASSETSDIR := /usr/share/${PROJECT}
|
||||||
|
|
||||||
%:
|
%:
|
||||||
dh $@ --buildsystem=golang --with=golang
|
dh $@ --builddirectory=${GOPATH} --buildsystem=golang
|
||||||
|
|
||||||
override_dh_auto_build:
|
override_dh_auto_build:
|
||||||
mkdir -p ${SRCDIR}
|
mkdir -p ${SRCDIR}
|
||||||
mkdir -p ${GOBIN}
|
mkdir -p ${GOBIN}
|
||||||
# copy project to local srcdir to build from there
|
# copy project to local srcdir to build from there
|
||||||
rsync -avz --progress --exclude=obj-${BLDPATH} --exclude=debian . $(SRCDIR)
|
rsync -avz --progress --exclude=_build --exclude=debian --exclude=tmp. --exclude=go.mod . $(SRCDIR)
|
||||||
# build go code
|
# build go code
|
||||||
(cd ${SRCDIR} && go install ./...)
|
(cd ${SRCDIR} && go install -buildmode=pie ./...)
|
||||||
|
|
||||||
override_dh_auto_test:
|
override_dh_auto_test:
|
||||||
(cd ${SRCDIR} && go test -v ./...)
|
(cd ${SRCDIR} && go test -v ./...)
|
||||||
|
|
||||||
override_dh_auto_install:
|
override_dh_auto_install:
|
||||||
mkdir -p ${DESTDIR}/${BINDIR}
|
mkdir -p ${DESTDIR}/${BINDIR}
|
||||||
mkdir -p ${DESTDIR}/${ASSETSDIR}
|
mkdir -p ${DESTDIR}/${ASSETSDIR}
|
||||||
cp ${CURDIR}/_build/bin/yq ${DESTDIR}/${BINDIR}
|
cp ${GOBIN}/yq ${DESTDIR}/${BINDIR}
|
||||||
cp -rf ${SRCDIR}/LICENSE ${DESTDIR}/${ASSETSDIR}
|
cp -f ${SRCDIR}/LICENSE ${DESTDIR}/${ASSETSDIR}
|
||||||
cp -rf ${SRCDIR}/README.md ${DESTDIR}/${PLUGINSDIR}
|
|
||||||
chmod a+x ${DESTDIR}/${BINDIR}/yq
|
chmod a+x ${DESTDIR}/${BINDIR}/yq
|
||||||
|
|
||||||
override_dh_auto_clean:
|
override_dh_auto_clean:
|
||||||
dh_clean
|
dh_clean
|
||||||
rm -rf ${CURDIR}/obj-${BLDPATH}
|
|
||||||
rm -rf ${CURDIR}/_build
|
rm -rf ${CURDIR}/_build
|
||||||
|
|||||||
3
go.mod
3
go.mod
@@ -20,8 +20,7 @@ require (
|
|||||||
golang.org/x/tools v0.0.0-20191213221258-04c2e8eff935 // indirect
|
golang.org/x/tools v0.0.0-20191213221258-04c2e8eff935 // indirect
|
||||||
gopkg.in/imdario/mergo.v0 v0.3.7 // indirect
|
gopkg.in/imdario/mergo.v0 v0.3.7 // 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.v2 v2.2.8 // indirect
|
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71
|
||||||
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2
|
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.13
|
go 1.13
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -145,4 +145,6 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
|||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM=
|
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71 h1:Xe2gvTZUJpsvOWUnvmL/tmhVBZUmHSvLbMjRj6NUUKo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func (n *navigator) doTraverse(value *yaml.Node, head interface{}, tail []interf
|
|||||||
|
|
||||||
func (n *navigator) getOrReplace(original *yaml.Node, expectedKind yaml.Kind) *yaml.Node {
|
func (n *navigator) getOrReplace(original *yaml.Node, expectedKind yaml.Kind) *yaml.Node {
|
||||||
if original.Kind != expectedKind {
|
if original.Kind != expectedKind {
|
||||||
log.Debug("wanted %v but it was %v, overriding", expectedKind, original.Kind)
|
log.Debug("wanted %v but it was %v, overriding", KindString(expectedKind), KindString(original.Kind))
|
||||||
return &yaml.Node{Kind: expectedKind}
|
return &yaml.Node{Kind: expectedKind}
|
||||||
}
|
}
|
||||||
return original
|
return original
|
||||||
@@ -84,6 +84,8 @@ func (n *navigator) recurse(value *yaml.Node, head interface{}, tail []interface
|
|||||||
|
|
||||||
if head == "+" {
|
if head == "+" {
|
||||||
return n.appendArray(value, head, tail, pathStack)
|
return n.appendArray(value, head, tail, pathStack)
|
||||||
|
} else if len(value.Content) == 0 && head == "**" {
|
||||||
|
return n.navigationStrategy.Visit(NewNodeContext(value, head, tail, pathStack))
|
||||||
}
|
}
|
||||||
return n.splatArray(value, head, tail, pathStack)
|
return n.splatArray(value, head, tail, pathStack)
|
||||||
}
|
}
|
||||||
@@ -111,7 +113,7 @@ func (n *navigator) recurseMap(value *yaml.Node, head string, tail []interface{}
|
|||||||
if n.navigationStrategy.ShouldTraverse(NewNodeContext(contents[indexInMap+1], head, tail, newPathStack), contents[indexInMap].Value) {
|
if n.navigationStrategy.ShouldTraverse(NewNodeContext(contents[indexInMap+1], head, tail, newPathStack), contents[indexInMap].Value) {
|
||||||
log.Debug("recurseMap: Going to traverse")
|
log.Debug("recurseMap: Going to traverse")
|
||||||
traversedEntry = true
|
traversedEntry = true
|
||||||
// contents[indexInMap+1] = n.getOrReplace(contents[indexInMap+1], guessKind(head, tail, contents[indexInMap+1].Kind))
|
contents[indexInMap+1] = n.getOrReplace(contents[indexInMap+1], guessKind(head, tail, contents[indexInMap+1].Kind))
|
||||||
errorTraversing := n.doTraverse(contents[indexInMap+1], head, tail, newPathStack)
|
errorTraversing := n.doTraverse(contents[indexInMap+1], head, tail, newPathStack)
|
||||||
log.Debug("recurseMap: Finished traversing")
|
log.Debug("recurseMap: Finished traversing")
|
||||||
n.navigationStrategy.DebugVisitedNodes()
|
n.navigationStrategy.DebugVisitedNodes()
|
||||||
@@ -126,7 +128,9 @@ func (n *navigator) recurseMap(value *yaml.Node, head string, tail []interface{}
|
|||||||
return errorVisiting
|
return errorVisiting
|
||||||
}
|
}
|
||||||
|
|
||||||
if traversedEntry || n.navigationStrategy.GetPathParser().IsPathExpression(head) || !n.navigationStrategy.AutoCreateMap(NewNodeContext(value, head, tail, pathStack)) {
|
if len(value.Content) == 0 && head == "**" {
|
||||||
|
return n.navigationStrategy.Visit(NewNodeContext(value, head, tail, pathStack))
|
||||||
|
} else if traversedEntry || n.navigationStrategy.GetPathParser().IsPathExpression(head) || !n.navigationStrategy.AutoCreateMap(NewNodeContext(value, head, tail, pathStack)) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,23 @@ type UpdateCommand struct {
|
|||||||
Overwrite bool
|
Overwrite bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func KindString(kind yaml.Kind) string {
|
||||||
|
switch kind {
|
||||||
|
case yaml.ScalarNode:
|
||||||
|
return "ScalarNode"
|
||||||
|
case yaml.SequenceNode:
|
||||||
|
return "SequenceNode"
|
||||||
|
case yaml.MappingNode:
|
||||||
|
return "MappingNode"
|
||||||
|
case yaml.DocumentNode:
|
||||||
|
return "DocumentNode"
|
||||||
|
case yaml.AliasNode:
|
||||||
|
return "AliasNode"
|
||||||
|
default:
|
||||||
|
return "unknown!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func DebugNode(value *yaml.Node) {
|
func DebugNode(value *yaml.Node) {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
log.Debug("-- node is nil --")
|
log.Debug("-- node is nil --")
|
||||||
@@ -30,7 +47,7 @@ func DebugNode(value *yaml.Node) {
|
|||||||
log.Error("Error debugging node, %v", errorEncoding.Error())
|
log.Error("Error debugging node, %v", errorEncoding.Error())
|
||||||
}
|
}
|
||||||
encoder.Close()
|
encoder.Close()
|
||||||
log.Debug("Tag: %v", value.Tag)
|
log.Debug("Tag: %v, Kind: %v", value.Tag, KindString(value.Kind))
|
||||||
log.Debug("%v", buf.String())
|
log.Debug("%v", buf.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,13 +71,20 @@ func mergePathStackToString(pathStack []interface{}, appendArrays bool) string {
|
|||||||
s := fmt.Sprintf("%v", path)
|
s := fmt.Sprintf("%v", path)
|
||||||
var _, errParsingInt = strconv.ParseInt(s, 10, 64) // nolint
|
var _, errParsingInt = strconv.ParseInt(s, 10, 64) // nolint
|
||||||
|
|
||||||
hasDot := strings.Contains(s, ".")
|
hasSpecial := strings.Contains(s, ".") || strings.Contains(s, "[") || strings.Contains(s, "]") || strings.Contains(s, "\"")
|
||||||
if hasDot || errParsingInt == nil {
|
hasDoubleQuotes := strings.Contains(s, "\"")
|
||||||
sb.WriteString("\"")
|
wrappingCharacterStart := "\""
|
||||||
|
wrappingCharacterEnd := "\""
|
||||||
|
if hasDoubleQuotes {
|
||||||
|
wrappingCharacterStart = "("
|
||||||
|
wrappingCharacterEnd = ")"
|
||||||
|
}
|
||||||
|
if hasSpecial || errParsingInt == nil {
|
||||||
|
sb.WriteString(wrappingCharacterStart)
|
||||||
}
|
}
|
||||||
sb.WriteString(s)
|
sb.WriteString(s)
|
||||||
if hasDot || errParsingInt == nil {
|
if hasSpecial || errParsingInt == nil {
|
||||||
sb.WriteString("\"")
|
sb.WriteString(wrappingCharacterEnd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,12 +115,14 @@ func guessKind(head interface{}, tail []interface{}, guess yaml.Kind) yaml.Kind
|
|||||||
return yaml.SequenceNode
|
return yaml.SequenceNode
|
||||||
}
|
}
|
||||||
pathParser := NewPathParser()
|
pathParser := NewPathParser()
|
||||||
if (pathParser.IsPathExpression(nextString) || head == "**") && (guess == yaml.SequenceNode || guess == yaml.MappingNode) {
|
if pathParser.IsPathExpression(nextString) && (guess == yaml.SequenceNode || guess == yaml.MappingNode) {
|
||||||
return guess
|
return guess
|
||||||
}
|
} else if guess == yaml.AliasNode {
|
||||||
if guess == yaml.AliasNode {
|
|
||||||
log.Debug("guess was an alias, okey doke.")
|
log.Debug("guess was an alias, okey doke.")
|
||||||
return guess
|
return guess
|
||||||
|
} else if head == "**" {
|
||||||
|
log.Debug("deep wildcard, go with the guess")
|
||||||
|
return guess
|
||||||
}
|
}
|
||||||
log.Debug("forcing a mapping node")
|
log.Debug("forcing a mapping node")
|
||||||
log.Debug("yaml.SequenceNode %v", guess == yaml.SequenceNode)
|
log.Debug("yaml.SequenceNode %v", guess == yaml.SequenceNode)
|
||||||
|
|||||||
@@ -32,5 +32,5 @@ upload() {
|
|||||||
done < <(find ./build -mindepth 1 -maxdepth 1 -print0)
|
done < <(find ./build -mindepth 1 -maxdepth 1 -print0)
|
||||||
}
|
}
|
||||||
|
|
||||||
# release
|
release
|
||||||
upload
|
upload
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: yq
|
name: yq
|
||||||
version: '3.1.1'
|
version: '3.1.2'
|
||||||
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.
|
||||||
|
|||||||
Reference in New Issue
Block a user