From 51fa1a87b7e4677ec9f58f4a7bd477bc6c50ce45 Mon Sep 17 00:00:00 2001 From: kenjones Date: Sat, 23 Sep 2017 13:53:04 -0400 Subject: [PATCH] Bugfix: Read yaml array Parsing an array into MapSlice results in `[{nil, nil}]`. Parse into `[]map[interface{}]interface{}` allows for the processing of top level arrays in the document. Resolves: #23 --- commands_test.go | 93 +++++++++++++++++++++++++++++++++++++++++++++ examples/array.yaml | 9 +++++ yaml.go | 43 +++++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 examples/array.yaml diff --git a/commands_test.go b/commands_test.go index 2661d076d89..ab3b468494a 100644 --- a/commands_test.go +++ b/commands_test.go @@ -106,6 +106,99 @@ func TestReadCmd(t *testing.T) { assertResult(t, "2\n", result.Output) } +func TestReadCmd_ArrayYaml(t *testing.T) { + cmd := getRootCommand() + result := runCmd(cmd, "read examples/array.yaml [0].gather_facts") + if result.Error != nil { + t.Error(result.Error) + } + assertResult(t, "false\n", result.Output) +} + +func TestReadCmd_ArrayYaml_NoPath(t *testing.T) { + cmd := getRootCommand() + result := runCmd(cmd, "read examples/array.yaml") + if result.Error != nil { + t.Error(result.Error) + } + expectedOutput := `- become: true + gather_facts: false + hosts: lalaland + name: Apply smth + roles: + - lala + - land + serial: 1 +` + assertResult(t, expectedOutput, result.Output) +} + +func TestReadCmd_ArrayYaml_OneElement(t *testing.T) { + cmd := getRootCommand() + result := runCmd(cmd, "read examples/array.yaml [0]") + if result.Error != nil { + t.Error(result.Error) + } + expectedOutput := `become: true +gather_facts: false +hosts: lalaland +name: Apply smth +roles: +- lala +- land +serial: 1 +` + assertResult(t, expectedOutput, result.Output) +} + +func TestReadCmd_ArrayYaml_Splat(t *testing.T) { + cmd := getRootCommand() + result := runCmd(cmd, "read examples/array.yaml [*]") + if result.Error != nil { + t.Error(result.Error) + } + expectedOutput := `- become: true + gather_facts: false + hosts: lalaland + name: Apply smth + roles: + - lala + - land + serial: 1 +` + assertResult(t, expectedOutput, result.Output) +} + +func TestReadCmd_ArrayYaml_SplatKey(t *testing.T) { + cmd := getRootCommand() + result := runCmd(cmd, "read examples/array.yaml [*].gather_facts") + if result.Error != nil { + t.Error(result.Error) + } + expectedOutput := "- false\n" + assertResult(t, expectedOutput, result.Output) +} + +func TestReadCmd_ArrayYaml_ErrorBadPath(t *testing.T) { + cmd := getRootCommand() + result := runCmd(cmd, "read examples/array.yaml [x].gather_facts") + if result.Error == nil { + t.Error("Expected command to fail due to invalid path") + } + expectedOutput := `Error accessing array: strconv.ParseInt: parsing "x": invalid syntax` + assertResult(t, expectedOutput, result.Error.Error()) +} + +func TestReadCmd_ArrayYaml_Splat_ErrorBadPath(t *testing.T) { + cmd := getRootCommand() + result := runCmd(cmd, "read examples/array.yaml [*].roles[x]") + if result.Error == nil { + t.Error("Expected command to fail due to invalid path") + } + expectedOutput := `Error accessing array: strconv.ParseInt: parsing "x": invalid syntax` + assertResult(t, expectedOutput, result.Error.Error()) +} + func TestReadCmd_Error(t *testing.T) { cmd := getRootCommand() result := runCmd(cmd, "read") diff --git a/examples/array.yaml b/examples/array.yaml new file mode 100644 index 00000000000..67c34c04909 --- /dev/null +++ b/examples/array.yaml @@ -0,0 +1,9 @@ +--- +- become: true + gather_facts: false + hosts: lalaland + name: "Apply smth" + roles: + - lala + - land + serial: 1 diff --git a/yaml.go b/yaml.go index 9038bc1b7c5..35b0af4dfcb 100644 --- a/yaml.go +++ b/yaml.go @@ -185,6 +185,17 @@ func read(args []string) (interface{}, error) { path = "thing." + path } + if parsedData != nil && parsedData[0].Key == nil { + var interfaceData []map[interface{}]interface{} + if err := readData(args[0], &interfaceData); err == nil { + var listMap []yaml.MapSlice + for _, item := range interfaceData { + listMap = append(listMap, mapToMapSlice(item)) + } + return readYamlArray(listMap, path) + } + } + if path == "" { return parsedData, nil } @@ -194,6 +205,38 @@ func read(args []string) (interface{}, error) { return readMap(parsedData, paths[0], paths[1:]) } +func readYamlArray(listMap []yaml.MapSlice, path string) (interface{}, error) { + if path == "" { + return listMap, nil + } + + var paths = parsePath(path) + + if paths[0] == "*" { + if len(paths[1:]) == 0 { + return listMap, nil + } + var results []interface{} + for _, m := range listMap { + value, err := readMap(m, paths[1], paths[2:]) + if err != nil { + return nil, err + } + results = append(results, value) + } + return results, nil + } + + index, err := strconv.ParseInt(paths[0], 10, 64) + if err != nil { + return nil, fmt.Errorf("Error accessing array: %v", err) + } + if len(paths[1:]) == 0 { + return listMap[index], nil + } + return readMap(listMap[index], paths[1], paths[2:]) +} + func newProperty(cmd *cobra.Command, args []string) error { updatedData, err := newYaml(args) if err != nil {