diff --git a/data/data.go b/data/data.go index beda7f038..fd97c7afc 100644 --- a/data/data.go +++ b/data/data.go @@ -123,6 +123,22 @@ func YAMLArray(in string) ([]interface{}, error) { return obj, nil } +// YAMLStream - parses a (potentially) multi-document YAML stream +func YAMLStream(in string) ([]interface{}, error) { + obj := []interface{}{} + s := strings.NewReader(in) + d := yaml.NewDecoder(s) + for { + var o interface{} + err := d.Decode(&o) + if err == io.EOF { + break + } + obj = append(obj, o) + } + return obj, nil +} + // TOML - Unmarshal a TOML Object func TOML(in string) (interface{}, error) { obj := make(map[string]interface{}) diff --git a/data/data_test.go b/data/data_test.go index ae2c31c7b..a76b84a0e 100644 --- a/data/data_test.go +++ b/data/data_test.go @@ -65,7 +65,7 @@ func TestUnmarshalArray(t *testing.T) { assert.EqualValues(t, expected, actual) } test(JSONArray(`["foo","bar",{"baz":{"qux": true},"quux":{"42":18},"corge":{"false":"blah"}}]`)) - test(YAMLArray(` + test(YAMLArray(`--- - foo - bar - baz: @@ -523,3 +523,22 @@ QUX='single quotes ignore $variables' assert.NoError(t, err) assert.EqualValues(t, expected, out) } + +func TestMultiDocYAML(t *testing.T) { + in := `foo: bar +--- +baz: qux +--- +# empty document with a comment +` + expected := []interface{}{ + map[string]interface{}{"foo": "bar"}, + map[string]interface{}{"baz": "qux"}, + nil, + } + ch, err := YAMLArray(in) + for i, out := range ch { + assert.NoError(t, err) + assert.EqualValues(t, expected[i], out) + } +} diff --git a/funcs/data.go b/funcs/data.go index b13619e3d..96b4c3522 100644 --- a/funcs/data.go +++ b/funcs/data.go @@ -67,6 +67,11 @@ func (f *DataFuncs) YAMLArray(in interface{}) ([]interface{}, error) { return data.YAMLArray(conv.ToString(in)) } +// YAMLStream - +func (f *DataFuncs) YAMLStream(in interface{}) ([]interface{}, error) { + return data.YAMLStream(conv.ToString(in)) +} + // TOML - func (f *DataFuncs) TOML(in interface{}) (interface{}, error) { return data.TOML(conv.ToString(in)) diff --git a/internal/tests/integration/datasources_file_test.go b/internal/tests/integration/datasources_file_test.go index 8304bca77..9b953337c 100644 --- a/internal/tests/integration/datasources_file_test.go +++ b/internal/tests/integration/datasources_file_test.go @@ -39,6 +39,14 @@ FOO.BAR = "values can be double-quoted, and shell\nescapes are supported" BAZ = "variable expansion: ${FOO}" QUX='single quotes ignore $variables' +`, + "multidoc.yaml": `--- +# empty document +--- +foo: bar +--- +foo: baz +... `, }), fs.WithDir("sortorder", fs.WithFiles(map[string]string{ @@ -191,4 +199,12 @@ bar`}) "FOO.BAR": "values can be double-quoted, and shell\nescapes are supported", "QUX": "single quotes ignore $variables" }`}) + + result = icmd.RunCmd(icmd.Command(GomplateBin, + "-d=multidoc.yaml", + "-i", `{{ range $d := (include "multidoc" | data.YAMLStream) }}---{{"\n"}}{{ range $k, $v := $d }}{{ $k }}: {{ $v }}{{"\n"}}{{ end }}{{ end }}`, + ), func(c *icmd.Cmd) { + c.Dir = s.tmpDir.Path() + }) + result.Assert(c, icmd.Expected{ExitCode: 0, Out: "---\n---\nfoo: bar\n---\nfoo: baz\n"}) }