From 97c68adc4d53c13fb32432010a8f7c5172e3549d Mon Sep 17 00:00:00 2001 From: Tuan Date: Sat, 28 Mar 2020 09:39:41 +0800 Subject: [PATCH] Add fromYamlArray and fromJsonArray template helpers (#7712) Signed-off-by: Tuan Nguyen --- pkg/engine/funcs.go | 42 +++++++++++++++++++++++++++++++++++----- pkg/engine/funcs_test.go | 20 +++++++++++++++++++ 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/pkg/engine/funcs.go b/pkg/engine/funcs.go index dac105e74..e5769cbe0 100644 --- a/pkg/engine/funcs.go +++ b/pkg/engine/funcs.go @@ -48,11 +48,13 @@ func funcMap() template.FuncMap { // Add some extra functionality extra := template.FuncMap{ - "toToml": toTOML, - "toYaml": toYAML, - "fromYaml": fromYAML, - "toJson": toJSON, - "fromJson": fromJSON, + "toToml": toTOML, + "toYaml": toYAML, + "fromYaml": fromYAML, + "fromYamlArray": fromYAMLArray, + "toJson": toJSON, + "fromJson": fromJSON, + "fromJsonArray": fromJSONArray, // This is a placeholder for the "include" function, which is // late-bound to a template. By declaring it here, we preserve the @@ -97,6 +99,21 @@ func fromYAML(str string) map[string]interface{} { return m } +// fromYAMLArray converts a YAML array into a []interface{}. +// +// This is not a general-purpose YAML parser, and will not parse all valid +// YAML documents. Additionally, because its intended use is within templates +// it tolerates errors. It will insert the returned error message string as +// the first and only item in the returned array. +func fromYAMLArray(str string) []interface{} { + a := []interface{}{} + + if err := yaml.Unmarshal([]byte(str), &a); err != nil { + a = []interface{}{err.Error()} + } + return a +} + // toTOML takes an interface, marshals it to toml, and returns a string. It will // always return a string, even on marshal error (empty string). // @@ -138,3 +155,18 @@ func fromJSON(str string) map[string]interface{} { } return m } + +// fromJSONArray converts a JSON array into a []interface{}. +// +// This is not a general-purpose JSON parser, and will not parse all valid +// JSON documents. Additionally, because its intended use is within templates +// it tolerates errors. It will insert the returned error message string as +// the first and only item in the returned array. +func fromJSONArray(str string) []interface{} { + a := []interface{}{} + + if err := json.Unmarshal([]byte(str), &a); err != nil { + a = []interface{}{err.Error()} + } + return a +} diff --git a/pkg/engine/funcs_test.go b/pkg/engine/funcs_test.go index a94ff257e..a405c1c47 100644 --- a/pkg/engine/funcs_test.go +++ b/pkg/engine/funcs_test.go @@ -45,6 +45,14 @@ func TestFuncs(t *testing.T) { tpl: `{{ fromYaml . }}`, expect: "map[hello:world]", vars: `hello: world`, + }, { + tpl: `{{ fromYamlArray . }}`, + expect: "[one 2 map[name:helm]]", + vars: "- one\n- 2\n- name: helm\n", + }, { + tpl: `{{ fromYamlArray . }}`, + expect: "[one 2 map[name:helm]]", + vars: `["one", 2, { "name": "helm" }]`, }, { // Regression for https://github.com/helm/helm/issues/2271 tpl: `{{ toToml . }}`, @@ -62,6 +70,14 @@ func TestFuncs(t *testing.T) { tpl: `{{ fromJson . }}`, expect: `map[Error:json: cannot unmarshal array into Go value of type map[string]interface {}]`, vars: `["one", "two"]`, + }, { + tpl: `{{ fromJsonArray . }}`, + expect: `[one 2 map[name:helm]]`, + vars: `["one", 2, { "name": "helm" }]`, + }, { + tpl: `{{ fromJsonArray . }}`, + expect: `[json: cannot unmarshal object into Go value of type []interface {}]`, + vars: `{"hello": "world"}`, }, { tpl: `{{ merge .dict (fromYaml .yaml) }}`, expect: `map[a:map[b:c]]`, @@ -74,6 +90,10 @@ func TestFuncs(t *testing.T) { tpl: `{{ fromYaml . }}`, expect: `map[Error:error unmarshaling JSON: while decoding JSON: json: cannot unmarshal array into Go value of type map[string]interface {}]`, vars: `["one", "two"]`, + }, { + tpl: `{{ fromYamlArray . }}`, + expect: `[error unmarshaling JSON: while decoding JSON: json: cannot unmarshal object into Go value of type []interface {}]`, + vars: `hello: world`, }} for _, tt := range tests {