1
0
mirror of https://github.com/taigrr/yq synced 2025-01-18 04:53:17 -08:00

Compare commits

..

11 Commits
3.1.1 ... 3.1.2

Author SHA1 Message Date
Mike Farah
2bd2a85a4c Fixed trailing empty docs 2020-02-21 11:37:59 +11:00
Mike Farah
ceb76e5c17 Fixed trailing empty docs 2020-02-21 11:34:26 +11:00
Mike Farah
44322f0248 Fixed writing to null document 2020-02-21 11:02:10 +11:00
Mike Farah
0347516d82 Always print new line so wc works properly 2020-02-21 10:29:37 +11:00
Mike Farah
a46386e093 Fixed special characters in path for merging 2020-02-18 20:18:49 +11:00
Mike Farah
f5c3beb159 Added test for https://github.com/mikefarah/yq/issues/361 2020-02-18 20:02:09 +11:00
Mike Farah
9864afc4e7 Fixed empty merge problem 2020-02-18 09:15:46 +11:00
Roberto Mier Escandon
69fae2d9cb Inc Deb version 2020-02-17 09:29:02 +11:00
Mike Farah
83c13ce392 Fixed empty merge problem - need to visit empty arrays and objects 2020-02-13 14:56:58 +11:00
Mike Farah
d83c46eec2 Uncomment line in publish script 2020-02-13 10:22:52 +11:00
Mike Farah
65802f9e0e updated readme 2020-02-12 16:28:24 +11:00
13 changed files with 254 additions and 79 deletions

View File

@@ -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

View File

@@ -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")

View File

@@ -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 {

View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -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=

View File

@@ -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
} }

View File

@@ -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)

View File

@@ -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

View File

@@ -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.