From c5f80a105d154ec4004988d4e2a1ced22e265fb4 Mon Sep 17 00:00:00 2001 From: kenjones Date: Sat, 23 Sep 2017 20:21:16 -0400 Subject: [PATCH] Feature: Add append to array Adds the ability to append a value to an array instead of having to know the index of the values within the array. Resolves: #17 --- commands_test.go | 19 ++++++++++++++++++ data_navigator.go | 10 ++++++++-- docs/mkdocs/search_index.json | 7 ++++++- docs/sitemap.xml | 12 ++++++------ docs/write/index.html | 36 +++++++++++++++++++++++++++++++++++ mkdocs/write.md | 23 ++++++++++++++++++++++ path_parser_test.go | 1 + yaml.go | 4 ++++ 8 files changed, 103 insertions(+), 9 deletions(-) diff --git a/commands_test.go b/commands_test.go index 420064b6e67..fb80813d112 100644 --- a/commands_test.go +++ b/commands_test.go @@ -435,6 +435,25 @@ func TestWriteCmd_Inplace(t *testing.T) { assertResult(t, expectedOutput, gotOutput) } +func TestWriteCmd_Append(t *testing.T) { + content := `b: + - foo +` + filename := writeTempYamlFile(content) + defer removeTempYamlFile(filename) + + cmd := getRootCommand() + result := runCmd(cmd, fmt.Sprintf("write %s b[+] 7", filename)) + if result.Error != nil { + t.Error(result.Error) + } + expectedOutput := `b: +- foo +- 7 +` + assertResult(t, expectedOutput, result.Output) +} + func TestMergeCmd(t *testing.T) { cmd := getRootCommand() result := runCmd(cmd, "merge examples/data1.yaml examples/data2.yaml") diff --git a/data_navigator.go b/data_navigator.go index 274071fc1dc..5f9469949ab 100644 --- a/data_navigator.go +++ b/data_navigator.go @@ -55,7 +55,7 @@ func updatedChildValue(child interface{}, remainingPaths []string, value interfa } _, nextIndexErr := strconv.ParseInt(remainingPaths[0], 10, 64) - if nextIndexErr != nil { + if nextIndexErr != nil && remainingPaths[0] != "+" { // must be a map return writeMap(child, remainingPaths, value) } @@ -81,7 +81,13 @@ func writeArray(context interface{}, paths []string, value interface{}) []interf log.Debugf("\tarray %v\n", array) rawIndex := paths[0] - index, _ := strconv.ParseInt(rawIndex, 10, 64) + var index int64 + // the append array indicator + if rawIndex == "+" { + index = int64(len(array)) + } else { + index, _ = strconv.ParseInt(rawIndex, 10, 64) + } // writeArray is only called by updatedChildValue which handles parsing the // index, as such this renders this dead code. // if err != nil { diff --git a/docs/mkdocs/search_index.json b/docs/mkdocs/search_index.json index c7d3989f9fe..533d377396a 100644 --- a/docs/mkdocs/search_index.json +++ b/docs/mkdocs/search_index.json @@ -57,7 +57,7 @@ }, { "location": "/write/", - "text": "yaml w \nyaml_file|json_file\n \npath\n \nnew value\n\n\n\n\n\nThis command can take a json file as input too, and will output yaml unless specified to export as json (-j)\n\n\nTo Stdout\n\n\nGiven a sample.yaml file of:\n\n\nb:\n c: 2\n\n\n\n\nthen\n\n\nyaml w sample.yaml b.c cat\n\n\n\n\nwill output:\n\n\nb:\n c: cat\n\n\n\n\nFrom STDIN\n\n\ncat sample.yaml | yaml w - b.c blah\n\n\n\n\nAdding new fields\n\n\nAny missing fields in the path will be created on the fly.\n\n\nGiven a sample.yaml file of:\n\n\nb:\n c: 2\n\n\n\n\nthen\n\n\nyaml w sample.yaml b.d[0] \nnew thing\n\n\n\n\n\nwill output:\n\n\nb:\n c: cat\n d:\n - new thing\n\n\n\n\nUpdating files in-place\n\n\nGiven a sample.yaml file of:\n\n\nb:\n c: 2\n\n\n\n\nthen\n\n\nyaml w -i sample.yaml b.c cat\n\n\n\n\nwill update the sample.yaml file so that the value of 'c' is cat.\n\n\nUpdating multiple values with a script\n\n\nGiven a sample.yaml file of:\n\n\nb:\n c: 2\n e:\n - name: Billy Bob\n\n\n\n\nand a script update_instructions.yaml of:\n\n\nb.c: 3\nb.e[0].name: Howdy Partner\n\n\n\n\nthen\n\n\nyaml w -s update_instructions.yaml sample.yaml\n\n\n\n\nwill output:\n\n\nb:\n c: 3\n e:\n - name: Howdy Partner\n\n\n\n\nAnd, of course, you can pipe the instructions in using '-':\n\n\ncat update_instructions.yaml | yaml w -s - sample.yaml\n\n\n\n\nValues starting with a hyphen (or dash)\n\n\nThe flag terminator needs to be used to stop the app from attempting to parse the subsequent arguments as flags:\n\n\nyaml w -- my.path -3\n\n\n\n\nwill output\n\n\nmy:\n path: -3", + "text": "yaml w \nyaml_file|json_file\n \npath\n \nnew value\n\n\n\n\n\nThis command can take a json file as input too, and will output yaml unless specified to export as json (-j)\n\n\nTo Stdout\n\n\nGiven a sample.yaml file of:\n\n\nb:\n c: 2\n\n\n\n\nthen\n\n\nyaml w sample.yaml b.c cat\n\n\n\n\nwill output:\n\n\nb:\n c: cat\n\n\n\n\nFrom STDIN\n\n\ncat sample.yaml | yaml w - b.c blah\n\n\n\n\nAdding new fields\n\n\nAny missing fields in the path will be created on the fly.\n\n\nGiven a sample.yaml file of:\n\n\nb:\n c: 2\n\n\n\n\nthen\n\n\nyaml w sample.yaml b.d[0] \nnew thing\n\n\n\n\n\nwill output:\n\n\nb:\n c: cat\n d:\n - new thing\n\n\n\n\nAppending value to an array field\n\n\nGiven a sample.yaml file of:\n\n\nb:\n c: 2\n d:\n - new thing\n - foo thing\n\n\n\n\nthen\n\n\nyaml w sample.yaml b.d[+] \nbar thing\n\n\n\n\n\nwill output:\n\n\nb:\n c: cat\n d:\n - new thing\n - foo thing\n - bar thing\n\n\n\n\nUpdating files in-place\n\n\nGiven a sample.yaml file of:\n\n\nb:\n c: 2\n\n\n\n\nthen\n\n\nyaml w -i sample.yaml b.c cat\n\n\n\n\nwill update the sample.yaml file so that the value of 'c' is cat.\n\n\nUpdating multiple values with a script\n\n\nGiven a sample.yaml file of:\n\n\nb:\n c: 2\n e:\n - name: Billy Bob\n\n\n\n\nand a script update_instructions.yaml of:\n\n\nb.c: 3\nb.e[0].name: Howdy Partner\n\n\n\n\nthen\n\n\nyaml w -s update_instructions.yaml sample.yaml\n\n\n\n\nwill output:\n\n\nb:\n c: 3\n e:\n - name: Howdy Partner\n\n\n\n\nAnd, of course, you can pipe the instructions in using '-':\n\n\ncat update_instructions.yaml | yaml w -s - sample.yaml\n\n\n\n\nValues starting with a hyphen (or dash)\n\n\nThe flag terminator needs to be used to stop the app from attempting to parse the subsequent arguments as flags:\n\n\nyaml w -- my.path -3\n\n\n\n\nwill output\n\n\nmy:\n path: -3", "title": "Write/Update" }, { @@ -75,6 +75,11 @@ "text": "Any missing fields in the path will be created on the fly. Given a sample.yaml file of: b:\n c: 2 then yaml w sample.yaml b.d[0] new thing will output: b:\n c: cat\n d:\n - new thing", "title": "Adding new fields" }, + { + "location": "/write/#appending-value-to-an-array-field", + "text": "Given a sample.yaml file of: b:\n c: 2\n d:\n - new thing\n - foo thing then yaml w sample.yaml b.d[+] bar thing will output: b:\n c: cat\n d:\n - new thing\n - foo thing\n - bar thing", + "title": "Appending value to an array field" + }, { "location": "/write/#updating-files-in-place", "text": "Given a sample.yaml file of: b:\n c: 2 then yaml w -i sample.yaml b.c cat will update the sample.yaml file so that the value of 'c' is cat.", diff --git a/docs/sitemap.xml b/docs/sitemap.xml index 21e7ee5e3ab..222fdf84e15 100644 --- a/docs/sitemap.xml +++ b/docs/sitemap.xml @@ -4,7 +4,7 @@ / - 2017-09-23 + 2017-09-24 daily @@ -12,7 +12,7 @@ /read/ - 2017-09-23 + 2017-09-24 daily @@ -20,7 +20,7 @@ /write/ - 2017-09-23 + 2017-09-24 daily @@ -28,7 +28,7 @@ /create/ - 2017-09-23 + 2017-09-24 daily @@ -36,7 +36,7 @@ /convert/ - 2017-09-23 + 2017-09-24 daily @@ -44,7 +44,7 @@ /merge/ - 2017-09-23 + 2017-09-24 daily diff --git a/docs/write/index.html b/docs/write/index.html index 64a3363ef63..6452bde6b84 100644 --- a/docs/write/index.html +++ b/docs/write/index.html @@ -250,6 +250,13 @@ Adding new fields + + +
  • + + Appending value to an array field + +
  • @@ -355,6 +362,13 @@ Adding new fields +
  • + +
  • + + Appending value to an array field + +
  • @@ -436,6 +450,28 @@

    Adding new fieldsAppending value to an array field

    +

    Given a sample.yaml file of:

    +
    b:
    +  c: 2
    +  d:
    +    - new thing
    +    - foo thing
    +
    + +

    then

    +
    yaml w sample.yaml b.d[+] "bar thing"
    +
    + +

    will output:

    +
    b:
    +  c: cat
    +  d:
    +    - new thing
    +    - foo thing
    +    - bar thing
    +
    +

    Updating files in-place

    Given a sample.yaml file of:

    b:
    diff --git a/mkdocs/write.md b/mkdocs/write.md
    index 209a004836a..460c74e8f33 100644
    --- a/mkdocs/write.md
    +++ b/mkdocs/write.md
    @@ -44,6 +44,29 @@ b:
         - new thing
     ```
     
    +### Appending value to an array field
    +Given a sample.yaml file of:
    +```yaml
    +b:
    +  c: 2
    +  d:
    +    - new thing
    +    - foo thing
    +```
    +then
    +```bash
    +yaml w sample.yaml b.d[+] "bar thing"
    +```
    +will output:
    +```yaml
    +b:
    +  c: cat
    +  d:
    +    - new thing
    +    - foo thing
    +    - bar thing
    +```
    +
     ### Updating files in-place
     Given a sample.yaml file of:
     ```yaml
    diff --git a/path_parser_test.go b/path_parser_test.go
    index e733f58b846..a8088d379ef 100644
    --- a/path_parser_test.go
    +++ b/path_parser_test.go
    @@ -10,6 +10,7 @@ var parsePathsTests = []struct {
     }{
     	{"a.b", []string{"a", "b"}},
     	{"a.b[0]", []string{"a", "b", "0"}},
    +	{"a.b.d[+]", []string{"a", "b", "d", "+"}},
     }
     
     func TestParsePath(t *testing.T) {
    diff --git a/yaml.go b/yaml.go
    index bff7eeee973..d1795579955 100644
    --- a/yaml.go
    +++ b/yaml.go
    @@ -98,10 +98,14 @@ yaml write --inplace things.yaml a.b.c cat
     yaml w -i things.yaml a.b.c cat
     yaml w --script update_script.yaml things.yaml
     yaml w -i -s update_script.yaml things.yaml
    +yaml w things.yaml a.b.d[+] foo
    +yaml w things.yaml a.b.d[+] foo
           `,
     		Long: `Updates the yaml file w.r.t the given path and value.
     Outputs to STDOUT unless the inplace flag is used, in which case the file is updated instead.
     
    +Append value to array adds the value to the end of array.
    +
     Update Scripts:
     Note that you can give an update script to perform more sophisticated updated. Update script
     format is a yaml map where the key is the path and the value is..well the value. e.g.: