mirror of
https://github.com/taigrr/yq
synced 2025-01-18 04:53:17 -08:00
Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f9f8665dd | ||
|
|
3dea1efc03 | ||
|
|
547787f3ae | ||
|
|
3e83ff7ac8 | ||
|
|
f18c5161e0 | ||
|
|
eeeeeffd7b | ||
|
|
27604289f4 | ||
|
|
3f36a18791 | ||
|
|
5fc13bdccd | ||
|
|
95fec2984e | ||
|
|
64d1e58f97 | ||
|
|
4b3fbb878f | ||
|
|
26a09e6ec0 | ||
|
|
ceafed30f9 | ||
|
|
b8b2c9de61 | ||
|
|
f5fdf98c38 | ||
|
|
29986db8f8 | ||
|
|
1f4e3a9cde | ||
|
|
b6da773dde | ||
|
|
8020d4253b | ||
|
|
3c701fe98e | ||
|
|
97d1aa2b26 | ||
|
|
d05391e244 | ||
|
|
d1cec1ad18 | ||
|
|
fe5842e5f9 | ||
|
|
e0d8cd6bf6 | ||
|
|
8f5ffe47ff | ||
|
|
5acc1e661e | ||
|
|
a9c0ef571c | ||
|
|
7a28531f2f | ||
|
|
5de2bea1b4 | ||
|
|
7320b8d3c9 | ||
|
|
2f70e6f27a | ||
|
|
a9e871ee00 | ||
|
|
bc4bab9380 | ||
|
|
665d9079fa | ||
|
|
7b54a44fcf | ||
|
|
94148e4398 | ||
|
|
f8553162ca | ||
|
|
be532bf2fe | ||
|
|
e9b8265ca3 | ||
|
|
0f8b864321 | ||
|
|
e5bcfedbe9 | ||
|
|
a5f5fb2562 | ||
|
|
84de9c078d | ||
|
|
c7f5261036 | ||
|
|
6e35356a84 | ||
|
|
b2fe3e6738 | ||
|
|
774badfef4 | ||
|
|
c4e9516aa6 | ||
|
|
323089eb64 | ||
|
|
53289366a5 | ||
|
|
cda9a82906 | ||
|
|
2dbde6b9fb | ||
|
|
f8c1c3c1b4 | ||
|
|
238a1241d2 | ||
|
|
8a61ef072a | ||
|
|
4f178d2317 | ||
|
|
133e55105c | ||
|
|
5e5468af3b | ||
|
|
9b4972e46e | ||
|
|
23543ee031 | ||
|
|
75c7d40c44 | ||
|
|
44b8a5e80f | ||
|
|
77c8f22a79 | ||
|
|
386a0ca3c3 | ||
|
|
53a20d4421 | ||
|
|
478208b7c4 | ||
|
|
1159d0a212 |
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@@ -0,0 +1 @@
|
||||
bin
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -8,6 +8,7 @@ _obj
|
||||
_test
|
||||
bin
|
||||
build
|
||||
build-done
|
||||
.DS_Store
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
@@ -26,7 +27,7 @@ coverage.out
|
||||
*.test
|
||||
*.prof
|
||||
yaml
|
||||
vendor/*/
|
||||
vendor/
|
||||
tmp/
|
||||
cover/
|
||||
yq
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.9.x
|
||||
- 1.13.x
|
||||
script:
|
||||
- scripts/devtools.sh
|
||||
- make local build
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.9 as builder
|
||||
FROM golang:1.13 as builder
|
||||
|
||||
WORKDIR /go/src/mikefarah/yq
|
||||
|
||||
@@ -6,10 +6,6 @@ WORKDIR /go/src/mikefarah/yq
|
||||
COPY ./scripts/devtools.sh /go/src/mikefarah/yq/scripts/devtools.sh
|
||||
RUN ./scripts/devtools.sh
|
||||
|
||||
# cache vendor
|
||||
COPY ./vendor/vendor.json /go/src/mikefarah/yq/vendor/vendor.json
|
||||
RUN govendor sync
|
||||
|
||||
COPY . /go/src/mikefarah/yq
|
||||
|
||||
RUN CGO_ENABLED=0 make local build
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.9
|
||||
FROM golang:1.13
|
||||
|
||||
COPY scripts/devtools.sh /opt/devtools.sh
|
||||
|
||||
|
||||
10
Makefile
10
Makefile
@@ -14,8 +14,7 @@ help:
|
||||
@echo ' make build Build yq binary.'
|
||||
@echo ' make install Install yq.'
|
||||
@echo ' make xcompile Build cross-compiled binaries of yq.'
|
||||
@echo ' make snap Build a snap package of yq.'
|
||||
@echo ' make vendor Install dependencies using govendor.'
|
||||
@echo ' make vendor Install dependencies to vendor directory.'
|
||||
@echo ' make format Run code formatter.'
|
||||
@echo ' make check Run static code analysis (lint).'
|
||||
@echo ' make test Run tests on project.'
|
||||
@@ -65,10 +64,6 @@ xcompile: check
|
||||
@find build -type d -exec chmod 755 {} \; || :
|
||||
@find build -type f -exec chmod 755 {} \; || :
|
||||
|
||||
.PHONY: snap
|
||||
snap:
|
||||
snapcraft
|
||||
|
||||
.PHONY: install
|
||||
install: build
|
||||
${DOCKRUN} go install
|
||||
@@ -76,8 +71,7 @@ install: build
|
||||
# Each of the fetch should be an entry within vendor.json; not currently included within project
|
||||
.PHONY: vendor
|
||||
vendor: tmp/dev_image_id
|
||||
${DOCKRUN} govendor sync
|
||||
@chmod 664 vendor/vendor.json
|
||||
${DOCKRUN} go mod vendor
|
||||
|
||||
# ----------------------------------------------
|
||||
# develop and test
|
||||
|
||||
72
README.md
72
README.md
@@ -1,30 +1,63 @@
|
||||
# yq
|
||||
# yq
|
||||
|
||||
[](https://travis-ci.org/mikefarah/yq)  
|
||||
[](https://travis-ci.org/mikefarah/yq)   
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
## Major upgrade - V3 beta is out!
|
||||
|
||||
This addresses a number of features requests and issues that have been raised :)
|
||||
|
||||
Currently only available only available as a [binary release here](https://github.com/mikefarah/yq/releases/tag/3.0.0-beta) or via docker mikefarah/yq:3.0.0-beta!
|
||||
|
||||
It does have a few breaking changes listed on the [release page](https://github.com/mikefarah/yq/releases/tag/3.0.0-beta)
|
||||
|
||||
Looking forward to feedback - once this is out of beta it will be added to the remaining package managers, and be the default version downloaded (and merged into master).
|
||||
|
||||
V2 will no longer have any new features added, and will be moved to a branch (v2). It will have limited maintenance for bugs for a few months.
|
||||
|
||||
## Install
|
||||
On MacOS:
|
||||
|
||||
### On MacOS:
|
||||
```
|
||||
brew install yq
|
||||
```
|
||||
On Ubuntu and other Linux distros supporting `snap` packages:
|
||||
### On Ubuntu and other Linux distros supporting `snap` packages:
|
||||
```
|
||||
snap install yq
|
||||
```
|
||||
On Ubuntu 16.04 or higher from Debian package:
|
||||
|
||||
#### Snap notes
|
||||
`yq` installs with with [_strict confinement_](https://docs.snapcraft.io/snap-confinement/6233) in snap, this means it doesn't have direct access to root files. To read root files you can:
|
||||
|
||||
```
|
||||
sudo cat /etc/myfile | yq r - a.path
|
||||
```
|
||||
|
||||
And to write to a root file you can either use [sponge](https://linux.die.net/man/1/sponge):
|
||||
```
|
||||
sudo cat /etc/myfile | yq w - a.path value | sudo sponge /etc/myfile
|
||||
```
|
||||
or write to a temporary file:
|
||||
```
|
||||
sudo cat /etc/myfile | yq w - a.path value | sudo tee /etc/myfile.tmp
|
||||
sudo mv /etc/myfile.tmp /etc/myfile
|
||||
rm /etc/myfile.tmp
|
||||
```
|
||||
|
||||
### On Ubuntu 16.04 or higher from Debian package:
|
||||
```
|
||||
sudo add-apt-repository ppa:rmescandon/yq
|
||||
sudo apt update
|
||||
sudo apt install yq -y
|
||||
```
|
||||
or, [Download latest binary](https://github.com/mikefarah/yq/releases/latest) or alternatively:
|
||||
### or, [Download latest binary](https://github.com/mikefarah/yq/releases/latest) or alternatively:
|
||||
```
|
||||
go get gopkg.in/mikefarah/yq.v2
|
||||
GO111MODULE=on go get github.com/mikefarah/yq/v2
|
||||
```
|
||||
|
||||
## Run with Docker
|
||||
@@ -32,13 +65,21 @@ go get gopkg.in/mikefarah/yq.v2
|
||||
Oneshot use:
|
||||
|
||||
```bash
|
||||
docker run -v ${PWD}:/workdir mikefarah/yq yq [flags] <command> FILE...
|
||||
docker run --rm -v ${PWD}:/workdir mikefarah/yq yq [flags] <command> FILE...
|
||||
```
|
||||
|
||||
Run commands interactively:
|
||||
|
||||
```bash
|
||||
docker run -it -v ${PWD}:/workdir mikefarah/yq sh
|
||||
docker run --rm -it -v ${PWD}:/workdir mikefarah/yq sh
|
||||
```
|
||||
|
||||
It can be useful to have a bash function to avoid typing the whole docker command:
|
||||
|
||||
```bash
|
||||
yq() {
|
||||
docker run --rm -i -v ${PWD}:/workdir mikefarah/yq yq $@
|
||||
}
|
||||
```
|
||||
|
||||
## Features
|
||||
@@ -63,6 +104,8 @@ docker run -it -v ${PWD}:/workdir mikefarah/yq sh
|
||||
Check out the [documentation](http://mikefarah.github.io/yq/) for more detailed and advanced usage.
|
||||
|
||||
```
|
||||
yq is a lightweight and portable command-line YAML processor. It aims to be the jq or sed of yaml files.
|
||||
|
||||
Usage:
|
||||
yq [flags]
|
||||
yq [command]
|
||||
@@ -72,9 +115,9 @@ Available Commands:
|
||||
help Help about any command
|
||||
merge yq m [--inplace/-i] [--doc/-d index] [--overwrite/-x] [--append/-a] sample.yaml sample2.yaml
|
||||
new yq n [--script/-s script_file] a.b.c newValue
|
||||
prefix yq p [--inplace/-i] [--doc/-d index] sample.yaml a.b.c
|
||||
read yq r [--doc/-d index] sample.yaml a.b.c
|
||||
write yq w [--inplace/-i] [--script/-s script_file] [--doc/-d index] sample.yaml a.b.c newValue
|
||||
prefix yq p [--inplace/-i] [--doc/-d index] sample.yaml a.b.c
|
||||
|
||||
Flags:
|
||||
-h, --help help for yq
|
||||
@@ -86,13 +129,16 @@ Use "yq [command] --help" for more information about a command.
|
||||
```
|
||||
|
||||
## 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`
|
||||
2. `make [local] vendor`
|
||||
3. add unit tests
|
||||
4. apply changes (use govendor with a preference to [gopkg](https://gopkg.in/) for package dependencies)
|
||||
4. apply changes to go.mod
|
||||
5. `make [local] build`
|
||||
6. If required, update the user documentation
|
||||
6. If required, update the user documentation
|
||||
- Update README.md and/or documentation under the mkdocs folder
|
||||
- `make [local] build-docs`
|
||||
- browse to docs/index.html and check your changes
|
||||
- browse to docs/index.html and check your changes
|
||||
7. profit
|
||||
|
||||
631
commands_test.go
631
commands_test.go
File diff suppressed because it is too large
Load Diff
@@ -1,282 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
yaml "gopkg.in/mikefarah/yaml.v2"
|
||||
)
|
||||
|
||||
func entryInSlice(context yaml.MapSlice, key interface{}) *yaml.MapItem {
|
||||
for idx := range context {
|
||||
var entry = &context[idx]
|
||||
if entry.Key == key {
|
||||
return entry
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getMapSlice(context interface{}) yaml.MapSlice {
|
||||
var mapSlice yaml.MapSlice
|
||||
switch context.(type) {
|
||||
case yaml.MapSlice:
|
||||
mapSlice = context.(yaml.MapSlice)
|
||||
default:
|
||||
mapSlice = make(yaml.MapSlice, 0)
|
||||
}
|
||||
return mapSlice
|
||||
}
|
||||
|
||||
func getArray(context interface{}) (array []interface{}, ok bool) {
|
||||
switch context.(type) {
|
||||
case []interface{}:
|
||||
array = context.([]interface{})
|
||||
ok = true
|
||||
default:
|
||||
array = make([]interface{}, 0)
|
||||
ok = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func writeMap(context interface{}, paths []string, value interface{}) yaml.MapSlice {
|
||||
log.Debugf("writeMap for %v for %v with value %v\n", paths, context, value)
|
||||
|
||||
mapSlice := getMapSlice(context)
|
||||
|
||||
if len(paths) == 0 {
|
||||
return mapSlice
|
||||
}
|
||||
|
||||
child := entryInSlice(mapSlice, paths[0])
|
||||
if child == nil {
|
||||
newChild := yaml.MapItem{Key: paths[0]}
|
||||
mapSlice = append(mapSlice, newChild)
|
||||
child = entryInSlice(mapSlice, paths[0])
|
||||
log.Debugf("\tAppended child at %v for mapSlice %v\n", paths[0], mapSlice)
|
||||
}
|
||||
|
||||
log.Debugf("\tchild.Value %v\n", child.Value)
|
||||
|
||||
remainingPaths := paths[1:]
|
||||
child.Value = updatedChildValue(child.Value, remainingPaths, value)
|
||||
log.Debugf("\tReturning mapSlice %v\n", mapSlice)
|
||||
return mapSlice
|
||||
}
|
||||
|
||||
func updatedChildValue(child interface{}, remainingPaths []string, value interface{}) interface{} {
|
||||
if len(remainingPaths) == 0 {
|
||||
return value
|
||||
}
|
||||
|
||||
_, nextIndexErr := strconv.ParseInt(remainingPaths[0], 10, 64)
|
||||
if nextIndexErr != nil && remainingPaths[0] != "+" {
|
||||
// must be a map
|
||||
return writeMap(child, remainingPaths, value)
|
||||
}
|
||||
|
||||
// must be an array
|
||||
return writeArray(child, remainingPaths, value)
|
||||
}
|
||||
|
||||
func writeArray(context interface{}, paths []string, value interface{}) []interface{} {
|
||||
log.Debugf("writeArray for %v for %v with value %v\n", paths, context, value)
|
||||
array, _ := getArray(context)
|
||||
|
||||
if len(paths) == 0 {
|
||||
return array
|
||||
}
|
||||
|
||||
log.Debugf("\tarray %v\n", array)
|
||||
|
||||
rawIndex := paths[0]
|
||||
var index int64
|
||||
// the append array indicator
|
||||
if rawIndex == "+" {
|
||||
index = int64(len(array))
|
||||
} else {
|
||||
index, _ = strconv.ParseInt(rawIndex, 10, 64) // nolint
|
||||
// writeArray is only called by updatedChildValue which handles parsing the
|
||||
// index, as such this renders this dead code.
|
||||
}
|
||||
|
||||
for index >= int64(len(array)) {
|
||||
array = append(array, nil)
|
||||
}
|
||||
currentChild := array[index]
|
||||
|
||||
log.Debugf("\tcurrentChild %v\n", currentChild)
|
||||
|
||||
remainingPaths := paths[1:]
|
||||
array[index] = updatedChildValue(currentChild, remainingPaths, value)
|
||||
log.Debugf("\tReturning array %v\n", array)
|
||||
return array
|
||||
}
|
||||
|
||||
func readMap(context yaml.MapSlice, head string, tail []string) (interface{}, error) {
|
||||
if head == "*" {
|
||||
return readMapSplat(context, tail)
|
||||
}
|
||||
var value interface{}
|
||||
|
||||
entry := entryInSlice(context, head)
|
||||
if entry != nil {
|
||||
value = entry.Value
|
||||
}
|
||||
return calculateValue(value, tail)
|
||||
}
|
||||
|
||||
func readMapSplat(context yaml.MapSlice, tail []string) (interface{}, error) {
|
||||
var newArray = make([]interface{}, len(context))
|
||||
var i = 0
|
||||
for _, entry := range context {
|
||||
if len(tail) > 0 {
|
||||
val, err := recurse(entry.Value, tail[0], tail[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newArray[i] = val
|
||||
} else {
|
||||
newArray[i] = entry.Value
|
||||
}
|
||||
i++
|
||||
}
|
||||
return newArray, nil
|
||||
}
|
||||
|
||||
func recurse(value interface{}, head string, tail []string) (interface{}, error) {
|
||||
switch value.(type) {
|
||||
case []interface{}:
|
||||
if head == "*" {
|
||||
return readArraySplat(value.([]interface{}), tail)
|
||||
}
|
||||
index, err := strconv.ParseInt(head, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error accessing array: %v", err)
|
||||
}
|
||||
return readArray(value.([]interface{}), index, tail)
|
||||
case yaml.MapSlice:
|
||||
return readMap(value.(yaml.MapSlice), head, tail)
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func readArray(array []interface{}, head int64, tail []string) (interface{}, error) {
|
||||
if head >= int64(len(array)) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
value := array[head]
|
||||
return calculateValue(value, tail)
|
||||
}
|
||||
|
||||
func readArraySplat(array []interface{}, tail []string) (interface{}, error) {
|
||||
var newArray = make([]interface{}, len(array))
|
||||
for index, value := range array {
|
||||
val, err := calculateValue(value, tail)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newArray[index] = val
|
||||
}
|
||||
return newArray, nil
|
||||
}
|
||||
|
||||
func calculateValue(value interface{}, tail []string) (interface{}, error) {
|
||||
if len(tail) > 0 {
|
||||
return recurse(value, tail[0], tail[1:])
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func deleteMap(context interface{}, paths []string) yaml.MapSlice {
|
||||
log.Debugf("deleteMap for %v for %v\n", paths, context)
|
||||
|
||||
mapSlice := getMapSlice(context)
|
||||
|
||||
if len(paths) == 0 {
|
||||
return mapSlice
|
||||
}
|
||||
|
||||
var found bool
|
||||
var index int
|
||||
var child yaml.MapItem
|
||||
for index, child = range mapSlice {
|
||||
if child.Key == paths[0] {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return mapSlice
|
||||
}
|
||||
|
||||
remainingPaths := paths[1:]
|
||||
|
||||
var newSlice yaml.MapSlice
|
||||
if len(remainingPaths) > 0 {
|
||||
newChild := yaml.MapItem{Key: child.Key}
|
||||
newChild.Value = deleteChildValue(child.Value, remainingPaths)
|
||||
|
||||
newSlice = make(yaml.MapSlice, len(mapSlice))
|
||||
for i := range mapSlice {
|
||||
item := mapSlice[i]
|
||||
if i == index {
|
||||
item = newChild
|
||||
}
|
||||
newSlice[i] = item
|
||||
}
|
||||
} else {
|
||||
// Delete item from slice at index
|
||||
newSlice = append(mapSlice[:index], mapSlice[index+1:]...)
|
||||
log.Debugf("\tDeleted item index %d from mapSlice", index)
|
||||
}
|
||||
|
||||
log.Debugf("\t\tlen: %d\tcap: %d\tslice: %v", len(mapSlice), cap(mapSlice), mapSlice)
|
||||
log.Debugf("\tReturning mapSlice %v\n", mapSlice)
|
||||
return newSlice
|
||||
}
|
||||
|
||||
func deleteArray(context interface{}, paths []string, index int64) interface{} {
|
||||
log.Debugf("deleteArray for %v for %v\n", paths, context)
|
||||
|
||||
array, ok := getArray(context)
|
||||
if !ok {
|
||||
// did not get an array
|
||||
return context
|
||||
}
|
||||
|
||||
if index >= int64(len(array)) {
|
||||
return array
|
||||
}
|
||||
|
||||
remainingPaths := paths[1:]
|
||||
if len(remainingPaths) > 0 {
|
||||
// Recurse into the array element at index
|
||||
array[index] = deleteMap(array[index], remainingPaths)
|
||||
} else {
|
||||
// Delete the array element at index
|
||||
array = append(array[:index], array[index+1:]...)
|
||||
log.Debugf("\tDeleted item index %d from array, leaving %v", index, array)
|
||||
}
|
||||
|
||||
log.Debugf("\tReturning array: %v\n", array)
|
||||
return array
|
||||
}
|
||||
|
||||
func deleteChildValue(child interface{}, remainingPaths []string) interface{} {
|
||||
log.Debugf("deleteChildValue for %v for %v\n", remainingPaths, child)
|
||||
|
||||
idx, nextIndexErr := strconv.ParseInt(remainingPaths[0], 10, 64)
|
||||
if nextIndexErr != nil {
|
||||
// must be a map
|
||||
log.Debugf("\tdetected a map, invoking deleteMap\n")
|
||||
return deleteMap(child, remainingPaths)
|
||||
}
|
||||
|
||||
log.Debugf("\tdetected an array, so traversing element with index %d\n", idx)
|
||||
return deleteArray(child, remainingPaths, idx)
|
||||
}
|
||||
@@ -1,387 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
yaml "gopkg.in/mikefarah/yaml.v2"
|
||||
)
|
||||
|
||||
func TestReadMap_simple(t *testing.T) {
|
||||
var data = parseData(`
|
||||
---
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
got, _ := readMap(data, "b", []string{"c"})
|
||||
assertResult(t, 2, got)
|
||||
}
|
||||
|
||||
func TestReadMap_splat(t *testing.T) {
|
||||
var data = parseData(`
|
||||
---
|
||||
mapSplat:
|
||||
item1: things
|
||||
item2: whatever
|
||||
`)
|
||||
res, _ := readMap(data, "mapSplat", []string{"*"})
|
||||
result := res.([]interface{})
|
||||
var actual = []string{result[0].(string), result[1].(string)}
|
||||
sort.Strings(actual)
|
||||
assertResult(t, "[things whatever]", fmt.Sprintf("%v", actual))
|
||||
}
|
||||
|
||||
func TestReadMap_deep_splat(t *testing.T) {
|
||||
var data = parseData(`
|
||||
---
|
||||
mapSplatDeep:
|
||||
item1:
|
||||
cats: bananas
|
||||
item2:
|
||||
cats: apples
|
||||
`)
|
||||
|
||||
res, _ := readMap(data, "mapSplatDeep", []string{"*", "cats"})
|
||||
result := res.([]interface{})
|
||||
var actual = []string{result[0].(string), result[1].(string)}
|
||||
sort.Strings(actual)
|
||||
assertResult(t, "[apples bananas]", fmt.Sprintf("%v", actual))
|
||||
}
|
||||
|
||||
func TestReadMap_key_doesnt_exist(t *testing.T) {
|
||||
var data = parseData(`
|
||||
---
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
got, _ := readMap(data, "b.x.f", []string{"c"})
|
||||
assertResult(t, nil, got)
|
||||
}
|
||||
|
||||
func TestReadMap_recurse_against_string(t *testing.T) {
|
||||
var data = parseData(`
|
||||
---
|
||||
a: cat
|
||||
`)
|
||||
got, _ := readMap(data, "a", []string{"b"})
|
||||
assertResult(t, nil, got)
|
||||
}
|
||||
|
||||
func TestReadMap_with_array(t *testing.T) {
|
||||
var data = parseData(`
|
||||
---
|
||||
b:
|
||||
d:
|
||||
- 3
|
||||
- 4
|
||||
`)
|
||||
got, _ := readMap(data, "b", []string{"d", "1"})
|
||||
assertResult(t, 4, got)
|
||||
}
|
||||
|
||||
func TestReadMap_with_array_and_bad_index(t *testing.T) {
|
||||
var data = parseData(`
|
||||
---
|
||||
b:
|
||||
d:
|
||||
- 3
|
||||
- 4
|
||||
`)
|
||||
_, err := readMap(data, "b", []string{"d", "x"})
|
||||
if err == nil {
|
||||
t.Fatal("Expected error due to invalid path")
|
||||
}
|
||||
expectedOutput := `Error accessing array: strconv.ParseInt: parsing "x": invalid syntax`
|
||||
assertResult(t, expectedOutput, err.Error())
|
||||
}
|
||||
|
||||
func TestReadMap_with_mapsplat_array_and_bad_index(t *testing.T) {
|
||||
var data = parseData(`
|
||||
---
|
||||
b:
|
||||
d:
|
||||
e:
|
||||
- 3
|
||||
- 4
|
||||
f:
|
||||
- 1
|
||||
- 2
|
||||
`)
|
||||
_, err := readMap(data, "b", []string{"d", "*", "x"})
|
||||
if err == nil {
|
||||
t.Fatal("Expected error due to invalid path")
|
||||
}
|
||||
expectedOutput := `Error accessing array: strconv.ParseInt: parsing "x": invalid syntax`
|
||||
assertResult(t, expectedOutput, err.Error())
|
||||
}
|
||||
|
||||
func TestReadMap_with_arraysplat_map_array_and_bad_index(t *testing.T) {
|
||||
var data = parseData(`
|
||||
---
|
||||
b:
|
||||
d:
|
||||
- names:
|
||||
- fred
|
||||
- smith
|
||||
- names:
|
||||
- sam
|
||||
- bo
|
||||
`)
|
||||
_, err := readMap(data, "b", []string{"d", "*", "names", "x"})
|
||||
if err == nil {
|
||||
t.Fatal("Expected error due to invalid path")
|
||||
}
|
||||
expectedOutput := `Error accessing array: strconv.ParseInt: parsing "x": invalid syntax`
|
||||
assertResult(t, expectedOutput, err.Error())
|
||||
}
|
||||
|
||||
func TestReadMap_with_array_out_of_bounds(t *testing.T) {
|
||||
var data = parseData(`
|
||||
---
|
||||
b:
|
||||
d:
|
||||
- 3
|
||||
- 4
|
||||
`)
|
||||
got, _ := readMap(data, "b", []string{"d", "3"})
|
||||
assertResult(t, nil, got)
|
||||
}
|
||||
|
||||
func TestReadMap_with_array_out_of_bounds_by_1(t *testing.T) {
|
||||
var data = parseData(`
|
||||
---
|
||||
b:
|
||||
d:
|
||||
- 3
|
||||
- 4
|
||||
`)
|
||||
got, _ := readMap(data, "b", []string{"d", "2"})
|
||||
assertResult(t, nil, got)
|
||||
}
|
||||
|
||||
func TestReadMap_with_array_splat(t *testing.T) {
|
||||
var data = parseData(`
|
||||
e:
|
||||
-
|
||||
name: Fred
|
||||
thing: cat
|
||||
-
|
||||
name: Sam
|
||||
thing: dog
|
||||
`)
|
||||
got, _ := readMap(data, "e", []string{"*", "name"})
|
||||
assertResult(t, "[Fred Sam]", fmt.Sprintf("%v", got))
|
||||
}
|
||||
|
||||
func TestWrite_really_simple(t *testing.T) {
|
||||
var data = parseData(`
|
||||
b: 2
|
||||
`)
|
||||
|
||||
updated := writeMap(data, []string{"b"}, "4")
|
||||
b := entryInSlice(updated, "b").Value
|
||||
assertResult(t, "4", b)
|
||||
}
|
||||
|
||||
func TestWrite_simple(t *testing.T) {
|
||||
var data = parseData(`
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
|
||||
updated := writeMap(data, []string{"b", "c"}, "4")
|
||||
b := entryInSlice(updated, "b").Value.(yaml.MapSlice)
|
||||
c := entryInSlice(b, "c").Value
|
||||
assertResult(t, "4", c)
|
||||
}
|
||||
|
||||
func TestWrite_new(t *testing.T) {
|
||||
var data = parseData(`
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
|
||||
updated := writeMap(data, []string{"b", "d"}, "4")
|
||||
b := entryInSlice(updated, "b").Value.(yaml.MapSlice)
|
||||
d := entryInSlice(b, "d").Value
|
||||
assertResult(t, "4", d)
|
||||
}
|
||||
|
||||
func TestWrite_new_deep(t *testing.T) {
|
||||
var data = parseData(`
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
|
||||
updated := writeMap(data, []string{"b", "d", "f"}, "4")
|
||||
got, _ := readMap(updated, "b", []string{"d", "f"})
|
||||
assertResult(t, "4", got)
|
||||
}
|
||||
|
||||
func TestWrite_array(t *testing.T) {
|
||||
var data = parseData(`
|
||||
b:
|
||||
- aa
|
||||
`)
|
||||
|
||||
updated := writeMap(data, []string{"b", "0"}, "bb")
|
||||
|
||||
b := entryInSlice(updated, "b").Value.([]interface{})
|
||||
assertResult(t, "bb", b[0].(string))
|
||||
}
|
||||
|
||||
func TestWrite_new_array(t *testing.T) {
|
||||
var data = parseData(`
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
|
||||
updated := writeMap(data, []string{"b", "0"}, "4")
|
||||
got, _ := readMap(updated, "b", []string{"0"})
|
||||
assertResult(t, "4", got)
|
||||
}
|
||||
|
||||
func TestWrite_new_array_deep(t *testing.T) {
|
||||
var data = parseData(`
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
|
||||
var expected = `b:
|
||||
- c: "4"`
|
||||
|
||||
updated := writeMap(data, []string{"b", "0", "c"}, "4")
|
||||
got, _ := yamlToString(updated)
|
||||
assertResult(t, expected, got)
|
||||
}
|
||||
|
||||
func TestWrite_new_map_array_deep(t *testing.T) {
|
||||
var data = parseData(`
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
|
||||
updated := writeMap(data, []string{"b", "d", "0"}, "4")
|
||||
got, _ := readMap(updated, "b", []string{"d", "0"})
|
||||
assertResult(t, "4", got)
|
||||
}
|
||||
|
||||
func TestWrite_add_to_array(t *testing.T) {
|
||||
var data = parseData(`
|
||||
b:
|
||||
- aa
|
||||
`)
|
||||
|
||||
var expected = `b:
|
||||
- aa
|
||||
- bb`
|
||||
|
||||
updated := writeMap(data, []string{"b", "1"}, "bb")
|
||||
got, _ := yamlToString(updated)
|
||||
assertResult(t, expected, got)
|
||||
}
|
||||
|
||||
func TestWrite_with_no_tail(t *testing.T) {
|
||||
var data = parseData(`
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
updated := writeMap(data, []string{"b"}, "4")
|
||||
|
||||
b := entryInSlice(updated, "b").Value
|
||||
assertResult(t, "4", fmt.Sprintf("%v", b))
|
||||
}
|
||||
|
||||
func TestWriteMap_no_paths(t *testing.T) {
|
||||
var data = parseData(`
|
||||
b: 5
|
||||
`)
|
||||
|
||||
result := writeMap(data, []string{}, 4)
|
||||
assertResult(t, fmt.Sprintf("%v", data), fmt.Sprintf("%v", result))
|
||||
}
|
||||
|
||||
func TestWriteArray_no_paths(t *testing.T) {
|
||||
var data = make([]interface{}, 1)
|
||||
data[0] = "mike"
|
||||
result := writeArray(data, []string{}, 4)
|
||||
assertResult(t, fmt.Sprintf("%v", data), fmt.Sprintf("%v", result))
|
||||
}
|
||||
|
||||
func TestDelete_MapItem(t *testing.T) {
|
||||
var data = parseData(`
|
||||
a: 123
|
||||
b: 456
|
||||
`)
|
||||
var expected = parseData(`
|
||||
b: 456
|
||||
`)
|
||||
|
||||
result := deleteMap(data, []string{"a"})
|
||||
assertResult(t, fmt.Sprintf("%v", expected), fmt.Sprintf("%v", result))
|
||||
}
|
||||
|
||||
// Ensure deleting an index into a string does nothing
|
||||
func TestDelete_index_to_string(t *testing.T) {
|
||||
var data = parseData(`
|
||||
a: mystring
|
||||
`)
|
||||
result := deleteMap(data, []string{"a", "0"})
|
||||
assertResult(t, fmt.Sprintf("%v", data), fmt.Sprintf("%v", result))
|
||||
}
|
||||
|
||||
func TestDelete_list_index(t *testing.T) {
|
||||
var data = parseData(`
|
||||
a: [3, 4]
|
||||
`)
|
||||
var expected = parseData(`
|
||||
a: [3]
|
||||
`)
|
||||
result := deleteMap(data, []string{"a", "1"})
|
||||
assertResult(t, fmt.Sprintf("%v", expected), fmt.Sprintf("%v", result))
|
||||
}
|
||||
|
||||
func TestDelete_list_index_beyond_bounds(t *testing.T) {
|
||||
var data = parseData(`
|
||||
a: [3, 4]
|
||||
`)
|
||||
result := deleteMap(data, []string{"a", "5"})
|
||||
assertResult(t, fmt.Sprintf("%v", data), fmt.Sprintf("%v", result))
|
||||
}
|
||||
|
||||
func TestDelete_list_index_out_of_bounds_by_1(t *testing.T) {
|
||||
var data = parseData(`
|
||||
a: [3, 4]
|
||||
`)
|
||||
result := deleteMap(data, []string{"a", "2"})
|
||||
assertResult(t, fmt.Sprintf("%v", data), fmt.Sprintf("%v", result))
|
||||
}
|
||||
|
||||
func TestDelete_no_paths(t *testing.T) {
|
||||
var data = parseData(`
|
||||
a: [3, 4]
|
||||
b:
|
||||
- name: test
|
||||
`)
|
||||
result := deleteMap(data, []string{})
|
||||
assertResult(t, fmt.Sprintf("%v", data), fmt.Sprintf("%v", result))
|
||||
}
|
||||
|
||||
func TestDelete_array_map_item(t *testing.T) {
|
||||
var data = parseData(`
|
||||
b:
|
||||
- name: fred
|
||||
value: blah
|
||||
- name: john
|
||||
value: test
|
||||
`)
|
||||
var expected = parseData(`
|
||||
b:
|
||||
- value: blah
|
||||
- name: john
|
||||
value: test
|
||||
`)
|
||||
result := deleteMap(data, []string{"b", "0", "name"})
|
||||
assertResult(t, fmt.Sprintf("%v", expected), fmt.Sprintf("%v", result))
|
||||
}
|
||||
12
debian/changelog
vendored
12
debian/changelog
vendored
@@ -1,3 +1,15 @@
|
||||
yq (2.2-1) bionic; urgency=medium
|
||||
|
||||
* Added Windows support for the "--inplace" command flag
|
||||
* Prefix now supports arrays
|
||||
* Add prefix command
|
||||
* Bump Alpine version to 3.8
|
||||
* Improved docker build process
|
||||
* Lint fixes
|
||||
* Build support for all linux architectures supported by gox
|
||||
|
||||
-- Roberto Mier Escandon <rmescandon@gmail.com> Sat, 19 Jan 2019 15:50:47 +0100
|
||||
|
||||
yq (2.1-0) bionic; urgency=medium
|
||||
|
||||
* Ability to read multiple documents in a single file
|
||||
|
||||
2
debian/control
vendored
2
debian/control
vendored
@@ -12,7 +12,7 @@ Vcs-Browser: https://github.com/mikefarah/yq.git
|
||||
Vcs-Git: https://github.com/mikefarah/yq.git
|
||||
|
||||
Package: yq
|
||||
Architecture: all
|
||||
Architecture: any
|
||||
Built-Using: ${misc:Built-Using}
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<meta name="lang:search.tokenizer" content="[\s\-]+">
|
||||
|
||||
<link rel="shortcut icon" href="/assets/images/favicon.png">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.1.0">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-4.2.0">
|
||||
|
||||
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="/assets/stylesheets/application.11e41852.css">
|
||||
<link rel="stylesheet" href="/assets/stylesheets/application.750b69bd.css">
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="/assets/javascripts/modernizr.20ef595d.js"></script>
|
||||
<script src="/assets/javascripts/modernizr.74668098.js"></script>
|
||||
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body dir="ltr">
|
||||
@@ -108,22 +111,19 @@
|
||||
<div class="md-flex__cell md-flex__cell--stretch">
|
||||
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
|
||||
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
|
||||
</span>
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<div class="md-search" data-md-component="search" role="dialog">
|
||||
<label class="md-search__overlay" for="__search"></label>
|
||||
<div class="md-search__inner" role="search">
|
||||
@@ -146,7 +146,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -157,20 +156,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -206,20 +203,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
@@ -357,7 +352,6 @@
|
||||
Material for MkDocs</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="md-footer-social">
|
||||
<link rel="stylesheet" href="/assets/fonts/font-awesome.css">
|
||||
|
||||
@@ -367,20 +361,16 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="/assets/javascripts/application.9e1f3b71.js"></script>
|
||||
<script src="/assets/javascripts/application.39abc4af.js"></script>
|
||||
|
||||
<script>app.initialize({version:"1.0.4",url:{base:"/"}})</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
6
docs/assets/javascripts/application.39abc4af.js
Normal file
6
docs/assets/javascripts/application.39abc4af.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
docs/assets/javascripts/lunr/lunr.ja.js
Normal file
1
docs/assets/javascripts/lunr/lunr.ja.js
Normal file
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(m){if(void 0===m)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===m.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var l="2"==m.version[0];m.ja=function(){this.pipeline.reset(),this.pipeline.add(m.ja.trimmer,m.ja.stopWordFilter,m.ja.stemmer),l?this.tokenizer=m.ja.tokenizer:(m.tokenizer&&(m.tokenizer=m.ja.tokenizer),this.tokenizerFn&&(this.tokenizerFn=m.ja.tokenizer))};var j=new m.TinySegmenter;m.ja.tokenizer=function(e){var r,t,i,n,o,s,p,a,u;if(!arguments.length||null==e||null==e)return[];if(Array.isArray(e))return e.map(function(e){return l?new m.Token(e.toLowerCase()):e.toLowerCase()});for(r=(t=e.toString().toLowerCase().replace(/^\s+/,"")).length-1;0<=r;r--)if(/\S/.test(t.charAt(r))){t=t.substring(0,r+1);break}for(o=[],i=t.length,p=a=0;a<=i;a++)if(s=a-p,t.charAt(a).match(/\s/)||a==i){if(0<s)for(n=j.segment(t.slice(p,a)).filter(function(e){return!!e}),u=p,r=0;r<n.length;r++)l?o.push(new m.Token(n[r],{position:[u,n[r].length],index:o.length})):o.push(n[r]),u+=n[r].length;p=a+1}return o},m.ja.stemmer=function(e){return e},m.Pipeline.registerFunction(m.ja.stemmer,"stemmer-ja"),m.ja.wordCharacters="一二三四五六七八九十百千万億兆一-龠々〆ヵヶぁ-んァ-ヴーア-ン゙a-zA-Za-zA-Z0-90-9",m.ja.trimmer=m.trimmerSupport.generateTrimmer(m.ja.wordCharacters),m.Pipeline.registerFunction(m.ja.trimmer,"trimmer-ja"),m.ja.stopWordFilter=m.generateStopWordFilter("これ それ あれ この その あの ここ そこ あそこ こちら どこ だれ なに なん 何 私 貴方 貴方方 我々 私達 あの人 あのかた 彼女 彼 です あります おります います は が の に を で え から まで より も どの と し それで しかし".split(" ")),m.Pipeline.registerFunction(m.ja.stopWordFilter,"stopWordFilter-ja"),m.jp=m.ja,m.Pipeline.registerFunction(m.jp.stemmer,"stemmer-jp"),m.Pipeline.registerFunction(m.jp.trimmer,"trimmer-jp"),m.Pipeline.registerFunction(m.jp.stopWordFilter,"stopWordFilter-jp")}});
|
||||
@@ -1 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(n){if(void 0===n)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===n.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i="2"==n.version[0];n.jp=function(){this.pipeline.reset(),this.pipeline.add(n.jp.stopWordFilter,n.jp.stemmer),i?this.tokenizer=n.jp.tokenizer:(n.tokenizer&&(n.tokenizer=n.jp.tokenizer),this.tokenizerFn&&(this.tokenizerFn=n.jp.tokenizer))};var o=new n.TinySegmenter;n.jp.tokenizer=function(e){if(!arguments.length||null==e||null==e)return[];if(Array.isArray(e))return e.map(function(e){return i?new n.Token(e.toLowerCase()):e.toLowerCase()});for(var r=e.toString().toLowerCase().replace(/^\s+/,""),t=r.length-1;0<=t;t--)if(/\S/.test(r.charAt(t))){r=r.substring(0,t+1);break}return o.segment(r).filter(function(e){return!!e}).map(function(e){return i?new n.Token(e):e})},n.jp.stemmer=function(e){return e},n.Pipeline.registerFunction(n.jp.stemmer,"stemmer-jp"),n.jp.wordCharacters="一二三四五六七八九十百千万億兆一-龠々〆ヵヶぁ-んァ-ヴーア-ン゙a-zA-Za-zA-Z0-90-9",n.jp.stopWordFilter=function(e){if(-1===n.jp.stopWordFilter.stopWords.indexOf(i?e.toString():e))return e},n.jp.stopWordFilter=n.generateStopWordFilter("これ それ あれ この その あの ここ そこ あそこ こちら どこ だれ なに なん 何 私 貴方 貴方方 我々 私達 あの人 あのかた 彼女 彼 です あります おります います は が の に を で え から まで より も どの と し それで しかし".split(" ")),n.Pipeline.registerFunction(n.jp.stopWordFilter,"stopWordFilter-jp")}});
|
||||
module.exports=require("./lunr.ja");
|
||||
1
docs/assets/javascripts/lunr/lunr.nl.js
Normal file
1
docs/assets/javascripts/lunr/lunr.nl.js
Normal file
File diff suppressed because one or more lines are too long
1
docs/assets/javascripts/lunr/lunr.th.js
Normal file
1
docs/assets/javascripts/lunr/lunr.th.js
Normal file
@@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(t){if(void 0===t)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===t.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i="2"==t.version[0];t.th=function(){this.pipeline.reset(),this.pipeline.add(t.th.trimmer),i?this.tokenizer=t.th.tokenizer:(t.tokenizer&&(t.tokenizer=t.th.tokenizer),this.tokenizerFn&&(this.tokenizerFn=t.th.tokenizer))},t.th.wordCharacters="[-]",t.th.trimmer=t.trimmerSupport.generateTrimmer(t.th.wordCharacters),t.Pipeline.registerFunction(t.th.trimmer,"trimmer-th");var n=t.wordcut;n.init(),t.th.tokenizer=function(e){if(!arguments.length||null==e||null==e)return[];if(Array.isArray(e))return e.map(function(e){return i?new t.Token(e):e});var r=e.toString().replace(/^\s+/,"");return n.cut(r).split("|")}}});
|
||||
1
docs/assets/javascripts/lunr/wordcut.js
Normal file
1
docs/assets/javascripts/lunr/wordcut.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
docs/assets/javascripts/modernizr.74668098.js
Normal file
1
docs/assets/javascripts/modernizr.74668098.js
Normal file
File diff suppressed because one or more lines are too long
1
docs/assets/stylesheets/application-palette.224b79ff.css
Normal file
1
docs/assets/stylesheets/application-palette.224b79ff.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1
docs/assets/stylesheets/application.750b69bd.css
Normal file
1
docs/assets/stylesheets/application.750b69bd.css
Normal file
File diff suppressed because one or more lines are too long
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<meta name="lang:search.tokenizer" content="[\s\-]+">
|
||||
|
||||
<link rel="shortcut icon" href="../assets/images/favicon.png">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.1.0">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-4.2.0">
|
||||
|
||||
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../assets/stylesheets/application.11e41852.css">
|
||||
<link rel="stylesheet" href="../assets/stylesheets/application.750b69bd.css">
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="../assets/javascripts/modernizr.20ef595d.js"></script>
|
||||
<script src="../assets/javascripts/modernizr.74668098.js"></script>
|
||||
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body dir="ltr">
|
||||
@@ -112,22 +115,19 @@
|
||||
<div class="md-flex__cell md-flex__cell--stretch">
|
||||
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
|
||||
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Convert
|
||||
</span>
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Convert
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<div class="md-search" data-md-component="search" role="dialog">
|
||||
<label class="md-search__overlay" for="__search"></label>
|
||||
<div class="md-search__inner" role="search">
|
||||
@@ -150,7 +150,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -161,20 +160,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -210,20 +207,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
@@ -514,7 +509,6 @@ b:
|
||||
Material for MkDocs</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="md-footer-social">
|
||||
<link rel="stylesheet" href="../assets/fonts/font-awesome.css">
|
||||
|
||||
@@ -524,20 +518,16 @@ b:
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="../assets/javascripts/application.9e1f3b71.js"></script>
|
||||
<script src="../assets/javascripts/application.39abc4af.js"></script>
|
||||
|
||||
<script>app.initialize({version:"1.0.4",url:{base:".."}})</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<meta name="lang:search.tokenizer" content="[\s\-]+">
|
||||
|
||||
<link rel="shortcut icon" href="../assets/images/favicon.png">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.1.0">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-4.2.0">
|
||||
|
||||
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../assets/stylesheets/application.11e41852.css">
|
||||
<link rel="stylesheet" href="../assets/stylesheets/application.750b69bd.css">
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="../assets/javascripts/modernizr.20ef595d.js"></script>
|
||||
<script src="../assets/javascripts/modernizr.74668098.js"></script>
|
||||
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body dir="ltr">
|
||||
@@ -112,22 +115,19 @@
|
||||
<div class="md-flex__cell md-flex__cell--stretch">
|
||||
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
|
||||
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Create
|
||||
</span>
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Create
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<div class="md-search" data-md-component="search" role="dialog">
|
||||
<label class="md-search__overlay" for="__search"></label>
|
||||
<div class="md-search__inner" role="search">
|
||||
@@ -150,7 +150,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -161,20 +160,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -210,20 +207,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
@@ -337,6 +332,13 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#keys-and-values-with-leading-dashes" title="Keys (and values) with leading dashes" class="md-nav__link">
|
||||
Keys (and values) with leading dashes
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -411,6 +413,13 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#keys-and-values-with-leading-dashes" title="Keys (and values) with leading dashes" class="md-nav__link">
|
||||
Keys (and values) with leading dashes
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -449,7 +458,7 @@
|
||||
<p>Create scripts follow the same format as the update scripts.</p>
|
||||
<p>Given a script create_instructions.yaml of:</p>
|
||||
<pre><code class="yaml">b.c: 3
|
||||
b.e[0].name: Howdy Partner
|
||||
b.e[+].name: Howdy Partner
|
||||
</code></pre>
|
||||
|
||||
<p>then</p>
|
||||
@@ -481,6 +490,15 @@ b.e[0].name: Howdy Partner
|
||||
|
||||
<p>Any valid yaml key can be specified as part of a key lookup.</p>
|
||||
<p>Note that the path is in quotes to avoid the square brackets being interpreted by your shell.</p>
|
||||
<h3 id="keys-and-values-with-leading-dashes">Keys (and values) with leading dashes<a class="headerlink" href="#keys-and-values-with-leading-dashes" title="Permanent link">¶</a></h3>
|
||||
<p>If a key or value has leading dashes, yq won't know that you are passing a value as opposed to a flag (and you will get a 'bad flag syntax' error).</p>
|
||||
<p>To fix that, you will need to tell it to stop processing flags by adding '--' after the last flag like so:</p>
|
||||
<pre><code class="bash">yq n -t -- --key --value
|
||||
</code></pre>
|
||||
|
||||
<p>Will result in</p>
|
||||
<p><code>`
|
||||
--key: --value</code></p>
|
||||
|
||||
|
||||
|
||||
@@ -544,7 +562,6 @@ b.e[0].name: Howdy Partner
|
||||
Material for MkDocs</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="md-footer-social">
|
||||
<link rel="stylesheet" href="../assets/fonts/font-awesome.css">
|
||||
|
||||
@@ -554,20 +571,16 @@ b.e[0].name: Howdy Partner
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="../assets/javascripts/application.9e1f3b71.js"></script>
|
||||
<script src="../assets/javascripts/application.39abc4af.js"></script>
|
||||
|
||||
<script>app.initialize({version:"1.0.4",url:{base:".."}})</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<meta name="lang:search.tokenizer" content="[\s\-]+">
|
||||
|
||||
<link rel="shortcut icon" href="../assets/images/favicon.png">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.1.0">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-4.2.0">
|
||||
|
||||
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../assets/stylesheets/application.11e41852.css">
|
||||
<link rel="stylesheet" href="../assets/stylesheets/application.750b69bd.css">
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="../assets/javascripts/modernizr.20ef595d.js"></script>
|
||||
<script src="../assets/javascripts/modernizr.74668098.js"></script>
|
||||
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body dir="ltr">
|
||||
@@ -112,22 +115,19 @@
|
||||
<div class="md-flex__cell md-flex__cell--stretch">
|
||||
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
|
||||
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Delete
|
||||
</span>
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Delete
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<div class="md-search" data-md-component="search" role="dialog">
|
||||
<label class="md-search__overlay" for="__search"></label>
|
||||
<div class="md-search__inner" role="search">
|
||||
@@ -150,7 +150,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -161,20 +160,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -210,20 +207,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
@@ -330,6 +325,27 @@
|
||||
Deleting nodes in-place
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#splat" title="Splat" class="md-nav__link">
|
||||
Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#prefix-splat" title="Prefix Splat" class="md-nav__link">
|
||||
Prefix Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#array-splat" title="Array Splat" class="md-nav__link">
|
||||
Array Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
@@ -353,6 +369,13 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#keys-and-values-with-leading-dashes" title="Keys (and values) with leading dashes" class="md-nav__link">
|
||||
Keys (and values) with leading dashes
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -444,6 +467,27 @@
|
||||
Deleting nodes in-place
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#splat" title="Splat" class="md-nav__link">
|
||||
Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#prefix-splat" title="Prefix Splat" class="md-nav__link">
|
||||
Prefix Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#array-splat" title="Array Splat" class="md-nav__link">
|
||||
Array Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
@@ -467,6 +511,13 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#keys-and-values-with-leading-dashes" title="Keys (and values) with leading dashes" class="md-nav__link">
|
||||
Keys (and values) with leading dashes
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -543,6 +594,91 @@
|
||||
</code></pre>
|
||||
|
||||
<p>will update the sample.yaml file so that the 'c' node is deleted</p>
|
||||
<h3 id="splat">Splat<a class="headerlink" href="#splat" title="Permanent link">¶</a></h3>
|
||||
<p>Given a sample.yaml file of:</p>
|
||||
<pre><code class="yaml">---
|
||||
bob:
|
||||
item1:
|
||||
cats: bananas
|
||||
dogs: woof
|
||||
item2:
|
||||
cats: apples
|
||||
dogs: woof2
|
||||
thing:
|
||||
cats: oranges
|
||||
dogs: woof3
|
||||
</code></pre>
|
||||
|
||||
<p>then</p>
|
||||
<pre><code class="bash">yq d sample.yaml bob.*.cats
|
||||
</code></pre>
|
||||
|
||||
<p>will output:</p>
|
||||
<pre><code class="yaml">---
|
||||
bob:
|
||||
item1:
|
||||
dogs: woof
|
||||
item2:
|
||||
dogs: woof2
|
||||
thing:
|
||||
dogs: woof3
|
||||
</code></pre>
|
||||
|
||||
<h3 id="prefix-splat">Prefix Splat<a class="headerlink" href="#prefix-splat" title="Permanent link">¶</a></h3>
|
||||
<p>Given a sample.yaml file of:</p>
|
||||
<pre><code class="yaml">---
|
||||
bob:
|
||||
item1:
|
||||
cats: bananas
|
||||
dogs: woof
|
||||
item2:
|
||||
cats: apples
|
||||
dogs: woof2
|
||||
thing:
|
||||
cats: oranges
|
||||
dogs: woof3
|
||||
</code></pre>
|
||||
|
||||
<p>then</p>
|
||||
<pre><code class="bash">yq d sample.yaml bob.item*.cats
|
||||
</code></pre>
|
||||
|
||||
<p>will output:</p>
|
||||
<pre><code class="yaml">---
|
||||
bob:
|
||||
item1:
|
||||
dogs: woof
|
||||
item2:
|
||||
dogs: woof2
|
||||
thing:
|
||||
cats: oranges
|
||||
dogs: woof3
|
||||
</code></pre>
|
||||
|
||||
<h3 id="array-splat">Array Splat<a class="headerlink" href="#array-splat" title="Permanent link">¶</a></h3>
|
||||
<p>Given a sample.yaml file of:</p>
|
||||
<pre><code class="yaml">---
|
||||
bob:
|
||||
- cats: bananas
|
||||
dogs: woof
|
||||
- cats: apples
|
||||
dogs: woof2
|
||||
- cats: oranges
|
||||
dogs: woof3
|
||||
</code></pre>
|
||||
|
||||
<p>then</p>
|
||||
<pre><code class="bash">yq d sample.yaml bob.[*].cats
|
||||
</code></pre>
|
||||
|
||||
<p>will output:</p>
|
||||
<pre><code class="yaml">---
|
||||
bob:
|
||||
- dogs: woof
|
||||
- dogs: woof2
|
||||
- dogs: woof3
|
||||
</code></pre>
|
||||
|
||||
<h3 id="multiple-documents-delete-from-single-document">Multiple Documents - delete from single document<a class="headerlink" href="#multiple-documents-delete-from-single-document" title="Permanent link">¶</a></h3>
|
||||
<p>Given a sample.yaml file of:</p>
|
||||
<pre><code class="yaml">something: else
|
||||
@@ -601,6 +737,15 @@ b:
|
||||
|
||||
<p>Any valid yaml key can be specified as part of a key lookup.</p>
|
||||
<p>Note that the path is in quotes to avoid the square brackets being interpreted by your shell.</p>
|
||||
<h3 id="keys-and-values-with-leading-dashes">Keys (and values) with leading dashes<a class="headerlink" href="#keys-and-values-with-leading-dashes" title="Permanent link">¶</a></h3>
|
||||
<p>If a key or value has leading dashes, yq won't know that you are passing a value as opposed to a flag (and you will get a 'bad flag syntax' error).</p>
|
||||
<p>To fix that, you will need to tell it to stop processing flags by adding '--' after the last flag like so:</p>
|
||||
<pre><code class="bash">yq n -t -- --key --value
|
||||
</code></pre>
|
||||
|
||||
<p>Will result in</p>
|
||||
<p><code>`
|
||||
--key: --value</code></p>
|
||||
|
||||
|
||||
|
||||
@@ -664,7 +809,6 @@ b:
|
||||
Material for MkDocs</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="md-footer-social">
|
||||
<link rel="stylesheet" href="../assets/fonts/font-awesome.css">
|
||||
|
||||
@@ -674,20 +818,16 @@ b:
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="../assets/javascripts/application.9e1f3b71.js"></script>
|
||||
<script src="../assets/javascripts/application.39abc4af.js"></script>
|
||||
|
||||
<script>app.initialize({version:"1.0.4",url:{base:".."}})</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<meta name="lang:search.tokenizer" content="[\s\-]+">
|
||||
|
||||
<link rel="shortcut icon" href="assets/images/favicon.png">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.1.0">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-4.2.0">
|
||||
|
||||
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="assets/stylesheets/application.11e41852.css">
|
||||
<link rel="stylesheet" href="assets/stylesheets/application.750b69bd.css">
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="assets/javascripts/modernizr.20ef595d.js"></script>
|
||||
<script src="assets/javascripts/modernizr.74668098.js"></script>
|
||||
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body dir="ltr">
|
||||
@@ -112,22 +115,19 @@
|
||||
<div class="md-flex__cell md-flex__cell--stretch">
|
||||
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
|
||||
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Install
|
||||
</span>
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Install
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<div class="md-search" data-md-component="search" role="dialog">
|
||||
<label class="md-search__overlay" for="__search"></label>
|
||||
<div class="md-search__inner" role="search">
|
||||
@@ -150,7 +150,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -161,20 +160,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -210,20 +207,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
@@ -480,7 +475,6 @@ sudo apt install yq -y
|
||||
Material for MkDocs</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="md-footer-social">
|
||||
<link rel="stylesheet" href="assets/fonts/font-awesome.css">
|
||||
|
||||
@@ -490,20 +484,16 @@ sudo apt install yq -y
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="assets/javascripts/application.9e1f3b71.js"></script>
|
||||
<script src="assets/javascripts/application.39abc4af.js"></script>
|
||||
|
||||
<script>app.initialize({version:"1.0.4",url:{base:"."}})</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<meta name="lang:search.tokenizer" content="[\s\-]+">
|
||||
|
||||
<link rel="shortcut icon" href="../assets/images/favicon.png">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.1.0">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-4.2.0">
|
||||
|
||||
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../assets/stylesheets/application.11e41852.css">
|
||||
<link rel="stylesheet" href="../assets/stylesheets/application.750b69bd.css">
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="../assets/javascripts/modernizr.20ef595d.js"></script>
|
||||
<script src="../assets/javascripts/modernizr.74668098.js"></script>
|
||||
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body dir="ltr">
|
||||
@@ -112,22 +115,19 @@
|
||||
<div class="md-flex__cell md-flex__cell--stretch">
|
||||
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
|
||||
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Merge
|
||||
</span>
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Merge
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<div class="md-search" data-md-component="search" role="dialog">
|
||||
<label class="md-search__overlay" for="__search"></label>
|
||||
<div class="md-search__inner" role="search">
|
||||
@@ -150,7 +150,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -161,20 +160,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -210,20 +207,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
@@ -711,7 +706,6 @@ b: dog
|
||||
Material for MkDocs</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="md-footer-social">
|
||||
<link rel="stylesheet" href="../assets/fonts/font-awesome.css">
|
||||
|
||||
@@ -721,20 +715,16 @@ b: dog
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="../assets/javascripts/application.9e1f3b71.js"></script>
|
||||
<script src="../assets/javascripts/application.39abc4af.js"></script>
|
||||
|
||||
<script>app.initialize({version:"1.0.4",url:{base:".."}})</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<meta name="lang:search.tokenizer" content="[\s\-]+">
|
||||
|
||||
<link rel="shortcut icon" href="../assets/images/favicon.png">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.1.0">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-4.2.0">
|
||||
|
||||
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../assets/stylesheets/application.11e41852.css">
|
||||
<link rel="stylesheet" href="../assets/stylesheets/application.750b69bd.css">
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="../assets/javascripts/modernizr.20ef595d.js"></script>
|
||||
<script src="../assets/javascripts/modernizr.74668098.js"></script>
|
||||
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body dir="ltr">
|
||||
@@ -112,22 +115,19 @@
|
||||
<div class="md-flex__cell md-flex__cell--stretch">
|
||||
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
|
||||
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Prefix
|
||||
</span>
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Prefix
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<div class="md-search" data-md-component="search" role="dialog">
|
||||
<label class="md-search__overlay" for="__search"></label>
|
||||
<div class="md-search__inner" role="search">
|
||||
@@ -150,7 +150,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -161,20 +160,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -210,20 +207,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
@@ -612,7 +607,6 @@ c:
|
||||
Material for MkDocs</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="md-footer-social">
|
||||
<link rel="stylesheet" href="../assets/fonts/font-awesome.css">
|
||||
|
||||
@@ -622,20 +616,16 @@ c:
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="../assets/javascripts/application.9e1f3b71.js"></script>
|
||||
<script src="../assets/javascripts/application.39abc4af.js"></script>
|
||||
|
||||
<script>app.initialize({version:"1.0.4",url:{base:".."}})</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<meta name="lang:search.tokenizer" content="[\s\-]+">
|
||||
|
||||
<link rel="shortcut icon" href="../assets/images/favicon.png">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.1.0">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-4.2.0">
|
||||
|
||||
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../assets/stylesheets/application.11e41852.css">
|
||||
<link rel="stylesheet" href="../assets/stylesheets/application.750b69bd.css">
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="../assets/javascripts/modernizr.20ef595d.js"></script>
|
||||
<script src="../assets/javascripts/modernizr.74668098.js"></script>
|
||||
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body dir="ltr">
|
||||
@@ -112,22 +115,19 @@
|
||||
<div class="md-flex__cell md-flex__cell--stretch">
|
||||
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
|
||||
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Read
|
||||
</span>
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Read
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<div class="md-search" data-md-component="search" role="dialog">
|
||||
<label class="md-search__overlay" for="__search"></label>
|
||||
<div class="md-search__inner" role="search">
|
||||
@@ -150,7 +150,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -161,20 +160,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -210,20 +207,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
@@ -287,6 +282,13 @@
|
||||
Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#prefix-splat" title="Prefix Splat" class="md-nav__link">
|
||||
Prefix Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
@@ -324,6 +326,13 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#keys-and-values-with-leading-dashes" title="Keys (and values) with leading dashes" class="md-nav__link">
|
||||
Keys (and values) with leading dashes
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -444,6 +453,13 @@
|
||||
Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#prefix-splat" title="Prefix Splat" class="md-nav__link">
|
||||
Prefix Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
@@ -481,6 +497,13 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#keys-and-values-with-leading-dashes" title="Keys (and values) with leading dashes" class="md-nav__link">
|
||||
Keys (and values) with leading dashes
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -531,12 +554,36 @@ bob:
|
||||
cats: bananas
|
||||
item2:
|
||||
cats: apples
|
||||
thing:
|
||||
cats: oranges
|
||||
</code></pre>
|
||||
|
||||
<p>then</p>
|
||||
<pre><code class="bash">yq r sample.yaml bob.*.cats
|
||||
</code></pre>
|
||||
|
||||
<p>will output</p>
|
||||
<pre><code class="yaml">- bananas
|
||||
- apples
|
||||
- oranges
|
||||
</code></pre>
|
||||
|
||||
<h3 id="prefix-splat">Prefix Splat<a class="headerlink" href="#prefix-splat" title="Permanent link">¶</a></h3>
|
||||
<p>Given a sample.yaml file of:</p>
|
||||
<pre><code class="yaml">---
|
||||
bob:
|
||||
item1:
|
||||
cats: bananas
|
||||
item2:
|
||||
cats: apples
|
||||
thing:
|
||||
cats: oranges
|
||||
</code></pre>
|
||||
|
||||
<p>then</p>
|
||||
<pre><code class="bash">yq r sample.yaml bob.item*.cats
|
||||
</code></pre>
|
||||
|
||||
<p>will output</p>
|
||||
<pre><code class="yaml">- bananas
|
||||
- apples
|
||||
@@ -629,6 +676,15 @@ e.g.: given a sample file of</p>
|
||||
|
||||
<p>Any valid yaml key can be specified as part of a key lookup.</p>
|
||||
<p>Note that the path is in quotes to avoid the square brackets being interpreted by your shell.</p>
|
||||
<h3 id="keys-and-values-with-leading-dashes">Keys (and values) with leading dashes<a class="headerlink" href="#keys-and-values-with-leading-dashes" title="Permanent link">¶</a></h3>
|
||||
<p>If a key or value has leading dashes, yq won't know that you are passing a value as opposed to a flag (and you will get a 'bad flag syntax' error).</p>
|
||||
<p>To fix that, you will need to tell it to stop processing flags by adding '--' after the last flag like so:</p>
|
||||
<pre><code class="bash">yq n -t -- --key --value
|
||||
</code></pre>
|
||||
|
||||
<p>Will result in</p>
|
||||
<p><code>`
|
||||
--key: --value</code></p>
|
||||
|
||||
|
||||
|
||||
@@ -692,7 +748,6 @@ e.g.: given a sample file of</p>
|
||||
Material for MkDocs</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="md-footer-social">
|
||||
<link rel="stylesheet" href="../assets/fonts/font-awesome.css">
|
||||
|
||||
@@ -702,20 +757,16 @@ e.g.: given a sample file of</p>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="../assets/javascripts/application.9e1f3b71.js"></script>
|
||||
<script src="../assets/javascripts/application.39abc4af.js"></script>
|
||||
|
||||
<script>app.initialize({version:"1.0.4",url:{base:".."}})</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
@@ -2,42 +2,42 @@
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>None</loc>
|
||||
<lastmod>2018-11-19</lastmod>
|
||||
<lastmod>2019-05-16</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
<loc>None</loc>
|
||||
<lastmod>2018-11-19</lastmod>
|
||||
<lastmod>2019-05-16</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
<loc>None</loc>
|
||||
<lastmod>2018-11-19</lastmod>
|
||||
<lastmod>2019-05-16</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
<loc>None</loc>
|
||||
<lastmod>2018-11-19</lastmod>
|
||||
<lastmod>2019-05-16</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
<loc>None</loc>
|
||||
<lastmod>2018-11-19</lastmod>
|
||||
<lastmod>2019-05-16</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
<loc>None</loc>
|
||||
<lastmod>2018-11-19</lastmod>
|
||||
<lastmod>2019-05-16</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
<loc>None</loc>
|
||||
<lastmod>2018-11-19</lastmod>
|
||||
<lastmod>2019-05-16</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
<url>
|
||||
<loc>None</loc>
|
||||
<lastmod>2018-11-19</lastmod>
|
||||
<lastmod>2019-05-16</lastmod>
|
||||
<changefreq>daily</changefreq>
|
||||
</url>
|
||||
</urlset>
|
||||
Binary file not shown.
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
|
||||
@@ -32,20 +32,20 @@
|
||||
<meta name="lang:search.tokenizer" content="[\s\-]+">
|
||||
|
||||
<link rel="shortcut icon" href="../../assets/images/favicon.png">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.1.0">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-4.2.0">
|
||||
|
||||
|
||||
|
||||
<title>Keys with dots - Yq</title>
|
||||
<title>Niche - Yq</title>
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../../assets/stylesheets/application.11e41852.css">
|
||||
<link rel="stylesheet" href="../../assets/stylesheets/application.750b69bd.css">
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="../../assets/javascripts/modernizr.20ef595d.js"></script>
|
||||
<script src="../../assets/javascripts/modernizr.74668098.js"></script>
|
||||
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body dir="ltr">
|
||||
@@ -112,22 +115,19 @@
|
||||
<div class="md-flex__cell md-flex__cell--stretch">
|
||||
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
|
||||
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Keys with dots
|
||||
</span>
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Niche
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<div class="md-search" data-md-component="search" role="dialog">
|
||||
<label class="md-search__overlay" for="__search"></label>
|
||||
<div class="md-search__inner" role="search">
|
||||
@@ -150,7 +150,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -161,20 +160,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -210,20 +207,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
@@ -349,6 +344,13 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#keys-and-values-with-leading-dashes" title="Keys (and values) with leading dashes" class="md-nav__link">
|
||||
Keys (and values) with leading dashes
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -365,10 +367,10 @@
|
||||
<article class="md-content__inner md-typeset">
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/edit/master/docs/snippets/keys_with_dots.md" title="Edit this page" class="md-icon md-content__icon"></a>
|
||||
<a href="https://github.com/mikefarah/yq/edit/master/docs/snippets/niche.md" title="Edit this page" class="md-icon md-content__icon"></a>
|
||||
|
||||
|
||||
<h1>Keys with dots</h1>
|
||||
<h1>Niche</h1>
|
||||
|
||||
<h3 id="keys-with-dots">Keys with dots<a class="headerlink" href="#keys-with-dots" title="Permanent link">¶</a></h3>
|
||||
<p>When specifying a key that has a dot use key lookup indicator.</p>
|
||||
@@ -384,6 +386,15 @@
|
||||
|
||||
<p>Any valid yaml key can be specified as part of a key lookup.</p>
|
||||
<p>Note that the path is in quotes to avoid the square brackets being interpreted by your shell.</p>
|
||||
<h3 id="keys-and-values-with-leading-dashes">Keys (and values) with leading dashes<a class="headerlink" href="#keys-and-values-with-leading-dashes" title="Permanent link">¶</a></h3>
|
||||
<p>If a key or value has leading dashes, yq won't know that you are passing a value as opposed to a flag (and you will get a 'bad flag syntax' error).</p>
|
||||
<p>To fix that, you will need to tell it to stop processing flags by adding '--' after the last flag like so:</p>
|
||||
<pre><code class="bash">yq n -t -- --key --value
|
||||
</code></pre>
|
||||
|
||||
<p>Will result in</p>
|
||||
<pre><code>--key: --value
|
||||
</code></pre>
|
||||
|
||||
|
||||
|
||||
@@ -412,7 +423,6 @@
|
||||
Material for MkDocs</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="md-footer-social">
|
||||
<link rel="stylesheet" href="../../assets/fonts/font-awesome.css">
|
||||
|
||||
@@ -422,20 +432,16 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="../../assets/javascripts/application.9e1f3b71.js"></script>
|
||||
<script src="../../assets/javascripts/application.39abc4af.js"></script>
|
||||
|
||||
<script>app.initialize({version:"1.0.4",url:{base:"../.."}})</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<meta name="lang:search.tokenizer" content="[\s\-]+">
|
||||
|
||||
<link rel="shortcut icon" href="../../assets/images/favicon.png">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.1.0">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-4.2.0">
|
||||
|
||||
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../../assets/stylesheets/application.11e41852.css">
|
||||
<link rel="stylesheet" href="../../assets/stylesheets/application.750b69bd.css">
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="../../assets/javascripts/modernizr.20ef595d.js"></script>
|
||||
<script src="../../assets/javascripts/modernizr.74668098.js"></script>
|
||||
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body dir="ltr">
|
||||
@@ -108,22 +111,19 @@
|
||||
<div class="md-flex__cell md-flex__cell--stretch">
|
||||
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
|
||||
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Works with json
|
||||
</span>
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Works with json
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<div class="md-search" data-md-component="search" role="dialog">
|
||||
<label class="md-search__overlay" for="__search"></label>
|
||||
<div class="md-search__inner" role="search">
|
||||
@@ -146,7 +146,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -157,20 +156,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -206,20 +203,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
@@ -366,7 +361,6 @@
|
||||
Material for MkDocs</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="md-footer-social">
|
||||
<link rel="stylesheet" href="../../assets/fonts/font-awesome.css">
|
||||
|
||||
@@ -376,20 +370,16 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="../../assets/javascripts/application.9e1f3b71.js"></script>
|
||||
<script src="../../assets/javascripts/application.39abc4af.js"></script>
|
||||
|
||||
<script>app.initialize({version:"1.0.4",url:{base:"../.."}})</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<meta name="lang:search.tokenizer" content="[\s\-]+">
|
||||
|
||||
<link rel="shortcut icon" href="../assets/images/favicon.png">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-3.1.0">
|
||||
<meta name="generator" content="mkdocs-1.0.4, mkdocs-material-4.2.0">
|
||||
|
||||
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../assets/stylesheets/application.11e41852.css">
|
||||
<link rel="stylesheet" href="../assets/stylesheets/application.750b69bd.css">
|
||||
|
||||
|
||||
|
||||
|
||||
<script src="../assets/javascripts/modernizr.20ef595d.js"></script>
|
||||
<script src="../assets/javascripts/modernizr.74668098.js"></script>
|
||||
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body dir="ltr">
|
||||
@@ -112,22 +115,19 @@
|
||||
<div class="md-flex__cell md-flex__cell--stretch">
|
||||
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
|
||||
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Write/Update
|
||||
</span>
|
||||
|
||||
<span class="md-header-nav__topic">
|
||||
Yq
|
||||
</span>
|
||||
<span class="md-header-nav__topic">
|
||||
Write/Update
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-flex__cell md-flex__cell--shrink">
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<label class="md-icon md-icon--search md-header-nav__button" for="__search"></label>
|
||||
|
||||
<div class="md-search" data-md-component="search" role="dialog">
|
||||
<label class="md-search__overlay" for="__search"></label>
|
||||
<div class="md-search__inner" role="search">
|
||||
@@ -150,7 +150,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -161,20 +160,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -210,20 +207,18 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
<a href="https://github.com/mikefarah/yq/" title="Go to repository" class="md-source" data-md-source="github">
|
||||
|
||||
<div class="md-source__icon">
|
||||
<svg viewBox="0 0 24 24" width="24" height="24">
|
||||
<use xlink:href="#__github" width="24" height="24"></use>
|
||||
</svg>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="md-source__repository">
|
||||
mikefarah/yq
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="md-nav__list" data-md-scrollfix>
|
||||
@@ -299,6 +294,27 @@
|
||||
Adding new fields
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#splat" title="Splat" class="md-nav__link">
|
||||
Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#prefix-splat" title="Prefix Splat" class="md-nav__link">
|
||||
Prefix Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#array-splat" title="Array Splat" class="md-nav__link">
|
||||
Array Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
@@ -350,6 +366,13 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#keys-and-values-with-leading-dashes" title="Keys (and values) with leading dashes" class="md-nav__link">
|
||||
Keys (and values) with leading dashes
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -458,6 +481,27 @@
|
||||
Adding new fields
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#splat" title="Splat" class="md-nav__link">
|
||||
Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#prefix-splat" title="Prefix Splat" class="md-nav__link">
|
||||
Prefix Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#array-splat" title="Array Splat" class="md-nav__link">
|
||||
Array Splat
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
@@ -509,6 +553,13 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#keys-and-values-with-leading-dashes" title="Keys (and values) with leading dashes" class="md-nav__link">
|
||||
Keys (and values) with leading dashes
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -560,7 +611,7 @@
|
||||
</code></pre>
|
||||
|
||||
<p>then</p>
|
||||
<pre><code class="bash">yq w sample.yaml b.d[0] "new thing"
|
||||
<pre><code class="bash">yq w sample.yaml b.d[+] "new thing"
|
||||
</code></pre>
|
||||
|
||||
<p>will output:</p>
|
||||
@@ -570,6 +621,81 @@
|
||||
- new thing
|
||||
</code></pre>
|
||||
|
||||
<h3 id="splat">Splat<a class="headerlink" href="#splat" title="Permanent link">¶</a></h3>
|
||||
<p>Given a sample.yaml file of:</p>
|
||||
<pre><code class="yaml">---
|
||||
bob:
|
||||
item1:
|
||||
cats: bananas
|
||||
item2:
|
||||
cats: apples
|
||||
thing:
|
||||
cats: oranges
|
||||
</code></pre>
|
||||
|
||||
<p>then</p>
|
||||
<pre><code class="bash">yq w sample.yaml bob.*.cats meow
|
||||
</code></pre>
|
||||
|
||||
<p>will output:</p>
|
||||
<pre><code class="yaml">---
|
||||
bob:
|
||||
item1:
|
||||
cats: meow
|
||||
item2:
|
||||
cats: meow
|
||||
thing:
|
||||
cats: meow
|
||||
</code></pre>
|
||||
|
||||
<h3 id="prefix-splat">Prefix Splat<a class="headerlink" href="#prefix-splat" title="Permanent link">¶</a></h3>
|
||||
<p>Given a sample.yaml file of:</p>
|
||||
<pre><code class="yaml">---
|
||||
bob:
|
||||
item1:
|
||||
cats: bananas
|
||||
item2:
|
||||
cats: apples
|
||||
thing:
|
||||
cats: oranges
|
||||
</code></pre>
|
||||
|
||||
<p>then</p>
|
||||
<pre><code class="bash">yq w sample.yaml bob.item*.cats meow
|
||||
</code></pre>
|
||||
|
||||
<p>will output:</p>
|
||||
<pre><code class="yaml">---
|
||||
bob:
|
||||
item1:
|
||||
cats: meow
|
||||
item2:
|
||||
cats: meow
|
||||
thing:
|
||||
cats: oranges
|
||||
</code></pre>
|
||||
|
||||
<h3 id="array-splat">Array Splat<a class="headerlink" href="#array-splat" title="Permanent link">¶</a></h3>
|
||||
<p>Given a sample.yaml file of:</p>
|
||||
<pre><code class="yaml">---
|
||||
bob:
|
||||
- cats: bananas
|
||||
- cats: apples
|
||||
- cats: oranges
|
||||
</code></pre>
|
||||
|
||||
<p>then</p>
|
||||
<pre><code class="bash">yq w sample.yaml bob[*].cats meow
|
||||
</code></pre>
|
||||
|
||||
<p>will output:</p>
|
||||
<pre><code class="yaml">---
|
||||
bob:
|
||||
- cats: meow
|
||||
- cats: meow
|
||||
- cats: meow
|
||||
</code></pre>
|
||||
|
||||
<h3 id="appending-value-to-an-array-field">Appending value to an array field<a class="headerlink" href="#appending-value-to-an-array-field" title="Permanent link">¶</a></h3>
|
||||
<p>Given a sample.yaml file of:</p>
|
||||
<pre><code class="yaml">b:
|
||||
@@ -655,7 +781,7 @@ b:
|
||||
|
||||
<p>and a script update_instructions.yaml of:</p>
|
||||
<pre><code class="yaml">b.c: 3
|
||||
b.e[0].name: Howdy Partner
|
||||
b.e[+].name: Howdy Partner
|
||||
</code></pre>
|
||||
|
||||
<p>then</p>
|
||||
@@ -697,6 +823,15 @@ b.e[0].name: Howdy Partner
|
||||
|
||||
<p>Any valid yaml key can be specified as part of a key lookup.</p>
|
||||
<p>Note that the path is in quotes to avoid the square brackets being interpreted by your shell.</p>
|
||||
<h3 id="keys-and-values-with-leading-dashes">Keys (and values) with leading dashes<a class="headerlink" href="#keys-and-values-with-leading-dashes" title="Permanent link">¶</a></h3>
|
||||
<p>If a key or value has leading dashes, yq won't know that you are passing a value as opposed to a flag (and you will get a 'bad flag syntax' error).</p>
|
||||
<p>To fix that, you will need to tell it to stop processing flags by adding '--' after the last flag like so:</p>
|
||||
<pre><code class="bash">yq n -t -- --key --value
|
||||
</code></pre>
|
||||
|
||||
<p>Will result in</p>
|
||||
<p><code>`
|
||||
--key: --value</code></p>
|
||||
|
||||
|
||||
|
||||
@@ -760,7 +895,6 @@ b.e[0].name: Howdy Partner
|
||||
Material for MkDocs</a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="md-footer-social">
|
||||
<link rel="stylesheet" href="../assets/fonts/font-awesome.css">
|
||||
|
||||
@@ -770,20 +904,16 @@ b.e[0].name: Howdy Partner
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="../assets/javascripts/application.9e1f3b71.js"></script>
|
||||
<script src="../assets/javascripts/application.39abc4af.js"></script>
|
||||
|
||||
<script>app.initialize({version:"1.0.4",url:{base:".."}})</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1 +1,14 @@
|
||||
b: dog
|
||||
deep1:
|
||||
hostA:
|
||||
value: 1234
|
||||
notRelevant:
|
||||
value: bananas
|
||||
hostB:
|
||||
value: 5678
|
||||
deep2:
|
||||
hostC:
|
||||
value: 1234
|
||||
notRelevant:
|
||||
value: bananas
|
||||
hostD:
|
||||
value: 5678
|
||||
|
||||
2
examples/empty.yaml
Normal file
2
examples/empty.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
# a: apple
|
||||
# b: cat
|
||||
@@ -1,2 +1,2 @@
|
||||
b.c: cat
|
||||
b.e[0].name: Mike Farah
|
||||
b.e[+].name: Mike Farah
|
||||
|
||||
2
examples/numbered_keys.yml
Normal file
2
examples/numbered_keys.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
5:
|
||||
6: camel!
|
||||
12
go.mod
Normal file
12
go.mod
Normal file
@@ -0,0 +1,12 @@
|
||||
module github.com/mikefarah/yq/v2
|
||||
|
||||
require (
|
||||
github.com/mikefarah/yaml/v2 v2.4.0
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/spf13/cobra v0.0.5
|
||||
golang.org/x/tools v0.0.0-20191030203535-5e247c9ad0a0 // indirect
|
||||
gopkg.in/imdario/mergo.v0 v0.3.7
|
||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
|
||||
)
|
||||
|
||||
go 1.13
|
||||
50
go.sum
Normal file
50
go.sum
Normal file
@@ -0,0 +1,50 @@
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mikefarah/yaml/v2 v2.4.0 h1:eYqfooY0BnvKTJxr7+ABJs13n3dg9n347GScDaU2Lww=
|
||||
github.com/mikefarah/yaml/v2 v2.4.0/go.mod h1:ahVqZF4n1W4NqwvVnZzC4es67xsW9uR/RRf2RRxieJU=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20191030203535-5e247c9ad0a0 h1:s5lp4ug7qHzUccgyFdjsX7OZDzHXRaePrF3B3vmUiuM=
|
||||
golang.org/x/tools v0.0.0-20191030203535-5e247c9ad0a0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/imdario/mergo.v0 v0.3.7 h1:QDotlIZtaO/p+Um0ok18HRTpq5i5/SAk/qprsor+9c8=
|
||||
gopkg.in/imdario/mergo.v0 v0.3.7/go.mod h1:9qPP6AGrlC1G2PTNXko614FwGZvorN7MiBU0Eppok+U=
|
||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW8s2qTSe3wGBtvo0MbVQG/c5k8RE=
|
||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
@@ -1,44 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
yaml "gopkg.in/mikefarah/yaml.v2"
|
||||
)
|
||||
|
||||
func jsonToString(context interface{}) (string, error) {
|
||||
out, err := json.Marshal(toJSON(context))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error printing yaml as json: %v", err)
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
func toJSON(context interface{}) interface{} {
|
||||
switch context.(type) {
|
||||
case []interface{}:
|
||||
oldArray := context.([]interface{})
|
||||
newArray := make([]interface{}, len(oldArray))
|
||||
for index, value := range oldArray {
|
||||
newArray[index] = toJSON(value)
|
||||
}
|
||||
return newArray
|
||||
case yaml.MapSlice:
|
||||
oldMap := context.(yaml.MapSlice)
|
||||
newMap := make(map[string]interface{})
|
||||
for _, entry := range oldMap {
|
||||
if str, ok := entry.Key.(string); ok {
|
||||
newMap[str] = toJSON(entry.Value)
|
||||
} else if i, ok := entry.Key.(int); ok {
|
||||
newMap[strconv.Itoa(i)] = toJSON(entry.Value)
|
||||
} else if b, ok := entry.Key.(bool); ok {
|
||||
newMap[strconv.FormatBool(b)] = toJSON(entry.Value)
|
||||
}
|
||||
}
|
||||
return newMap
|
||||
default:
|
||||
return context
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestJsonToString(t *testing.T) {
|
||||
var data = parseData(`
|
||||
---
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
got, _ := jsonToString(data)
|
||||
assertResult(t, "{\"b\":{\"c\":2}}", got)
|
||||
}
|
||||
|
||||
func TestJsonToString_withIntKey(t *testing.T) {
|
||||
var data = parseData(`
|
||||
---
|
||||
b:
|
||||
2: c
|
||||
`)
|
||||
got, _ := jsonToString(data)
|
||||
assertResult(t, `{"b":{"2":"c"}}`, got)
|
||||
}
|
||||
|
||||
func TestJsonToString_withBoolKey(t *testing.T) {
|
||||
var data = parseData(`
|
||||
---
|
||||
b:
|
||||
false: c
|
||||
`)
|
||||
got, _ := jsonToString(data)
|
||||
assertResult(t, `{"b":{"false":"c"}}`, got)
|
||||
}
|
||||
|
||||
func TestJsonToString_withArray(t *testing.T) {
|
||||
var data = parseData(`
|
||||
---
|
||||
b:
|
||||
- item: one
|
||||
- item: two
|
||||
`)
|
||||
got, _ := jsonToString(data)
|
||||
assertResult(t, "{\"b\":[{\"item\":\"one\"},{\"item\":\"two\"}]}", got)
|
||||
}
|
||||
12
merge.go
12
merge.go
@@ -1,12 +0,0 @@
|
||||
package main
|
||||
|
||||
import "gopkg.in/imdario/mergo.v0"
|
||||
|
||||
func merge(dst interface{}, src interface{}, overwrite bool, append bool) error {
|
||||
if overwrite {
|
||||
return mergo.Merge(dst, src, mergo.WithOverride)
|
||||
} else if append {
|
||||
return mergo.Merge(dst, src, mergo.WithAppendSlice)
|
||||
}
|
||||
return mergo.Merge(dst, src)
|
||||
}
|
||||
@@ -20,7 +20,7 @@ Create scripts follow the same format as the update scripts.
|
||||
Given a script create_instructions.yaml of:
|
||||
```yaml
|
||||
b.c: 3
|
||||
b.e[0].name: Howdy Partner
|
||||
b.e[+].name: Howdy Partner
|
||||
```
|
||||
then
|
||||
|
||||
@@ -41,4 +41,4 @@ You can also pipe the instructions in:
|
||||
cat create_instructions.yaml | yq n -s -
|
||||
```
|
||||
|
||||
{!snippets/keys_with_dots.md!}
|
||||
{!snippets/niche.md!}
|
||||
|
||||
@@ -59,6 +59,93 @@ yq d -i sample.yaml b.c
|
||||
will update the sample.yaml file so that the 'c' node is deleted
|
||||
|
||||
|
||||
### Splat
|
||||
Given a sample.yaml file of:
|
||||
```yaml
|
||||
---
|
||||
bob:
|
||||
item1:
|
||||
cats: bananas
|
||||
dogs: woof
|
||||
item2:
|
||||
cats: apples
|
||||
dogs: woof2
|
||||
thing:
|
||||
cats: oranges
|
||||
dogs: woof3
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq d sample.yaml bob.*.cats
|
||||
```
|
||||
will output:
|
||||
```yaml
|
||||
---
|
||||
bob:
|
||||
item1:
|
||||
dogs: woof
|
||||
item2:
|
||||
dogs: woof2
|
||||
thing:
|
||||
dogs: woof3
|
||||
```
|
||||
|
||||
### Prefix Splat
|
||||
Given a sample.yaml file of:
|
||||
```yaml
|
||||
---
|
||||
bob:
|
||||
item1:
|
||||
cats: bananas
|
||||
dogs: woof
|
||||
item2:
|
||||
cats: apples
|
||||
dogs: woof2
|
||||
thing:
|
||||
cats: oranges
|
||||
dogs: woof3
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq d sample.yaml bob.item*.cats
|
||||
```
|
||||
will output:
|
||||
```yaml
|
||||
---
|
||||
bob:
|
||||
item1:
|
||||
dogs: woof
|
||||
item2:
|
||||
dogs: woof2
|
||||
thing:
|
||||
cats: oranges
|
||||
dogs: woof3
|
||||
```
|
||||
|
||||
### Array Splat
|
||||
Given a sample.yaml file of:
|
||||
```yaml
|
||||
---
|
||||
bob:
|
||||
- cats: bananas
|
||||
dogs: woof
|
||||
- cats: apples
|
||||
dogs: woof2
|
||||
- cats: oranges
|
||||
dogs: woof3
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq d sample.yaml bob.[*].cats
|
||||
```
|
||||
will output:
|
||||
```yaml
|
||||
---
|
||||
bob:
|
||||
- dogs: woof
|
||||
- dogs: woof2
|
||||
- dogs: woof3
|
||||
```
|
||||
|
||||
### Multiple Documents - delete from single document
|
||||
Given a sample.yaml file of:
|
||||
@@ -107,4 +194,4 @@ b:
|
||||
|
||||
Note that '*' is in quotes to avoid being interpreted by your shell.
|
||||
|
||||
{!snippets/keys_with_dots.md!}
|
||||
{!snippets/niche.md!}
|
||||
|
||||
@@ -32,6 +32,8 @@ bob:
|
||||
cats: bananas
|
||||
item2:
|
||||
cats: apples
|
||||
thing:
|
||||
cats: oranges
|
||||
```
|
||||
then
|
||||
```bash
|
||||
@@ -41,6 +43,29 @@ will output
|
||||
```yaml
|
||||
- bananas
|
||||
- apples
|
||||
- oranges
|
||||
```
|
||||
|
||||
### Prefix Splat
|
||||
Given a sample.yaml file of:
|
||||
```yaml
|
||||
---
|
||||
bob:
|
||||
item1:
|
||||
cats: bananas
|
||||
item2:
|
||||
cats: apples
|
||||
thing:
|
||||
cats: oranges
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq r sample.yaml bob.item*.cats
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
- bananas
|
||||
- apples
|
||||
```
|
||||
|
||||
### Multiple Documents - specify a single document
|
||||
@@ -122,4 +147,4 @@ will output:
|
||||
```
|
||||
Note that the path is in quotes to avoid the square brackets being interpreted by your shell.
|
||||
|
||||
{!snippets/keys_with_dots.md!}
|
||||
{!snippets/niche.md!}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
### Keys with dots
|
||||
When specifying a key that has a dot use key lookup indicator.
|
||||
|
||||
```yaml
|
||||
b:
|
||||
foo.bar: 7
|
||||
```
|
||||
|
||||
```bash
|
||||
yaml r sample.yaml 'b[foo.bar]'
|
||||
```
|
||||
|
||||
```bash
|
||||
yaml w sample.yaml 'b[foo.bar]' 9
|
||||
```
|
||||
|
||||
Any valid yaml key can be specified as part of a key lookup.
|
||||
|
||||
Note that the path is in quotes to avoid the square brackets being interpreted by your shell.
|
||||
35
mkdocs/snippets/niche.md
Normal file
35
mkdocs/snippets/niche.md
Normal file
@@ -0,0 +1,35 @@
|
||||
### Keys with dots
|
||||
When specifying a key that has a dot use key lookup indicator.
|
||||
|
||||
```yaml
|
||||
b:
|
||||
foo.bar: 7
|
||||
```
|
||||
|
||||
```bash
|
||||
yaml r sample.yaml 'b[foo.bar]'
|
||||
```
|
||||
|
||||
```bash
|
||||
yaml w sample.yaml 'b[foo.bar]' 9
|
||||
```
|
||||
|
||||
Any valid yaml key can be specified as part of a key lookup.
|
||||
|
||||
Note that the path is in quotes to avoid the square brackets being interpreted by your shell.
|
||||
|
||||
### Keys (and values) with leading dashes
|
||||
If a key or value has leading dashes, yq won't know that you are passing a value as opposed to a flag (and you will get a 'bad flag syntax' error).
|
||||
|
||||
To fix that, you will need to tell it to stop processing flags by adding '--' after the last flag like so:
|
||||
|
||||
|
||||
```bash
|
||||
yq n -t -- --key --value
|
||||
```
|
||||
|
||||
Will result in
|
||||
|
||||
```
|
||||
--key: --value
|
||||
```
|
||||
@@ -33,7 +33,7 @@ b:
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq w sample.yaml b.d[0] "new thing"
|
||||
yq w sample.yaml b.d[+] "new thing"
|
||||
```
|
||||
will output:
|
||||
```yaml
|
||||
@@ -43,6 +43,84 @@ b:
|
||||
- new thing
|
||||
```
|
||||
|
||||
### Splat
|
||||
Given a sample.yaml file of:
|
||||
```yaml
|
||||
---
|
||||
bob:
|
||||
item1:
|
||||
cats: bananas
|
||||
item2:
|
||||
cats: apples
|
||||
thing:
|
||||
cats: oranges
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq w sample.yaml bob.*.cats meow
|
||||
```
|
||||
will output:
|
||||
```yaml
|
||||
---
|
||||
bob:
|
||||
item1:
|
||||
cats: meow
|
||||
item2:
|
||||
cats: meow
|
||||
thing:
|
||||
cats: meow
|
||||
```
|
||||
|
||||
### Prefix Splat
|
||||
Given a sample.yaml file of:
|
||||
```yaml
|
||||
---
|
||||
bob:
|
||||
item1:
|
||||
cats: bananas
|
||||
item2:
|
||||
cats: apples
|
||||
thing:
|
||||
cats: oranges
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq w sample.yaml bob.item*.cats meow
|
||||
```
|
||||
will output:
|
||||
```yaml
|
||||
---
|
||||
bob:
|
||||
item1:
|
||||
cats: meow
|
||||
item2:
|
||||
cats: meow
|
||||
thing:
|
||||
cats: oranges
|
||||
```
|
||||
|
||||
### Array Splat
|
||||
Given a sample.yaml file of:
|
||||
```yaml
|
||||
---
|
||||
bob:
|
||||
- cats: bananas
|
||||
- cats: apples
|
||||
- cats: oranges
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq w sample.yaml bob[*].cats meow
|
||||
```
|
||||
will output:
|
||||
```yaml
|
||||
---
|
||||
bob:
|
||||
- cats: meow
|
||||
- cats: meow
|
||||
- cats: meow
|
||||
```
|
||||
|
||||
### Appending value to an array field
|
||||
Given a sample.yaml file of:
|
||||
```yaml
|
||||
@@ -136,7 +214,7 @@ b:
|
||||
and a script update_instructions.yaml of:
|
||||
```yaml
|
||||
b.c: 3
|
||||
b.e[0].name: Howdy Partner
|
||||
b.e[+].name: Howdy Partner
|
||||
```
|
||||
then
|
||||
|
||||
@@ -169,4 +247,4 @@ my:
|
||||
path: -3
|
||||
```
|
||||
|
||||
{!snippets/keys_with_dots.md!}
|
||||
{!snippets/niche.md!}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
package main
|
||||
|
||||
func parsePath(path string) []string {
|
||||
return parsePathAccum([]string{}, path)
|
||||
}
|
||||
|
||||
func parsePathAccum(paths []string, remaining string) []string {
|
||||
head, tail := nextYamlPath(remaining)
|
||||
if tail == "" {
|
||||
return append(paths, head)
|
||||
}
|
||||
return parsePathAccum(append(paths, head), tail)
|
||||
}
|
||||
|
||||
func nextYamlPath(path string) (pathElement string, remaining string) {
|
||||
switch path[0] {
|
||||
case '[':
|
||||
// e.g [0].blah.cat -> we need to return "0" and "blah.cat"
|
||||
return search(path[1:], []uint8{']'}, true)
|
||||
case '"':
|
||||
// e.g "a.b".blah.cat -> we need to return "a.b" and "blah.cat"
|
||||
return search(path[1:], []uint8{'"'}, true)
|
||||
default:
|
||||
// e.g "a.blah.cat" -> return "a" and "blah.cat"
|
||||
return search(path[0:], []uint8{'.', '['}, false)
|
||||
}
|
||||
}
|
||||
|
||||
func search(path string, matchingChars []uint8, skipNext bool) (pathElement string, remaining string) {
|
||||
for i := 0; i < len(path); i++ {
|
||||
var char = path[i]
|
||||
if contains(matchingChars, char) {
|
||||
var remainingStart = i + 1
|
||||
if skipNext {
|
||||
remainingStart = remainingStart + 1
|
||||
} else if !skipNext && char != '.' {
|
||||
remainingStart = i
|
||||
}
|
||||
if remainingStart > len(path) {
|
||||
remainingStart = len(path)
|
||||
}
|
||||
return path[0:i], path[remainingStart:]
|
||||
}
|
||||
}
|
||||
return path, ""
|
||||
}
|
||||
|
||||
func contains(matchingChars []uint8, candidate uint8) bool {
|
||||
for _, a := range matchingChars {
|
||||
if a == candidate {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var parsePathsTests = []struct {
|
||||
path string
|
||||
expectedPaths []string
|
||||
}{
|
||||
{"a.b", []string{"a", "b"}},
|
||||
{"a.b[0]", []string{"a", "b", "0"}},
|
||||
{"a.b.d[+]", []string{"a", "b", "d", "+"}},
|
||||
}
|
||||
|
||||
func TestParsePath(t *testing.T) {
|
||||
for _, tt := range parsePathsTests {
|
||||
assertResultComplex(t, tt.expectedPaths, parsePath(tt.path))
|
||||
}
|
||||
}
|
||||
|
||||
var nextYamlPathTests = []struct {
|
||||
path string
|
||||
expectedElement string
|
||||
expectedRemaining string
|
||||
}{
|
||||
{"a.b", "a", "b"},
|
||||
{"a", "a", ""},
|
||||
{"a.b.c", "a", "b.c"},
|
||||
{"\"a.b\".c", "a.b", "c"},
|
||||
{"a.\"b.c\".d", "a", "\"b.c\".d"},
|
||||
{"[1].a.d", "1", "a.d"},
|
||||
{"a[0].c", "a", "[0].c"},
|
||||
{"[0]", "0", ""},
|
||||
}
|
||||
|
||||
func TestNextYamlPath(t *testing.T) {
|
||||
for _, tt := range nextYamlPathTests {
|
||||
var element, remaining = nextYamlPath(tt.path)
|
||||
assertResultWithContext(t, tt.expectedElement, element, tt)
|
||||
assertResultWithContext(t, tt.expectedRemaining, remaining, tt)
|
||||
}
|
||||
}
|
||||
54
pkg/marshal/json_converter.go
Normal file
54
pkg/marshal/json_converter.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package marshal
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
yaml "github.com/mikefarah/yaml/v2"
|
||||
)
|
||||
|
||||
type JsonConverter interface {
|
||||
JsonToString(context interface{}) (string, error)
|
||||
}
|
||||
|
||||
type jsonConverter struct{}
|
||||
|
||||
func NewJsonConverter() JsonConverter {
|
||||
return &jsonConverter{}
|
||||
}
|
||||
|
||||
func (j *jsonConverter) JsonToString(context interface{}) (string, error) {
|
||||
out, err := json.Marshal(j.toJSON(context))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error printing yaml as json: %v", err)
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
func (j *jsonConverter) toJSON(context interface{}) interface{} {
|
||||
switch context := context.(type) {
|
||||
case []interface{}:
|
||||
oldArray := context
|
||||
newArray := make([]interface{}, len(oldArray))
|
||||
for index, value := range oldArray {
|
||||
newArray[index] = j.toJSON(value)
|
||||
}
|
||||
return newArray
|
||||
case yaml.MapSlice:
|
||||
oldMap := context
|
||||
newMap := make(map[string]interface{})
|
||||
for _, entry := range oldMap {
|
||||
if str, ok := entry.Key.(string); ok {
|
||||
newMap[str] = j.toJSON(entry.Value)
|
||||
} else if i, ok := entry.Key.(int); ok {
|
||||
newMap[strconv.Itoa(i)] = j.toJSON(entry.Value)
|
||||
} else if b, ok := entry.Key.(bool); ok {
|
||||
newMap[strconv.FormatBool(b)] = j.toJSON(entry.Value)
|
||||
}
|
||||
}
|
||||
return newMap
|
||||
default:
|
||||
return context
|
||||
}
|
||||
}
|
||||
48
pkg/marshal/json_converter_test.go
Normal file
48
pkg/marshal/json_converter_test.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package marshal
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mikefarah/yq/v2/test"
|
||||
)
|
||||
|
||||
func TestJsonToString(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
got, _ := NewJsonConverter().JsonToString(data)
|
||||
test.AssertResult(t, "{\"b\":{\"c\":2}}", got)
|
||||
}
|
||||
|
||||
func TestJsonToString_withIntKey(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
2: c
|
||||
`)
|
||||
got, _ := NewJsonConverter().JsonToString(data)
|
||||
test.AssertResult(t, `{"b":{"2":"c"}}`, got)
|
||||
}
|
||||
|
||||
func TestJsonToString_withBoolKey(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
false: c
|
||||
`)
|
||||
got, _ := NewJsonConverter().JsonToString(data)
|
||||
test.AssertResult(t, `{"b":{"false":"c"}}`, got)
|
||||
}
|
||||
|
||||
func TestJsonToString_withArray(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
- item: one
|
||||
- item: two
|
||||
`)
|
||||
got, _ := NewJsonConverter().JsonToString(data)
|
||||
test.AssertResult(t, "{\"b\":[{\"item\":\"one\"},{\"item\":\"two\"}]}", got)
|
||||
}
|
||||
43
pkg/marshal/yaml_converter.go
Normal file
43
pkg/marshal/yaml_converter.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package marshal
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
yaml "github.com/mikefarah/yaml/v2"
|
||||
errors "github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type YamlConverter interface {
|
||||
YamlToString(context interface{}, trimOutput bool) (string, error)
|
||||
}
|
||||
|
||||
type yamlConverter struct{}
|
||||
|
||||
func NewYamlConverter() YamlConverter {
|
||||
return &yamlConverter{}
|
||||
}
|
||||
|
||||
func (y *yamlConverter) YamlToString(context interface{}, trimOutput bool) (string, error) {
|
||||
switch context := context.(type) {
|
||||
case string:
|
||||
return context, nil
|
||||
default:
|
||||
return y.marshalContext(context, trimOutput)
|
||||
}
|
||||
}
|
||||
|
||||
func (y *yamlConverter) marshalContext(context interface{}, trimOutput bool) (string, error) {
|
||||
out, err := yaml.Marshal(context)
|
||||
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error printing yaml")
|
||||
}
|
||||
|
||||
outStr := string(out)
|
||||
// trim the trailing new line as it's easier for a script to add
|
||||
// it in if required than to remove it
|
||||
if trimOutput {
|
||||
return strings.Trim(outStr, "\n "), nil
|
||||
}
|
||||
return outStr, nil
|
||||
}
|
||||
52
pkg/marshal/yaml_converter_test.go
Normal file
52
pkg/marshal/yaml_converter_test.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package marshal
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mikefarah/yq/v2/test"
|
||||
)
|
||||
|
||||
func TestYamlToString(t *testing.T) {
|
||||
var raw = `b:
|
||||
c: 2
|
||||
`
|
||||
var data = test.ParseData(raw)
|
||||
got, _ := NewYamlConverter().YamlToString(data, false)
|
||||
test.AssertResult(t, raw, got)
|
||||
}
|
||||
|
||||
func TestYamlToString_withTrim(t *testing.T) {
|
||||
var raw = `b:
|
||||
c: 2`
|
||||
var data = test.ParseData(raw)
|
||||
got, _ := NewYamlConverter().YamlToString(data, true)
|
||||
test.AssertResult(t, raw, got)
|
||||
}
|
||||
|
||||
func TestYamlToString_withIntKey(t *testing.T) {
|
||||
var raw = `b:
|
||||
2: c
|
||||
`
|
||||
var data = test.ParseData(raw)
|
||||
got, _ := NewYamlConverter().YamlToString(data, false)
|
||||
test.AssertResult(t, raw, got)
|
||||
}
|
||||
|
||||
func TestYamlToString_withBoolKey(t *testing.T) {
|
||||
var raw = `b:
|
||||
false: c
|
||||
`
|
||||
var data = test.ParseData(raw)
|
||||
got, _ := NewYamlConverter().YamlToString(data, false)
|
||||
test.AssertResult(t, raw, got)
|
||||
}
|
||||
|
||||
func TestYamlToString_withArray(t *testing.T) {
|
||||
var raw = `b:
|
||||
- item: one
|
||||
- item: two
|
||||
`
|
||||
var data = test.ParseData(raw)
|
||||
got, _ := NewYamlConverter().YamlToString(data, false)
|
||||
test.AssertResult(t, raw, got)
|
||||
}
|
||||
376
pkg/yqlib/data_navigator.go
Normal file
376
pkg/yqlib/data_navigator.go
Normal file
@@ -0,0 +1,376 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
yaml "github.com/mikefarah/yaml/v2"
|
||||
logging "gopkg.in/op/go-logging.v1"
|
||||
)
|
||||
|
||||
type DataNavigator interface {
|
||||
ReadChildValue(child interface{}, remainingPaths []string) (interface{}, error)
|
||||
UpdatedChildValue(child interface{}, remainingPaths []string, value interface{}) interface{}
|
||||
DeleteChildValue(child interface{}, remainingPaths []string) (interface{}, error)
|
||||
}
|
||||
|
||||
type navigator struct {
|
||||
log *logging.Logger
|
||||
}
|
||||
|
||||
func NewDataNavigator(l *logging.Logger) DataNavigator {
|
||||
return &navigator{
|
||||
log: l,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *navigator) ReadChildValue(child interface{}, remainingPaths []string) (interface{}, error) {
|
||||
if len(remainingPaths) == 0 {
|
||||
return child, nil
|
||||
}
|
||||
return n.recurse(child, remainingPaths[0], remainingPaths[1:])
|
||||
}
|
||||
|
||||
func (n *navigator) UpdatedChildValue(child interface{}, remainingPaths []string, value interface{}) interface{} {
|
||||
if len(remainingPaths) == 0 {
|
||||
return value
|
||||
}
|
||||
n.log.Debugf("UpdatedChildValue for child %v with path %v to set value %v", child, remainingPaths, value)
|
||||
n.log.Debugf("type of child is %v", reflect.TypeOf(child))
|
||||
|
||||
switch child := child.(type) {
|
||||
case nil:
|
||||
if remainingPaths[0] == "+" || remainingPaths[0] == "*" {
|
||||
return n.writeArray(child, remainingPaths, value)
|
||||
}
|
||||
case []interface{}:
|
||||
_, nextIndexErr := strconv.ParseInt(remainingPaths[0], 10, 64)
|
||||
arrayCommand := nextIndexErr == nil || remainingPaths[0] == "+" || remainingPaths[0] == "*"
|
||||
if arrayCommand {
|
||||
return n.writeArray(child, remainingPaths, value)
|
||||
}
|
||||
}
|
||||
return n.writeMap(child, remainingPaths, value)
|
||||
}
|
||||
|
||||
func (n *navigator) DeleteChildValue(child interface{}, remainingPaths []string) (interface{}, error) {
|
||||
n.log.Debugf("DeleteChildValue for %v for %v\n", remainingPaths, child)
|
||||
if len(remainingPaths) == 0 {
|
||||
return child, nil
|
||||
}
|
||||
var head = remainingPaths[0]
|
||||
var tail = remainingPaths[1:]
|
||||
switch child := child.(type) {
|
||||
case yaml.MapSlice:
|
||||
return n.deleteMap(child, remainingPaths)
|
||||
case []interface{}:
|
||||
if head == "*" {
|
||||
return n.deleteArraySplat(child, tail)
|
||||
}
|
||||
index, err := strconv.ParseInt(head, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error accessing array: %v", err)
|
||||
}
|
||||
return n.deleteArray(child, remainingPaths, index)
|
||||
}
|
||||
return child, nil
|
||||
}
|
||||
|
||||
func (n *navigator) recurse(value interface{}, head string, tail []string) (interface{}, error) {
|
||||
switch value := value.(type) {
|
||||
case []interface{}:
|
||||
if head == "*" {
|
||||
return n.readArraySplat(value, tail)
|
||||
}
|
||||
index, err := strconv.ParseInt(head, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error accessing array: %v", err)
|
||||
}
|
||||
return n.readArray(value, index, tail)
|
||||
case yaml.MapSlice:
|
||||
return n.readMap(value, head, tail)
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (n *navigator) matchesKey(key string, actual interface{}) bool {
|
||||
var actualString = fmt.Sprintf("%v", actual)
|
||||
var prefixMatch = strings.TrimSuffix(key, "*")
|
||||
if prefixMatch != key {
|
||||
return strings.HasPrefix(actualString, prefixMatch)
|
||||
}
|
||||
return actualString == key
|
||||
}
|
||||
|
||||
func (n *navigator) entriesInSlice(context yaml.MapSlice, key string) []*yaml.MapItem {
|
||||
var matches = make([]*yaml.MapItem, 0)
|
||||
for idx := range context {
|
||||
var entry = &context[idx]
|
||||
if n.matchesKey(key, entry.Key) {
|
||||
matches = append(matches, entry)
|
||||
}
|
||||
}
|
||||
return matches
|
||||
}
|
||||
|
||||
func (n *navigator) getMapSlice(context interface{}) yaml.MapSlice {
|
||||
var mapSlice yaml.MapSlice
|
||||
switch context := context.(type) {
|
||||
case yaml.MapSlice:
|
||||
mapSlice = context
|
||||
default:
|
||||
mapSlice = make(yaml.MapSlice, 0)
|
||||
}
|
||||
return mapSlice
|
||||
}
|
||||
|
||||
func (n *navigator) getArray(context interface{}) (array []interface{}, ok bool) {
|
||||
switch context := context.(type) {
|
||||
case []interface{}:
|
||||
array = context
|
||||
ok = true
|
||||
default:
|
||||
array = make([]interface{}, 0)
|
||||
ok = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (n *navigator) writeMap(context interface{}, paths []string, value interface{}) interface{} {
|
||||
n.log.Debugf("writeMap with path %v for %v to set value %v\n", paths, context, value)
|
||||
|
||||
mapSlice := n.getMapSlice(context)
|
||||
|
||||
if len(paths) == 0 {
|
||||
return context
|
||||
}
|
||||
|
||||
children := n.entriesInSlice(mapSlice, paths[0])
|
||||
|
||||
if len(children) == 0 && paths[0] == "*" {
|
||||
n.log.Debugf("\tNo matches, return map as is")
|
||||
return context
|
||||
}
|
||||
|
||||
if len(children) == 0 {
|
||||
newChild := yaml.MapItem{Key: paths[0]}
|
||||
mapSlice = append(mapSlice, newChild)
|
||||
children = n.entriesInSlice(mapSlice, paths[0])
|
||||
n.log.Debugf("\tAppended child at %v for mapSlice %v\n", paths[0], mapSlice)
|
||||
}
|
||||
|
||||
remainingPaths := paths[1:]
|
||||
for _, child := range children {
|
||||
child.Value = n.UpdatedChildValue(child.Value, remainingPaths, value)
|
||||
}
|
||||
n.log.Debugf("\tReturning mapSlice %v\n", mapSlice)
|
||||
return mapSlice
|
||||
}
|
||||
|
||||
func (n *navigator) writeArray(context interface{}, paths []string, value interface{}) []interface{} {
|
||||
n.log.Debugf("writeArray with path %v for %v to set value %v\n", paths, context, value)
|
||||
array, _ := n.getArray(context)
|
||||
|
||||
if len(paths) == 0 {
|
||||
return array
|
||||
}
|
||||
|
||||
n.log.Debugf("\tarray %v\n", array)
|
||||
|
||||
rawIndex := paths[0]
|
||||
remainingPaths := paths[1:]
|
||||
var index int64
|
||||
// the append array indicator
|
||||
if rawIndex == "+" {
|
||||
index = int64(len(array))
|
||||
} else if rawIndex == "*" {
|
||||
for index, oldChild := range array {
|
||||
array[index] = n.UpdatedChildValue(oldChild, remainingPaths, value)
|
||||
}
|
||||
return array
|
||||
} else {
|
||||
index, _ = strconv.ParseInt(rawIndex, 10, 64) // nolint
|
||||
// writeArray is only called by UpdatedChildValue which handles parsing the
|
||||
// index, as such this renders this dead code.
|
||||
}
|
||||
|
||||
for index >= int64(len(array)) {
|
||||
array = append(array, nil)
|
||||
}
|
||||
currentChild := array[index]
|
||||
|
||||
n.log.Debugf("\tcurrentChild %v\n", currentChild)
|
||||
|
||||
array[index] = n.UpdatedChildValue(currentChild, remainingPaths, value)
|
||||
n.log.Debugf("\tReturning array %v\n", array)
|
||||
return array
|
||||
}
|
||||
|
||||
func (n *navigator) readMap(context yaml.MapSlice, head string, tail []string) (interface{}, error) {
|
||||
n.log.Debugf("readingMap %v with key %v\n", context, head)
|
||||
if head == "*" {
|
||||
return n.readMapSplat(context, tail)
|
||||
}
|
||||
|
||||
entries := n.entriesInSlice(context, head)
|
||||
if len(entries) == 1 {
|
||||
return n.calculateValue(entries[0].Value, tail)
|
||||
} else if len(entries) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
var errInIdx error
|
||||
values := make([]interface{}, len(entries))
|
||||
for idx, entry := range entries {
|
||||
values[idx], errInIdx = n.calculateValue(entry.Value, tail)
|
||||
if errInIdx != nil {
|
||||
n.log.Errorf("Error updating index %v in %v", idx, context)
|
||||
return nil, errInIdx
|
||||
}
|
||||
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func (n *navigator) readMapSplat(context yaml.MapSlice, tail []string) (interface{}, error) {
|
||||
var newArray = make([]interface{}, len(context))
|
||||
var i = 0
|
||||
for _, entry := range context {
|
||||
if len(tail) > 0 {
|
||||
val, err := n.recurse(entry.Value, tail[0], tail[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newArray[i] = val
|
||||
} else {
|
||||
newArray[i] = entry.Value
|
||||
}
|
||||
i++
|
||||
}
|
||||
return newArray, nil
|
||||
}
|
||||
|
||||
func (n *navigator) readArray(array []interface{}, head int64, tail []string) (interface{}, error) {
|
||||
if head >= int64(len(array)) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
value := array[head]
|
||||
return n.calculateValue(value, tail)
|
||||
}
|
||||
|
||||
func (n *navigator) readArraySplat(array []interface{}, tail []string) (interface{}, error) {
|
||||
var newArray = make([]interface{}, len(array))
|
||||
for index, value := range array {
|
||||
val, err := n.calculateValue(value, tail)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newArray[index] = val
|
||||
}
|
||||
return newArray, nil
|
||||
}
|
||||
|
||||
func (n *navigator) calculateValue(value interface{}, tail []string) (interface{}, error) {
|
||||
if len(tail) > 0 {
|
||||
return n.recurse(value, tail[0], tail[1:])
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (n *navigator) deleteMap(context interface{}, paths []string) (yaml.MapSlice, error) {
|
||||
n.log.Debugf("deleteMap for %v for %v\n", paths, context)
|
||||
|
||||
mapSlice := n.getMapSlice(context)
|
||||
|
||||
if len(paths) == 0 {
|
||||
return mapSlice, nil
|
||||
}
|
||||
|
||||
var index int
|
||||
var child yaml.MapItem
|
||||
for index, child = range mapSlice {
|
||||
if n.matchesKey(paths[0], child.Key) {
|
||||
n.log.Debugf("\tMatched [%v] with [%v] at index %v", paths[0], child.Key, index)
|
||||
var badDelete error
|
||||
mapSlice, badDelete = n.deleteEntryInMap(mapSlice, child, index, paths)
|
||||
if badDelete != nil {
|
||||
return nil, badDelete
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mapSlice, nil
|
||||
|
||||
}
|
||||
|
||||
func (n *navigator) deleteEntryInMap(original yaml.MapSlice, child yaml.MapItem, index int, paths []string) (yaml.MapSlice, error) {
|
||||
remainingPaths := paths[1:]
|
||||
|
||||
var newSlice yaml.MapSlice
|
||||
if len(remainingPaths) > 0 {
|
||||
newChild := yaml.MapItem{Key: child.Key}
|
||||
var errorDeleting error
|
||||
newChild.Value, errorDeleting = n.DeleteChildValue(child.Value, remainingPaths)
|
||||
if errorDeleting != nil {
|
||||
return nil, errorDeleting
|
||||
}
|
||||
|
||||
newSlice = make(yaml.MapSlice, len(original))
|
||||
for i := range original {
|
||||
item := original[i]
|
||||
if i == index {
|
||||
item = newChild
|
||||
}
|
||||
newSlice[i] = item
|
||||
}
|
||||
} else {
|
||||
// Delete item from slice at index
|
||||
newSlice = append(original[:index], original[index+1:]...)
|
||||
n.log.Debugf("\tDeleted item index %d from original", index)
|
||||
}
|
||||
|
||||
n.log.Debugf("\tReturning original %v\n", original)
|
||||
return newSlice, nil
|
||||
}
|
||||
|
||||
func (n *navigator) deleteArraySplat(array []interface{}, tail []string) (interface{}, error) {
|
||||
n.log.Debugf("deleteArraySplat for %v for %v\n", tail, array)
|
||||
var newArray = make([]interface{}, len(array))
|
||||
for index, value := range array {
|
||||
val, err := n.DeleteChildValue(value, tail)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newArray[index] = val
|
||||
}
|
||||
return newArray, nil
|
||||
}
|
||||
|
||||
func (n *navigator) deleteArray(array []interface{}, paths []string, index int64) (interface{}, error) {
|
||||
n.log.Debugf("deleteArray for %v for %v\n", paths, array)
|
||||
|
||||
if index >= int64(len(array)) {
|
||||
return array, nil
|
||||
}
|
||||
|
||||
remainingPaths := paths[1:]
|
||||
if len(remainingPaths) > 0 {
|
||||
// recurse into the array element at index
|
||||
var errorDeleting error
|
||||
array[index], errorDeleting = n.deleteMap(array[index], remainingPaths)
|
||||
if errorDeleting != nil {
|
||||
return nil, errorDeleting
|
||||
}
|
||||
|
||||
} else {
|
||||
// Delete the array element at index
|
||||
array = append(array[:index], array[index+1:]...)
|
||||
n.log.Debugf("\tDeleted item index %d from array, leaving %v", index, array)
|
||||
}
|
||||
|
||||
n.log.Debugf("\tReturning array: %v\n", array)
|
||||
return array, nil
|
||||
}
|
||||
397
pkg/yqlib/data_navigator_test.go
Normal file
397
pkg/yqlib/data_navigator_test.go
Normal file
@@ -0,0 +1,397 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/mikefarah/yq/v2/test"
|
||||
logging "gopkg.in/op/go-logging.v1"
|
||||
)
|
||||
|
||||
func TestDataNavigator(t *testing.T) {
|
||||
var log = logging.MustGetLogger("yq")
|
||||
subject := NewDataNavigator(log)
|
||||
|
||||
t.Run("TestReadMap_simple", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
got, _ := subject.ReadChildValue(data, []string{"b", "c"})
|
||||
test.AssertResult(t, 2, got)
|
||||
})
|
||||
|
||||
t.Run("TestReadMap_numberKey", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
200: things
|
||||
`)
|
||||
got, _ := subject.ReadChildValue(data, []string{"200"})
|
||||
test.AssertResult(t, "things", got)
|
||||
})
|
||||
|
||||
t.Run("TestReadMap_splat", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
mapSplat:
|
||||
item1: things
|
||||
item2: whatever
|
||||
otherThing: cat
|
||||
`)
|
||||
res, _ := subject.ReadChildValue(data, []string{"mapSplat", "*"})
|
||||
test.AssertResult(t, "[things whatever cat]", fmt.Sprintf("%v", res))
|
||||
})
|
||||
|
||||
t.Run("TestReadMap_prefixSplat", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
mapSplat:
|
||||
item1: things
|
||||
item2: whatever
|
||||
otherThing: cat
|
||||
`)
|
||||
res, _ := subject.ReadChildValue(data, []string{"mapSplat", "item*"})
|
||||
test.AssertResult(t, "[things whatever]", fmt.Sprintf("%v", res))
|
||||
})
|
||||
|
||||
t.Run("TestReadMap_deep_splat", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
mapSplatDeep:
|
||||
item1:
|
||||
cats: bananas
|
||||
item2:
|
||||
cats: apples
|
||||
`)
|
||||
|
||||
res, _ := subject.ReadChildValue(data, []string{"mapSplatDeep", "*", "cats"})
|
||||
result := res.([]interface{})
|
||||
var actual = []string{result[0].(string), result[1].(string)}
|
||||
sort.Strings(actual)
|
||||
test.AssertResult(t, "[apples bananas]", fmt.Sprintf("%v", actual))
|
||||
})
|
||||
|
||||
t.Run("TestReadMap_key_doesnt_exist", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
got, _ := subject.ReadChildValue(data, []string{"b", "x", "f", "c"})
|
||||
test.AssertResult(t, nil, got)
|
||||
})
|
||||
|
||||
t.Run("TestReadMap_recurse_against_string", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
a: cat
|
||||
`)
|
||||
got, _ := subject.ReadChildValue(data, []string{"a", "b"})
|
||||
test.AssertResult(t, nil, got)
|
||||
})
|
||||
|
||||
t.Run("TestReadMap_with_array", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
d:
|
||||
- 3
|
||||
- 4
|
||||
`)
|
||||
got, _ := subject.ReadChildValue(data, []string{"b", "d", "1"})
|
||||
test.AssertResult(t, 4, got)
|
||||
})
|
||||
|
||||
t.Run("TestReadMap_with_array_and_bad_index", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
d:
|
||||
- 3
|
||||
- 4
|
||||
`)
|
||||
_, err := subject.ReadChildValue(data, []string{"b", "d", "x"})
|
||||
if err == nil {
|
||||
t.Fatal("Expected error due to invalid path")
|
||||
}
|
||||
expectedOutput := `error accessing array: strconv.ParseInt: parsing "x": invalid syntax`
|
||||
test.AssertResult(t, expectedOutput, err.Error())
|
||||
})
|
||||
|
||||
t.Run("TestReadMap_with_mapsplat_array_and_bad_index", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
d:
|
||||
e:
|
||||
- 3
|
||||
- 4
|
||||
f:
|
||||
- 1
|
||||
- 2
|
||||
`)
|
||||
_, err := subject.ReadChildValue(data, []string{"b", "d", "*", "x"})
|
||||
if err == nil {
|
||||
t.Fatal("Expected error due to invalid path")
|
||||
}
|
||||
expectedOutput := `error accessing array: strconv.ParseInt: parsing "x": invalid syntax`
|
||||
test.AssertResult(t, expectedOutput, err.Error())
|
||||
})
|
||||
|
||||
t.Run("TestReadMap_with_arraysplat_map_array_and_bad_index", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
d:
|
||||
- names:
|
||||
- fred
|
||||
- smith
|
||||
- names:
|
||||
- sam
|
||||
- bo
|
||||
`)
|
||||
_, err := subject.ReadChildValue(data, []string{"b", "d", "*", "names", "x"})
|
||||
if err == nil {
|
||||
t.Fatal("Expected error due to invalid path")
|
||||
}
|
||||
expectedOutput := `error accessing array: strconv.ParseInt: parsing "x": invalid syntax`
|
||||
test.AssertResult(t, expectedOutput, err.Error())
|
||||
})
|
||||
|
||||
t.Run("TestReadMap_with_array_out_of_bounds", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
d:
|
||||
- 3
|
||||
- 4
|
||||
`)
|
||||
got, _ := subject.ReadChildValue(data, []string{"b", "d", "3"})
|
||||
test.AssertResult(t, nil, got)
|
||||
})
|
||||
|
||||
t.Run("TestReadMap_with_array_out_of_bounds_by_1", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
d:
|
||||
- 3
|
||||
- 4
|
||||
`)
|
||||
got, _ := subject.ReadChildValue(data, []string{"b", "d", "2"})
|
||||
test.AssertResult(t, nil, got)
|
||||
})
|
||||
|
||||
t.Run("TestReadMap_with_array_splat", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
e:
|
||||
-
|
||||
name: Fred
|
||||
thing: cat
|
||||
-
|
||||
name: Sam
|
||||
thing: dog
|
||||
`)
|
||||
got, _ := subject.ReadChildValue(data, []string{"e", "*", "name"})
|
||||
test.AssertResult(t, "[Fred Sam]", fmt.Sprintf("%v", got))
|
||||
})
|
||||
|
||||
t.Run("TestWrite_really_simple", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
b: 2
|
||||
`)
|
||||
|
||||
updated := subject.UpdatedChildValue(data, []string{"b"}, "4")
|
||||
test.AssertResult(t, "[{b 4}]", fmt.Sprintf("%v", updated))
|
||||
})
|
||||
|
||||
t.Run("TestWrite_simple", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
|
||||
updated := subject.UpdatedChildValue(data, []string{"b", "c"}, "4")
|
||||
test.AssertResult(t, "[{b [{c 4}]}]", fmt.Sprintf("%v", updated))
|
||||
})
|
||||
|
||||
t.Run("TestWrite_new", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
|
||||
updated := subject.UpdatedChildValue(data, []string{"b", "d"}, "4")
|
||||
test.AssertResult(t, "[{b [{c 2} {d 4}]}]", fmt.Sprintf("%v", updated))
|
||||
})
|
||||
|
||||
t.Run("TestWrite_new_deep", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
|
||||
updated := subject.UpdatedChildValue(data, []string{"b", "d", "f"}, "4")
|
||||
test.AssertResult(t, "[{b [{c 2} {d [{f 4}]}]}]", fmt.Sprintf("%v", updated))
|
||||
})
|
||||
|
||||
t.Run("TestWrite_array", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
b:
|
||||
- aa
|
||||
`)
|
||||
|
||||
updated := subject.UpdatedChildValue(data, []string{"b", "0"}, "bb")
|
||||
|
||||
test.AssertResult(t, "[{b [bb]}]", fmt.Sprintf("%v", updated))
|
||||
})
|
||||
|
||||
t.Run("TestWrite_new_array", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
|
||||
updated := subject.UpdatedChildValue(data, []string{"b", "0"}, "4")
|
||||
test.AssertResult(t, "[{b [{c 2} {0 4}]}]", fmt.Sprintf("%v", updated))
|
||||
})
|
||||
|
||||
t.Run("TestWrite_new_array_deep", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
a: apple
|
||||
`)
|
||||
|
||||
updated := subject.UpdatedChildValue(data, []string{"b", "+", "c"}, "4")
|
||||
test.AssertResult(t, "[{a apple} {b [[{c 4}]]}]", fmt.Sprintf("%v", updated))
|
||||
})
|
||||
|
||||
t.Run("TestWrite_new_map_array_deep", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
|
||||
updated := subject.UpdatedChildValue(data, []string{"b", "d", "+"}, "4")
|
||||
test.AssertResult(t, "[{b [{c 2} {d [4]}]}]", fmt.Sprintf("%v", updated))
|
||||
})
|
||||
|
||||
t.Run("TestWrite_add_to_array", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
b:
|
||||
- aa
|
||||
`)
|
||||
|
||||
updated := subject.UpdatedChildValue(data, []string{"b", "1"}, "bb")
|
||||
test.AssertResult(t, "[{b [aa bb]}]", fmt.Sprintf("%v", updated))
|
||||
})
|
||||
|
||||
t.Run("TestWrite_with_no_tail", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
b:
|
||||
c: 2
|
||||
`)
|
||||
updated := subject.UpdatedChildValue(data, []string{"b"}, "4")
|
||||
|
||||
test.AssertResult(t, "[{b 4}]", fmt.Sprintf("%v", updated))
|
||||
})
|
||||
|
||||
t.Run("TestWriteMap_no_paths", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
b: 5
|
||||
`)
|
||||
var new = test.ParseData(`
|
||||
c: 4
|
||||
`)
|
||||
result := subject.UpdatedChildValue(data, []string{}, new)
|
||||
test.AssertResult(t, fmt.Sprintf("%v", new), fmt.Sprintf("%v", result))
|
||||
})
|
||||
|
||||
t.Run("TestWriteArray_no_paths", func(t *testing.T) {
|
||||
var data = make([]interface{}, 1)
|
||||
data[0] = "mike"
|
||||
var new = test.ParseData(`
|
||||
c: 4
|
||||
`)
|
||||
result := subject.UpdatedChildValue(data, []string{}, new)
|
||||
test.AssertResult(t, fmt.Sprintf("%v", new), fmt.Sprintf("%v", result))
|
||||
})
|
||||
|
||||
t.Run("TestDelete_MapItem", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
a: 123
|
||||
b: 456
|
||||
`)
|
||||
var expected = test.ParseData(`
|
||||
b: 456
|
||||
`)
|
||||
|
||||
result, _ := subject.DeleteChildValue(data, []string{"a"})
|
||||
test.AssertResult(t, fmt.Sprintf("%v", expected), fmt.Sprintf("%v", result))
|
||||
})
|
||||
|
||||
// Ensure deleting an index into a string does nothing
|
||||
t.Run("TestDelete_index_to_string", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
a: mystring
|
||||
`)
|
||||
result, _ := subject.DeleteChildValue(data, []string{"a", "0"})
|
||||
test.AssertResult(t, fmt.Sprintf("%v", data), fmt.Sprintf("%v", result))
|
||||
})
|
||||
|
||||
t.Run("TestDelete_list_index", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
a: [3, 4]
|
||||
`)
|
||||
var expected = test.ParseData(`
|
||||
a: [3]
|
||||
`)
|
||||
result, _ := subject.DeleteChildValue(data, []string{"a", "1"})
|
||||
test.AssertResult(t, fmt.Sprintf("%v", expected), fmt.Sprintf("%v", result))
|
||||
})
|
||||
|
||||
t.Run("TestDelete_list_index_beyond_bounds", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
a: [3, 4]
|
||||
`)
|
||||
result, _ := subject.DeleteChildValue(data, []string{"a", "5"})
|
||||
test.AssertResult(t, fmt.Sprintf("%v", data), fmt.Sprintf("%v", result))
|
||||
})
|
||||
|
||||
t.Run("TestDelete_list_index_out_of_bounds_by_1", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
a: [3, 4]
|
||||
`)
|
||||
result, _ := subject.DeleteChildValue(data, []string{"a", "2"})
|
||||
test.AssertResult(t, fmt.Sprintf("%v", data), fmt.Sprintf("%v", result))
|
||||
})
|
||||
|
||||
t.Run("TestDelete_no_paths", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
a: [3, 4]
|
||||
b:
|
||||
- name: test
|
||||
`)
|
||||
result, _ := subject.DeleteChildValue(data, []string{})
|
||||
test.AssertResult(t, fmt.Sprintf("%v", data), fmt.Sprintf("%v", result))
|
||||
})
|
||||
|
||||
t.Run("TestDelete_array_map_item", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
b:
|
||||
- name: fred
|
||||
value: blah
|
||||
- name: john
|
||||
value: test
|
||||
`)
|
||||
var expected = test.ParseData(`
|
||||
b:
|
||||
- value: blah
|
||||
- name: john
|
||||
value: test
|
||||
`)
|
||||
result, _ := subject.DeleteChildValue(data, []string{"b", "0", "name"})
|
||||
test.AssertResult(t, fmt.Sprintf("%v", expected), fmt.Sprintf("%v", result))
|
||||
})
|
||||
}
|
||||
70
pkg/yqlib/lib.go
Normal file
70
pkg/yqlib/lib.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
mergo "gopkg.in/imdario/mergo.v0"
|
||||
logging "gopkg.in/op/go-logging.v1"
|
||||
)
|
||||
|
||||
type YqLib interface {
|
||||
ReadPath(dataBucket interface{}, path string) (interface{}, error)
|
||||
WritePath(dataBucket interface{}, path string, value interface{}) interface{}
|
||||
PrefixPath(dataBucket interface{}, prefix string) interface{}
|
||||
DeletePath(dataBucket interface{}, path string) (interface{}, error)
|
||||
Merge(dst interface{}, src interface{}, overwrite bool, append bool) error
|
||||
}
|
||||
|
||||
type lib struct {
|
||||
navigator DataNavigator
|
||||
parser PathParser
|
||||
}
|
||||
|
||||
func NewYqLib(l *logging.Logger) YqLib {
|
||||
return &lib{
|
||||
navigator: NewDataNavigator(l),
|
||||
parser: NewPathParser(),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *lib) ReadPath(dataBucket interface{}, path string) (interface{}, error) {
|
||||
var paths = l.parser.ParsePath(path)
|
||||
return l.navigator.ReadChildValue(dataBucket, paths)
|
||||
}
|
||||
|
||||
func (l *lib) WritePath(dataBucket interface{}, path string, value interface{}) interface{} {
|
||||
var paths = l.parser.ParsePath(path)
|
||||
return l.navigator.UpdatedChildValue(dataBucket, paths, value)
|
||||
}
|
||||
|
||||
func (l *lib) PrefixPath(dataBucket interface{}, prefix string) interface{} {
|
||||
var paths = l.parser.ParsePath(prefix)
|
||||
|
||||
// Inverse order
|
||||
for i := len(paths)/2 - 1; i >= 0; i-- {
|
||||
opp := len(paths) - 1 - i
|
||||
paths[i], paths[opp] = paths[opp], paths[i]
|
||||
}
|
||||
|
||||
var mapDataBucket = dataBucket
|
||||
for _, key := range paths {
|
||||
singlePath := []string{key}
|
||||
mapDataBucket = l.navigator.UpdatedChildValue(nil, singlePath, mapDataBucket)
|
||||
}
|
||||
|
||||
return mapDataBucket
|
||||
}
|
||||
|
||||
func (l *lib) DeletePath(dataBucket interface{}, path string) (interface{}, error) {
|
||||
var paths = l.parser.ParsePath(path)
|
||||
return l.navigator.DeleteChildValue(dataBucket, paths)
|
||||
}
|
||||
|
||||
func (l *lib) Merge(dst interface{}, src interface{}, overwriteFlag bool, appendFlag bool) error {
|
||||
opts := []func(*mergo.Config){}
|
||||
if overwriteFlag {
|
||||
opts = append(opts, mergo.WithOverride)
|
||||
}
|
||||
if appendFlag {
|
||||
opts = append(opts, mergo.WithAppendSlice)
|
||||
}
|
||||
return mergo.Merge(dst, src, opts...)
|
||||
}
|
||||
183
pkg/yqlib/lib_test.go
Normal file
183
pkg/yqlib/lib_test.go
Normal file
@@ -0,0 +1,183 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/mikefarah/yq/v2/test"
|
||||
logging "gopkg.in/op/go-logging.v1"
|
||||
)
|
||||
|
||||
func TestLib(t *testing.T) {
|
||||
|
||||
var log = logging.MustGetLogger("yq")
|
||||
subject := NewYqLib(log)
|
||||
|
||||
t.Run("TestReadPath", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
2: c
|
||||
`)
|
||||
|
||||
got, _ := subject.ReadPath(data, "b.2")
|
||||
test.AssertResult(t, `c`, got)
|
||||
})
|
||||
|
||||
t.Run("TestReadPath_WithError", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
- c
|
||||
`)
|
||||
|
||||
_, err := subject.ReadPath(data, "b.[a]")
|
||||
if err == nil {
|
||||
t.Fatal("Expected error due to invalid path")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("TestWritePath", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
2: c
|
||||
`)
|
||||
|
||||
got := subject.WritePath(data, "b.3", "a")
|
||||
test.AssertResult(t, `[{b [{2 c} {3 a}]}]`, fmt.Sprintf("%v", got))
|
||||
})
|
||||
|
||||
t.Run("TestPrefixPath", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
2: c
|
||||
`)
|
||||
|
||||
got := subject.PrefixPath(data, "a.d")
|
||||
test.AssertResult(t, `[{a [{d [{b [{2 c}]}]}]}]`, fmt.Sprintf("%v", got))
|
||||
})
|
||||
|
||||
t.Run("TestDeletePath", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
2: c
|
||||
3: a
|
||||
`)
|
||||
|
||||
got, _ := subject.DeletePath(data, "b.2")
|
||||
test.AssertResult(t, `[{b [{3 a}]}]`, fmt.Sprintf("%v", got))
|
||||
})
|
||||
|
||||
t.Run("TestDeletePath_WithError", func(t *testing.T) {
|
||||
var data = test.ParseData(`
|
||||
---
|
||||
b:
|
||||
- c
|
||||
`)
|
||||
|
||||
_, err := subject.DeletePath(data, "b.[a]")
|
||||
if err == nil {
|
||||
t.Fatal("Expected error due to invalid path")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("TestMerge", func(t *testing.T) {
|
||||
var dst = test.ParseData(`
|
||||
---
|
||||
a: b
|
||||
c: d
|
||||
`)
|
||||
var src = test.ParseData(`
|
||||
---
|
||||
a: 1
|
||||
b: 2
|
||||
`)
|
||||
|
||||
var mergedData = make(map[interface{}]interface{})
|
||||
mergedData["root"] = dst
|
||||
var mapDataBucket = make(map[interface{}]interface{})
|
||||
mapDataBucket["root"] = src
|
||||
|
||||
err := subject.Merge(&mergedData, mapDataBucket, false, false)
|
||||
if err != nil {
|
||||
t.Fatal("Unexpected error")
|
||||
}
|
||||
test.AssertResult(t, `[{a b} {c d}]`, fmt.Sprintf("%v", mergedData["root"]))
|
||||
})
|
||||
|
||||
t.Run("TestMerge_WithOverwrite", func(t *testing.T) {
|
||||
var dst = test.ParseData(`
|
||||
---
|
||||
a: b
|
||||
c: d
|
||||
`)
|
||||
var src = test.ParseData(`
|
||||
---
|
||||
a: 1
|
||||
b: 2
|
||||
`)
|
||||
|
||||
var mergedData = make(map[interface{}]interface{})
|
||||
mergedData["root"] = dst
|
||||
var mapDataBucket = make(map[interface{}]interface{})
|
||||
mapDataBucket["root"] = src
|
||||
|
||||
err := subject.Merge(&mergedData, mapDataBucket, true, false)
|
||||
if err != nil {
|
||||
t.Fatal("Unexpected error")
|
||||
}
|
||||
test.AssertResult(t, `[{a 1} {b 2}]`, fmt.Sprintf("%v", mergedData["root"]))
|
||||
})
|
||||
|
||||
t.Run("TestMerge_WithAppend", func(t *testing.T) {
|
||||
var dst = test.ParseData(`
|
||||
---
|
||||
a: b
|
||||
c: d
|
||||
`)
|
||||
var src = test.ParseData(`
|
||||
---
|
||||
a: 1
|
||||
b: 2
|
||||
`)
|
||||
|
||||
var mergedData = make(map[interface{}]interface{})
|
||||
mergedData["root"] = dst
|
||||
var mapDataBucket = make(map[interface{}]interface{})
|
||||
mapDataBucket["root"] = src
|
||||
|
||||
err := subject.Merge(&mergedData, mapDataBucket, false, true)
|
||||
if err != nil {
|
||||
t.Fatal("Unexpected error")
|
||||
}
|
||||
test.AssertResult(t, `[{a b} {c d} {a 1} {b 2}]`, fmt.Sprintf("%v", mergedData["root"]))
|
||||
})
|
||||
|
||||
t.Run("TestMerge_WithAppendAndOverwrite", func(t *testing.T) {
|
||||
var dst = map[interface{}]interface{}{
|
||||
"a": "initial",
|
||||
"b": []string{"old"},
|
||||
}
|
||||
var src = map[interface{}]interface{}{
|
||||
"a": "replaced",
|
||||
"b": []string{"new"},
|
||||
}
|
||||
|
||||
err := subject.Merge(&dst, src, true, true)
|
||||
if err != nil {
|
||||
t.Fatal("Unexpected error")
|
||||
}
|
||||
test.AssertResult(t, `map[a:replaced b:[old new]]`, fmt.Sprintf("%v", dst))
|
||||
})
|
||||
|
||||
t.Run("TestMerge_WithError", func(t *testing.T) {
|
||||
err := subject.Merge(nil, nil, false, false)
|
||||
if err == nil {
|
||||
t.Fatal("Expected error due to nil")
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
65
pkg/yqlib/path_parser.go
Normal file
65
pkg/yqlib/path_parser.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package yqlib
|
||||
|
||||
type PathParser interface {
|
||||
ParsePath(path string) []string
|
||||
}
|
||||
|
||||
type pathParser struct{}
|
||||
|
||||
func NewPathParser() PathParser {
|
||||
return &pathParser{}
|
||||
}
|
||||
|
||||
func (p *pathParser) ParsePath(path string) []string {
|
||||
return p.parsePathAccum([]string{}, path)
|
||||
}
|
||||
|
||||
func (p *pathParser) parsePathAccum(paths []string, remaining string) []string {
|
||||
head, tail := p.nextYamlPath(remaining)
|
||||
if tail == "" {
|
||||
return append(paths, head)
|
||||
}
|
||||
return p.parsePathAccum(append(paths, head), tail)
|
||||
}
|
||||
|
||||
func (p *pathParser) nextYamlPath(path string) (pathElement string, remaining string) {
|
||||
switch path[0] {
|
||||
case '[':
|
||||
// e.g [0].blah.cat -> we need to return "0" and "blah.cat"
|
||||
return p.search(path[1:], []uint8{']'}, true)
|
||||
case '"':
|
||||
// e.g "a.b".blah.cat -> we need to return "a.b" and "blah.cat"
|
||||
return p.search(path[1:], []uint8{'"'}, true)
|
||||
default:
|
||||
// e.g "a.blah.cat" -> return "a" and "blah.cat"
|
||||
return p.search(path[0:], []uint8{'.', '['}, false)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pathParser) search(path string, matchingChars []uint8, skipNext bool) (pathElement string, remaining string) {
|
||||
for i := 0; i < len(path); i++ {
|
||||
var char = path[i]
|
||||
if p.contains(matchingChars, char) {
|
||||
var remainingStart = i + 1
|
||||
if skipNext {
|
||||
remainingStart = remainingStart + 1
|
||||
} else if !skipNext && char != '.' {
|
||||
remainingStart = i
|
||||
}
|
||||
if remainingStart > len(path) {
|
||||
remainingStart = len(path)
|
||||
}
|
||||
return path[0:i], path[remainingStart:]
|
||||
}
|
||||
}
|
||||
return path, ""
|
||||
}
|
||||
|
||||
func (p *pathParser) contains(matchingChars []uint8, candidate uint8) bool {
|
||||
for _, a := range matchingChars {
|
||||
if a == candidate {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
29
pkg/yqlib/path_parser_test.go
Normal file
29
pkg/yqlib/path_parser_test.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mikefarah/yq/v2/test"
|
||||
)
|
||||
|
||||
var parsePathsTests = []struct {
|
||||
path string
|
||||
expectedPaths []string
|
||||
}{
|
||||
{"a.b", []string{"a", "b"}},
|
||||
{"a.b[0]", []string{"a", "b", "0"}},
|
||||
{"a.b.d[+]", []string{"a", "b", "d", "+"}},
|
||||
{"a", []string{"a"}},
|
||||
{"a.b.c", []string{"a", "b", "c"}},
|
||||
{"\"a.b\".c", []string{"a.b", "c"}},
|
||||
{"a.\"b.c\".d", []string{"a", "b.c", "d"}},
|
||||
{"[1].a.d", []string{"1", "a", "d"}},
|
||||
{"a[0].c", []string{"a", "0", "c"}},
|
||||
{"[0]", []string{"0"}},
|
||||
}
|
||||
|
||||
func TestParsePath(t *testing.T) {
|
||||
for _, tt := range parsePathsTests {
|
||||
test.AssertResultComplex(t, tt.expectedPaths, NewPathParser().ParsePath(tt.path))
|
||||
}
|
||||
}
|
||||
42
pkg/yqlib/value_parser.go
Normal file
42
pkg/yqlib/value_parser.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type ValueParser interface {
|
||||
ParseValue(argument string) interface{}
|
||||
}
|
||||
|
||||
type valueParser struct{}
|
||||
|
||||
func NewValueParser() ValueParser {
|
||||
return &valueParser{}
|
||||
}
|
||||
|
||||
func (v *valueParser) ParseValue(argument string) interface{} {
|
||||
var value, err interface{}
|
||||
var inQuotes = len(argument) > 0 && argument[0] == '"'
|
||||
if !inQuotes {
|
||||
intValue, intErr := strconv.ParseInt(argument, 10, 64)
|
||||
floatValue, floatErr := strconv.ParseFloat(argument, 64)
|
||||
if intErr == nil && floatErr == nil {
|
||||
if int64(floatValue) == intValue {
|
||||
return intValue
|
||||
}
|
||||
return floatValue
|
||||
} else if floatErr == nil {
|
||||
// In case cannot parse the int due to large precision
|
||||
return floatValue
|
||||
}
|
||||
value, err = strconv.ParseBool(argument)
|
||||
if err == nil {
|
||||
return value
|
||||
}
|
||||
if argument == "[]" {
|
||||
return make([]interface{}, 0)
|
||||
}
|
||||
return argument
|
||||
}
|
||||
return argument[1 : len(argument)-1]
|
||||
}
|
||||
26
pkg/yqlib/value_parser_test.go
Normal file
26
pkg/yqlib/value_parser_test.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package yqlib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mikefarah/yq/v2/test"
|
||||
)
|
||||
|
||||
var parseValueTests = []struct {
|
||||
argument string
|
||||
expectedResult interface{}
|
||||
testDescription string
|
||||
}{
|
||||
{"true", true, "boolean"},
|
||||
{"\"true\"", "true", "boolean as string"},
|
||||
{"3.4", 3.4, "number"},
|
||||
{"\"3.4\"", "3.4", "number as string"},
|
||||
{"", "", "empty string"},
|
||||
{"1212121", int64(1212121), "big number"},
|
||||
}
|
||||
|
||||
func TestParseValue(t *testing.T) {
|
||||
for _, tt := range parseValueTests {
|
||||
test.AssertResultWithContext(t, tt.expectedResult, NewValueParser().ParseValue(tt.argument), tt.testDescription)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
- increment version in version.go
|
||||
- increment version in snapcraft.yaml
|
||||
- commit
|
||||
- tag git with same version number
|
||||
- be sure to also tag with 'v' for gopkg.in
|
||||
- make sure local build passes
|
||||
@@ -19,13 +20,18 @@
|
||||
|
||||
then use the UI (https://snapcraft.io/yq/release)
|
||||
|
||||
- go get
|
||||
- update the readme instructions
|
||||
|
||||
- brew
|
||||
- brew bump-formula-pr --url=https://github.com/mikefarah/yq/archive/2.1.2.tar.gz yq
|
||||
- brew bump-formula-pr --url=https://github.com/mikefarah/yq/archive/2.2.0.tar.gz yq
|
||||
- if that fails with random ruby errors try:
|
||||
- clearing out the gems rm -rf .gem/ruby/2.3.0
|
||||
- export HOMEBREW_FORCE_VENDOR_RUBY=1
|
||||
|
||||
- docker
|
||||
- build and push latest and new version tag
|
||||
- docker build . --arg -t mikefarah/yq:latest -t mikefarah/yq:VERSION
|
||||
- docker build . -t mikefarah/yq:latest -t mikefarah/yq:VERSION
|
||||
|
||||
- debian package
|
||||
- execute
|
||||
|
||||
@@ -6,7 +6,7 @@ set -e
|
||||
X=$(./yq w ./examples/sample.yaml b.c 3 | ./yq r - b.c)
|
||||
|
||||
if [[ $X != 3 ]]; then
|
||||
echo "Failed acceptance test: expected 2 but was $X"
|
||||
echo "Failed acceptance test: expected 3 but was $X"
|
||||
exit 1
|
||||
fi
|
||||
echo "acceptance tests passed"
|
||||
|
||||
@@ -3,24 +3,14 @@
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
gometalinter \
|
||||
--skip=examples \
|
||||
--tests \
|
||||
--vendor \
|
||||
--disable=aligncheck \
|
||||
--disable=gotype \
|
||||
--disable=goconst \
|
||||
--cyclo-over=20 \
|
||||
--deadline=300s \
|
||||
./...
|
||||
./bin/golangci-lint run
|
||||
|
||||
gometalinter \
|
||||
--skip=examples \
|
||||
--tests \
|
||||
--vendor \
|
||||
--disable=aligncheck \
|
||||
--disable=gotype \
|
||||
--disable=goconst \
|
||||
--disable=gocyclo \
|
||||
--deadline=300s \
|
||||
./...
|
||||
# ./bin/golangci-lint \
|
||||
# --tests \
|
||||
# --vendor \
|
||||
# --disable=aligncheck \
|
||||
# --disable=gotype \
|
||||
# --disable=goconst \
|
||||
# --disable=gocyclo \
|
||||
# --deadline=300s \
|
||||
# ./...
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
set -e
|
||||
|
||||
go test -coverprofile=coverage.out
|
||||
go test -coverprofile=coverage.out ./...
|
||||
go tool cover -html=coverage.out -o cover/coverage.html
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
go get -u github.com/alecthomas/gometalinter
|
||||
go get -u golang.org/x/tools/cmd/goimports
|
||||
go get -u github.com/mitchellh/gox
|
||||
go get -u github.com/kardianos/govendor
|
||||
go get -u github.com/aktau/github-release
|
||||
|
||||
# install all the linters
|
||||
gometalinter --install --update
|
||||
set -e
|
||||
wget -O - -q https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.21.0
|
||||
go get golang.org/x/tools/cmd/goimports
|
||||
2
scripts/doctools.sh
Normal file → Executable file
2
scripts/doctools.sh
Normal file → Executable file
@@ -1,4 +1,4 @@
|
||||
#!/bin.bash
|
||||
#!/bin/bash
|
||||
|
||||
brew install mkdocs libyaml
|
||||
pip3 install markdown-include
|
||||
|
||||
@@ -10,11 +10,13 @@ REPO="yq"
|
||||
release() {
|
||||
github-release release \
|
||||
--user "$OWNER" \
|
||||
--draft \
|
||||
--repo "$REPO" \
|
||||
--tag "$CURRENT"
|
||||
}
|
||||
|
||||
upload() {
|
||||
mkdir -p ./build-done
|
||||
while IFS= read -r -d $'\0'; do
|
||||
file=$REPLY
|
||||
BINARY=$(basename "${file}")
|
||||
@@ -26,6 +28,7 @@ upload() {
|
||||
--tag "$CURRENT" \
|
||||
--name "${BINARY}" \
|
||||
--file "$file"
|
||||
mv "$file" "./build-done/${BINARY}"
|
||||
done < <(find ./build -mindepth 1 -maxdepth 1 -print0)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
go test -v $(go list ./... | grep -v -E 'vendor|examples')
|
||||
go test -v $(go list ./... | grep -v -E 'examples')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: yq
|
||||
version: 2.2.0
|
||||
version: '2.4.1'
|
||||
summary: A lightweight and portable command-line YAML processor
|
||||
description: |
|
||||
The aim of the project is to be the jq or sed of yaml files.
|
||||
@@ -19,4 +19,4 @@ parts:
|
||||
go-importpath: github.com/mikefarah/yq
|
||||
after: [go]
|
||||
go:
|
||||
source-tag: go1.9.4
|
||||
source-tag: go1.11
|
||||
|
||||
6
test/fixture/keyonly.yaml
Normal file
6
test/fixture/keyonly.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
a:
|
||||
b:
|
||||
c: 1
|
||||
d:
|
||||
e: 2
|
||||
f:
|
||||
@@ -1,4 +1,4 @@
|
||||
package main
|
||||
package test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
yaml "gopkg.in/mikefarah/yaml.v2"
|
||||
"gopkg.in/spf13/cobra.v0"
|
||||
yaml "github.com/mikefarah/yaml/v2"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type resulter struct {
|
||||
@@ -19,7 +19,7 @@ type resulter struct {
|
||||
Command *cobra.Command
|
||||
}
|
||||
|
||||
func runCmd(c *cobra.Command, input string) resulter {
|
||||
func RunCmd(c *cobra.Command, input string) resulter {
|
||||
buf := new(bytes.Buffer)
|
||||
c.SetOutput(buf)
|
||||
c.SetArgs(strings.Split(input, " "))
|
||||
@@ -30,7 +30,7 @@ func runCmd(c *cobra.Command, input string) resulter {
|
||||
return resulter{err, output, c}
|
||||
}
|
||||
|
||||
func parseData(rawData string) yaml.MapSlice {
|
||||
func ParseData(rawData string) yaml.MapSlice {
|
||||
var parsedData yaml.MapSlice
|
||||
err := yaml.Unmarshal([]byte(rawData), &parsedData)
|
||||
if err != nil {
|
||||
@@ -40,21 +40,21 @@ func parseData(rawData string) yaml.MapSlice {
|
||||
return parsedData
|
||||
}
|
||||
|
||||
func assertResult(t *testing.T, expectedValue interface{}, actualValue interface{}) {
|
||||
func AssertResult(t *testing.T, expectedValue interface{}, actualValue interface{}) {
|
||||
t.Helper()
|
||||
if expectedValue != actualValue {
|
||||
t.Error("Expected <", expectedValue, "> but got <", actualValue, ">", fmt.Sprintf("%T", actualValue))
|
||||
}
|
||||
}
|
||||
|
||||
func assertResultComplex(t *testing.T, expectedValue interface{}, actualValue interface{}) {
|
||||
func AssertResultComplex(t *testing.T, expectedValue interface{}, actualValue interface{}) {
|
||||
t.Helper()
|
||||
if !reflect.DeepEqual(expectedValue, actualValue) {
|
||||
t.Error("Expected <", expectedValue, "> but got <", actualValue, ">", fmt.Sprintf("%T", actualValue))
|
||||
}
|
||||
}
|
||||
|
||||
func assertResultWithContext(t *testing.T, expectedValue interface{}, actualValue interface{}, context interface{}) {
|
||||
func AssertResultWithContext(t *testing.T, expectedValue interface{}, actualValue interface{}, context interface{}) {
|
||||
t.Helper()
|
||||
if expectedValue != actualValue {
|
||||
t.Error(context)
|
||||
@@ -62,7 +62,7 @@ func assertResultWithContext(t *testing.T, expectedValue interface{}, actualValu
|
||||
}
|
||||
}
|
||||
|
||||
func writeTempYamlFile(content string) string {
|
||||
func WriteTempYamlFile(content string) string {
|
||||
tmpfile, _ := ioutil.TempFile("", "testyaml")
|
||||
defer func() {
|
||||
_ = tmpfile.Close()
|
||||
@@ -72,11 +72,11 @@ func writeTempYamlFile(content string) string {
|
||||
return tmpfile.Name()
|
||||
}
|
||||
|
||||
func readTempYamlFile(name string) string {
|
||||
func ReadTempYamlFile(name string) string {
|
||||
content, _ := ioutil.ReadFile(name)
|
||||
return string(content)
|
||||
}
|
||||
|
||||
func removeTempYamlFile(name string) {
|
||||
func RemoveTempYamlFile(name string) {
|
||||
_ = os.Remove(name)
|
||||
}
|
||||
49
vendor/vendor.json
vendored
49
vendor/vendor.json
vendored
@@ -1,49 +0,0 @@
|
||||
{
|
||||
"comment": "",
|
||||
"ignore": "test",
|
||||
"package": [
|
||||
{
|
||||
"checksumSHA1": "40vJyUB4ezQSn/NSadsKEOrudMc=",
|
||||
"path": "github.com/inconshreveable/mousetrap",
|
||||
"revision": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75",
|
||||
"revisionTime": "2014-10-17T20:07:13Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "ljd3FhYRJ91cLZz3wsH9BQQ2JbA=",
|
||||
"path": "github.com/pkg/errors",
|
||||
"revision": "816c9085562cd7ee03e7f8188a1cfd942858cded",
|
||||
"revisionTime": "2018-03-11T21:45:15Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "OJI0OgC5V8gZtfS1e0CDYMhkDNc=",
|
||||
"path": "github.com/spf13/pflag",
|
||||
"revision": "3ebe029320b2676d667ae88da602a5f854788a8a",
|
||||
"revisionTime": "2018-06-01T13:25:42Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "RwlkCZz8VFXAE4aHQQOSC0hLu5k=",
|
||||
"path": "gopkg.in/imdario/mergo.v0",
|
||||
"revision": "9316a62528ac99aaecb4e47eadd6dc8aa6533d58",
|
||||
"revisionTime": "2018-06-08T14:01:56Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "7wtGubs4v7+RZovtlmyT9KwA/gE=",
|
||||
"path": "gopkg.in/mikefarah/yaml.v2",
|
||||
"revision": "e175af14aaa1d0eff2ee04b691e4a4827a111416",
|
||||
"revisionTime": "2018-06-13T04:05:11Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "rL5r44ASTGubGW88gqQwlvVQshw=",
|
||||
"path": "gopkg.in/op/go-logging.v1",
|
||||
"revision": "b2cb9fa56473e98db8caba80237377e83fe44db5",
|
||||
"revisionTime": "2016-02-11T21:21:56Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "xsZjAbfLrXcMtY6fyQ8QC6EvJD0=",
|
||||
"path": "gopkg.in/spf13/cobra.v0",
|
||||
"revision": "ef82de70bb3f60c65fb8eebacbb2d122ef517385",
|
||||
"revisionTime": "2018-04-27T13:45:50Z"
|
||||
}
|
||||
],
|
||||
"rootPath": "github.com/mikefarah/yq"
|
||||
}
|
||||
@@ -11,7 +11,7 @@ var (
|
||||
GitDescribe string
|
||||
|
||||
// Version is main version number that is being run at the moment.
|
||||
Version = "2.2.0"
|
||||
Version = "2.4.1"
|
||||
|
||||
// VersionPrerelease is a pre-release marker for the version. If this is "" (empty string)
|
||||
// then it means that it is a final release. Otherwise, this is a pre-release
|
||||
|
||||
162
yq.go
162
yq.go
@@ -10,11 +10,14 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/mikefarah/yq/v2/pkg/marshal"
|
||||
"github.com/mikefarah/yq/v2/pkg/yqlib"
|
||||
|
||||
errors "github.com/pkg/errors"
|
||||
|
||||
yaml "gopkg.in/mikefarah/yaml.v2"
|
||||
yaml "github.com/mikefarah/yaml/v2"
|
||||
"github.com/spf13/cobra"
|
||||
logging "gopkg.in/op/go-logging.v1"
|
||||
cobra "gopkg.in/spf13/cobra.v0"
|
||||
)
|
||||
|
||||
var trimOutput = true
|
||||
@@ -22,11 +25,17 @@ var writeInplace = false
|
||||
var writeScript = ""
|
||||
var outputToJSON = false
|
||||
var overwriteFlag = false
|
||||
var keyOnlyFlag = false
|
||||
var allowEmptyFlag = false
|
||||
var appendFlag = false
|
||||
var verbose = false
|
||||
var version = false
|
||||
var docIndex = "0"
|
||||
var log = logging.MustGetLogger("yq")
|
||||
var lib = yqlib.NewYqLib(log)
|
||||
var jsonConverter = marshal.NewJsonConverter()
|
||||
var yamlConverter = marshal.NewYamlConverter()
|
||||
var valueParser = yqlib.NewValueParser()
|
||||
|
||||
func main() {
|
||||
cmd := newCommandCLI()
|
||||
@@ -39,7 +48,9 @@ func main() {
|
||||
func newCommandCLI() *cobra.Command {
|
||||
yaml.DefaultMapType = reflect.TypeOf(yaml.MapSlice{})
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "yq",
|
||||
Use: "yq",
|
||||
Short: "yq is a lightweight and portable command-line YAML processor.",
|
||||
Long: `yq is a lightweight and portable command-line YAML processor. It aims to be the jq or sed of yaml files.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if version {
|
||||
cmd.Print(GetVersionDisplay())
|
||||
@@ -94,12 +105,14 @@ yq r - a.b.c (reads from stdin)
|
||||
yq r things.yaml a.*.c
|
||||
yq r -d1 things.yaml a.array[0].blah
|
||||
yq r things.yaml a.array[*].blah
|
||||
yq r -- things.yaml --key-starting-with-dashes
|
||||
`,
|
||||
Long: "Outputs the value of the given path in the yaml file to STDOUT",
|
||||
RunE: readProperty,
|
||||
}
|
||||
cmdRead.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||
cmdRead.PersistentFlags().BoolVarP(&outputToJSON, "tojson", "j", false, "output as json")
|
||||
cmdRead.PersistentFlags().BoolVarP(&keyOnlyFlag, "keyonly", "k", false, "output with top level keys only")
|
||||
return cmdRead
|
||||
}
|
||||
|
||||
@@ -110,7 +123,7 @@ func createWriteCmd() *cobra.Command {
|
||||
Short: "yq w [--inplace/-i] [--script/-s script_file] [--doc/-d index] sample.yaml a.b.c newValue",
|
||||
Example: `
|
||||
yq write things.yaml a.b.c cat
|
||||
yq write --inplace things.yaml a.b.c cat
|
||||
yq write --inplace -- things.yaml a.b.c --cat
|
||||
yq w -i things.yaml a.b.c cat
|
||||
yq w --script update_script.yaml things.yaml
|
||||
yq w -i -s update_script.yaml things.yaml
|
||||
@@ -146,6 +159,7 @@ func createPrefixCmd() *cobra.Command {
|
||||
Example: `
|
||||
yq prefix things.yaml a.b.c
|
||||
yq prefix --inplace things.yaml a.b.c
|
||||
yq prefix --inplace -- things.yaml --key-starting-with-dash
|
||||
yq p -i things.yaml a.b.c
|
||||
yq p --doc 2 things.yaml a.b.d
|
||||
yq p -d2 things.yaml a.b.d
|
||||
@@ -168,6 +182,7 @@ func createDeleteCmd() *cobra.Command {
|
||||
Example: `
|
||||
yq delete things.yaml a.b.c
|
||||
yq delete --inplace things.yaml a.b.c
|
||||
yq delete --inplace -- things.yaml --key-starting-with-dash
|
||||
yq d -i things.yaml a.b.c
|
||||
yq d things.yaml a.b.c
|
||||
`,
|
||||
@@ -189,6 +204,7 @@ func createNewCmd() *cobra.Command {
|
||||
Example: `
|
||||
yq new a.b.c cat
|
||||
yq n a.b.c cat
|
||||
yq n -- --key-starting-with-dash cat
|
||||
yq n --script create_script.yaml
|
||||
`,
|
||||
Long: `Creates a new yaml w.r.t the given path and value.
|
||||
@@ -229,6 +245,7 @@ Note that if you set both flags only overwrite will take effect.
|
||||
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(&appendFlag, "append", "a", false, "update the yaml file by appending array values")
|
||||
cmdMerge.PersistentFlags().BoolVarP(&allowEmptyFlag, "allow-empty", "e", false, "allow empty yaml files")
|
||||
cmdMerge.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||
return cmdMerge
|
||||
}
|
||||
@@ -255,19 +272,25 @@ func readProperty(cmd *cobra.Command, args []string) error {
|
||||
if errorReading == io.EOF {
|
||||
log.Debugf("done %v / %v", currentIndex, docIndexInt)
|
||||
if !updateAll && currentIndex <= docIndexInt {
|
||||
return fmt.Errorf("Asked to process document index %v but there are only %v document(s)", docIndex, currentIndex)
|
||||
return fmt.Errorf("asked to process document index %v but there are only %v document(s)", docIndex, currentIndex)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
log.Debugf("processing %v - requested index %v", currentIndex, docIndexInt)
|
||||
if updateAll || currentIndex == docIndexInt {
|
||||
log.Debugf("reading %v in index %v", path, currentIndex)
|
||||
mappedDoc, errorParsing := readPath(dataBucket, path)
|
||||
log.Debugf("%v", mappedDoc)
|
||||
if errorParsing != nil {
|
||||
return errors.Wrapf(errorParsing, "Error reading path in document index %v", currentIndex)
|
||||
if path == "" {
|
||||
log.Debug("no path")
|
||||
log.Debugf("%v", dataBucket)
|
||||
mappedDocs = append(mappedDocs, dataBucket)
|
||||
} else {
|
||||
mappedDoc, errorParsing := lib.ReadPath(dataBucket, path)
|
||||
log.Debugf("%v", mappedDoc)
|
||||
if errorParsing != nil {
|
||||
return errors.Wrapf(errorParsing, "Error reading path in document index %v", currentIndex)
|
||||
}
|
||||
mappedDocs = append(mappedDocs, mappedDoc)
|
||||
}
|
||||
mappedDocs = append(mappedDocs, mappedDoc)
|
||||
}
|
||||
currentIndex = currentIndex + 1
|
||||
}
|
||||
@@ -283,6 +306,13 @@ func readProperty(cmd *cobra.Command, args []string) error {
|
||||
dataBucket = mappedDocs
|
||||
}
|
||||
|
||||
if keyOnlyFlag {
|
||||
for _, value := range dataBucket.(yaml.MapSlice) {
|
||||
cmd.Println(value.Key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
dataStr, err := toString(dataBucket)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -291,15 +321,6 @@ func readProperty(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func readPath(dataBucket interface{}, path string) (interface{}, error) {
|
||||
if path == "" {
|
||||
log.Debug("no path")
|
||||
return dataBucket, nil
|
||||
}
|
||||
var paths = parsePath(path)
|
||||
return recurse(dataBucket, paths[0], paths[1:])
|
||||
}
|
||||
|
||||
func newProperty(cmd *cobra.Command, args []string) error {
|
||||
updatedData, err := newYaml(args)
|
||||
if err != nil {
|
||||
@@ -331,8 +352,7 @@ func newYaml(args []string) (interface{}, error) {
|
||||
path := entry.Key.(string)
|
||||
value := entry.Value
|
||||
log.Debugf("setting %v to %v", path, value)
|
||||
var paths = parsePath(path)
|
||||
dataBucket = updatedChildValue(dataBucket, paths, value)
|
||||
dataBucket = lib.WritePath(dataBucket, path, value)
|
||||
}
|
||||
|
||||
return dataBucket, nil
|
||||
@@ -370,7 +390,7 @@ func mapYamlDecoder(updateData updateDataFn, encoder *yaml.Encoder) yamlDecoderF
|
||||
|
||||
if errorReading == io.EOF {
|
||||
if !updateAll && currentIndex <= docIndexInt {
|
||||
return fmt.Errorf("Asked to process document index %v but there are only %v document(s)", docIndex, currentIndex)
|
||||
return fmt.Errorf("asked to process document index %v but there are only %v document(s)", docIndex, currentIndex)
|
||||
}
|
||||
return nil
|
||||
} else if errorReading != nil {
|
||||
@@ -408,8 +428,7 @@ func writeProperty(cmd *cobra.Command, args []string) error {
|
||||
path := entry.Key.(string)
|
||||
value := entry.Value
|
||||
log.Debugf("setting %v to %v", path, value)
|
||||
var paths = parsePath(path)
|
||||
dataBucket = updatedChildValue(dataBucket, paths, value)
|
||||
dataBucket = lib.WritePath(dataBucket, path, value)
|
||||
}
|
||||
}
|
||||
return dataBucket, nil
|
||||
@@ -421,28 +440,18 @@ func prefixProperty(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 2 {
|
||||
return errors.New("Must provide <filename> <prefixed_path>")
|
||||
}
|
||||
prefixPath := args[1]
|
||||
|
||||
var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex()
|
||||
if errorParsingDocIndex != nil {
|
||||
return errorParsingDocIndex
|
||||
}
|
||||
|
||||
var paths = parsePath(args[1])
|
||||
|
||||
// Inverse order
|
||||
for i := len(paths)/2 - 1; i >= 0; i-- {
|
||||
opp := len(paths) - 1 - i
|
||||
paths[i], paths[opp] = paths[opp], paths[i]
|
||||
}
|
||||
|
||||
var updateData = func(dataBucket interface{}, currentIndex int) (interface{}, error) {
|
||||
|
||||
if updateAll || currentIndex == docIndexInt {
|
||||
log.Debugf("Prefixing %v to doc %v", paths, currentIndex)
|
||||
var mapDataBucket = dataBucket
|
||||
for _, key := range paths {
|
||||
singlePath := []string{key}
|
||||
mapDataBucket = updatedChildValue(nil, singlePath, mapDataBucket)
|
||||
}
|
||||
log.Debugf("Prefixing %v to doc %v", prefixPath, currentIndex)
|
||||
var mapDataBucket = lib.PrefixPath(dataBucket, prefixPath)
|
||||
return mapDataBucket, nil
|
||||
}
|
||||
return dataBucket, nil
|
||||
@@ -462,11 +471,11 @@ func readAndUpdate(stdOut io.Writer, inputFile string, updateData updateDataFn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = tempFile.Chmod(info.Mode())
|
||||
destinationName = tempFile.Name()
|
||||
err = os.Chmod(destinationName, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
destinationName = tempFile.Name()
|
||||
destination = tempFile
|
||||
defer func() {
|
||||
safelyCloseFile(tempFile)
|
||||
@@ -488,7 +497,6 @@ func deleteProperty(cmd *cobra.Command, args []string) error {
|
||||
return errors.New("Must provide <filename> <path_to_delete>")
|
||||
}
|
||||
var deletePath = args[1]
|
||||
var paths = parsePath(deletePath)
|
||||
var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex()
|
||||
if errorParsingDocIndex != nil {
|
||||
return errorParsingDocIndex
|
||||
@@ -497,7 +505,7 @@ func deleteProperty(cmd *cobra.Command, args []string) error {
|
||||
var updateData = func(dataBucket interface{}, currentIndex int) (interface{}, error) {
|
||||
if updateAll || currentIndex == docIndexInt {
|
||||
log.Debugf("Deleting path in doc %v", currentIndex)
|
||||
return deleteChildValue(dataBucket, paths), nil
|
||||
return lib.DeletePath(dataBucket, deletePath)
|
||||
}
|
||||
return dataBucket, nil
|
||||
}
|
||||
@@ -524,16 +532,19 @@ func mergeProperties(cmd *cobra.Command, args []string) error {
|
||||
// map
|
||||
var mapDataBucket = make(map[interface{}]interface{})
|
||||
mapDataBucket["root"] = dataBucket
|
||||
if err := merge(&mergedData, mapDataBucket, overwriteFlag, appendFlag); err != nil {
|
||||
if err := lib.Merge(&mergedData, mapDataBucket, overwriteFlag, appendFlag); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, f := range filesToMerge {
|
||||
var fileToMerge interface{}
|
||||
if err := readData(f, 0, &fileToMerge); err != nil {
|
||||
if allowEmptyFlag && err == io.EOF {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
mapDataBucket["root"] = fileToMerge
|
||||
if err := merge(&mergedData, mapDataBucket, overwriteFlag, appendFlag); err != nil {
|
||||
if err := lib.Merge(&mergedData, mapDataBucket, overwriteFlag, appendFlag); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -556,72 +567,33 @@ func readWriteCommands(args []string, expectedArgs int, badArgsMessage string) (
|
||||
return nil, errors.New(badArgsMessage)
|
||||
} else {
|
||||
writeCommands = make(yaml.MapSlice, 1)
|
||||
writeCommands[0] = yaml.MapItem{Key: args[expectedArgs-2], Value: parseValue(args[expectedArgs-1])}
|
||||
writeCommands[0] = yaml.MapItem{Key: args[expectedArgs-2], Value: valueParser.ParseValue(args[expectedArgs-1])}
|
||||
}
|
||||
return writeCommands, nil
|
||||
}
|
||||
|
||||
func parseValue(argument string) interface{} {
|
||||
var value, err interface{}
|
||||
var inQuotes = len(argument) > 0 && argument[0] == '"'
|
||||
if !inQuotes {
|
||||
value, err = strconv.ParseFloat(argument, 64)
|
||||
if err == nil {
|
||||
return value
|
||||
}
|
||||
value, err = strconv.ParseBool(argument)
|
||||
if err == nil {
|
||||
return value
|
||||
}
|
||||
if argument == "[]" {
|
||||
return make([]interface{}, 0)
|
||||
}
|
||||
return argument
|
||||
}
|
||||
return argument[1 : len(argument)-1]
|
||||
}
|
||||
|
||||
func toString(context interface{}) (string, error) {
|
||||
if outputToJSON {
|
||||
return jsonToString(context)
|
||||
return jsonConverter.JsonToString(context)
|
||||
}
|
||||
return yamlToString(context)
|
||||
}
|
||||
|
||||
func yamlToString(context interface{}) (string, error) {
|
||||
switch context.(type) {
|
||||
case string:
|
||||
return context.(string), nil
|
||||
default:
|
||||
return marshalContext(context)
|
||||
}
|
||||
}
|
||||
|
||||
func marshalContext(context interface{}) (string, error) {
|
||||
out, err := yaml.Marshal(context)
|
||||
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error printing yaml")
|
||||
}
|
||||
|
||||
outStr := string(out)
|
||||
// trim the trailing new line as it's easier for a script to add
|
||||
// it in if required than to remove it
|
||||
if trimOutput {
|
||||
return strings.Trim(outStr, "\n "), nil
|
||||
}
|
||||
return outStr, nil
|
||||
return yamlConverter.YamlToString(context, trimOutput)
|
||||
}
|
||||
|
||||
func safelyRenameFile(from string, to string) {
|
||||
if renameError := os.Rename(from, to); renameError != nil {
|
||||
log.Warningf("Error renaming from %v to %v, attemting to copy contents", from, to)
|
||||
log.Warning(renameError.Error())
|
||||
log.Debugf("Error renaming from %v to %v, attemting to copy contents", from, to)
|
||||
log.Debug(renameError.Error())
|
||||
// can't do this rename when running in docker to a file targeted in a mounted volume,
|
||||
// so gracefully degrade to copying the entire contents.
|
||||
if copyError := copyFileContents(from, to); copyError != nil {
|
||||
log.Errorf("Failed copying from %v to %v", from, to)
|
||||
log.Errorf(copyError.Error())
|
||||
log.Error(copyError.Error())
|
||||
} else {
|
||||
removeErr := os.Remove(from)
|
||||
if removeErr != nil {
|
||||
log.Errorf("failed removing original file: %s", from)
|
||||
log.Error(removeErr.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
77
yq_test.go
77
yq_test.go
@@ -1,40 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/mikefarah/yq/v2/pkg/marshal"
|
||||
"github.com/mikefarah/yq/v2/test"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var parseValueTests = []struct {
|
||||
argument string
|
||||
expectedResult interface{}
|
||||
testDescription string
|
||||
}{
|
||||
{"true", true, "boolean"},
|
||||
{"\"true\"", "true", "boolean as string"},
|
||||
{"3.4", 3.4, "number"},
|
||||
{"\"3.4\"", "3.4", "number as string"},
|
||||
{"", "", "empty string"},
|
||||
}
|
||||
|
||||
func TestParseValue(t *testing.T) {
|
||||
for _, tt := range parseValueTests {
|
||||
assertResultWithContext(t, tt.expectedResult, parseValue(tt.argument), tt.testDescription)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultilineString(t *testing.T) {
|
||||
testString := `
|
||||
abcd
|
||||
efg`
|
||||
formattedResult, _ := yamlToString(testString)
|
||||
assertResult(t, testString, formattedResult)
|
||||
formattedResult, _ := marshal.NewYamlConverter().YamlToString(testString, false)
|
||||
test.AssertResult(t, testString, formattedResult)
|
||||
}
|
||||
|
||||
func TestNewYaml(t *testing.T) {
|
||||
result, _ := newYaml([]string{"b.c", "3"})
|
||||
formattedResult := fmt.Sprintf("%v", result)
|
||||
assertResult(t,
|
||||
test.AssertResult(t,
|
||||
"[{b [{c 3}]}]",
|
||||
formattedResult)
|
||||
}
|
||||
@@ -42,11 +30,19 @@ func TestNewYaml(t *testing.T) {
|
||||
func TestNewYamlArray(t *testing.T) {
|
||||
result, _ := newYaml([]string{"[0].cat", "meow"})
|
||||
formattedResult := fmt.Sprintf("%v", result)
|
||||
assertResult(t,
|
||||
test.AssertResult(t,
|
||||
"[[{cat meow}]]",
|
||||
formattedResult)
|
||||
}
|
||||
|
||||
func TestNewYamlBigInt(t *testing.T) {
|
||||
result, _ := newYaml([]string{"b", "1212121"})
|
||||
formattedResult := fmt.Sprintf("%v", result)
|
||||
test.AssertResult(t,
|
||||
"[{b 1212121}]",
|
||||
formattedResult)
|
||||
}
|
||||
|
||||
func TestNewYaml_WithScript(t *testing.T) {
|
||||
writeScript = "examples/instruction_sample.yaml"
|
||||
expectedResult := `b:
|
||||
@@ -54,8 +50,8 @@ func TestNewYaml_WithScript(t *testing.T) {
|
||||
e:
|
||||
- name: Mike Farah`
|
||||
result, _ := newYaml([]string{""})
|
||||
actualResult, _ := yamlToString(result)
|
||||
assertResult(t, expectedResult, actualResult)
|
||||
actualResult, _ := marshal.NewYamlConverter().YamlToString(result, true)
|
||||
test.AssertResult(t, expectedResult, actualResult)
|
||||
}
|
||||
|
||||
func TestNewYaml_WithUnknownScript(t *testing.T) {
|
||||
@@ -64,6 +60,35 @@ func TestNewYaml_WithUnknownScript(t *testing.T) {
|
||||
if err == nil {
|
||||
t.Error("Expected error due to unknown file")
|
||||
}
|
||||
expectedOutput := `open fake-unknown: no such file or directory`
|
||||
assertResult(t, expectedOutput, err.Error())
|
||||
var expectedOutput string
|
||||
if runtime.GOOS == "windows" {
|
||||
expectedOutput = `open fake-unknown: The system cannot find the file specified.`
|
||||
} else {
|
||||
expectedOutput = `open fake-unknown: no such file or directory`
|
||||
}
|
||||
test.AssertResult(t, expectedOutput, err.Error())
|
||||
}
|
||||
|
||||
func TestReadWithKeyOnly(t *testing.T) {
|
||||
readCmd := createReadCmd()
|
||||
expectedResult := `b
|
||||
d
|
||||
f
|
||||
`
|
||||
actualResult, err := executeTestCommand(readCmd, "test/fixture/keyonly.yaml", "a", "-k")
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
test.AssertResult(t, expectedResult, actualResult)
|
||||
}
|
||||
|
||||
func executeTestCommand(command *cobra.Command, args ...string) (output string, err error) {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
command.SetOutput(buf)
|
||||
command.SetArgs(args)
|
||||
|
||||
_, err = command.ExecuteC()
|
||||
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user