From 55e9359760d613337bb5bfb5ce89383377a737db Mon Sep 17 00:00:00 2001 From: Johan Dewe Date: Fri, 11 Jun 2021 15:05:10 +0200 Subject: [PATCH] fix: make export --format respect "/" in template actions During tk export path separators are temporarily replaced with BEL in order to protect paths from being mixed with template output. But when there is a slash in a template action (e.g. {{index .metadata.labels "app.kubernetes.io/name"}}, that slash also got replaced, and the template did not work as expected. This fix ensures that the BEL replacement only occurs within the text portions of the template, and the action blocks are being preserved. Fixes #568 --- .vscode/settings.json | 3 +++ pkg/tanka/export.go | 20 +++++++++++++++++++- pkg/tanka/export_test.go | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json create mode 100644 pkg/tanka/export_test.go diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..008074e26 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "go.formatTool": "gofmt" +} \ No newline at end of file diff --git a/pkg/tanka/export.go b/pkg/tanka/export.go index 8916bd0ac..69109595f 100644 --- a/pkg/tanka/export.go +++ b/pkg/tanka/export.go @@ -175,7 +175,7 @@ func writeExportFile(path string, data []byte) error { func createTemplate(format string, env manifest.Manifest) (*template.Template, error) { // Replace all os.path separators in string with BelRune for creating subfolders - replaceFormat := strings.Replace(format, string(os.PathSeparator), BelRune, -1) + replaceFormat := replaceTmplText(format, string(os.PathSeparator), BelRune) envMap := template.FuncMap{"env": func() manifest.Manifest { return env }} @@ -189,6 +189,24 @@ func createTemplate(format string, env manifest.Manifest) (*template.Template, e return template, nil } +func replaceTmplText(s, old, new string) string { + parts := []string{} + l := strings.Index(s, "{{") + r := strings.Index(s, "}}") + 2 + + for l != -1 && l < r { + // replace only in text between template action blocks + text := strings.ReplaceAll(s[:l], old, new) + action := s[l:r] + parts = append(parts, text, action) + s = s[r:] + l = strings.Index(s, "{{") + r = strings.Index(s, "}}") + 2 + } + parts = append(parts, strings.ReplaceAll(s, old, new)) + return strings.Join(parts, "") +} + func applyTemplate(template *template.Template, m manifest.Manifest) (path string, err error) { buf := bytes.Buffer{} if err := template.Execute(&buf, m); err != nil { diff --git a/pkg/tanka/export_test.go b/pkg/tanka/export_test.go new file mode 100644 index 000000000..9663c6952 --- /dev/null +++ b/pkg/tanka/export_test.go @@ -0,0 +1,33 @@ +package tanka + +import "testing" + +func Test_replaceTmplText(t *testing.T) { + type args struct { + s string + old string + new string + } + tests := []struct { + name string + args args + want string + }{ + {"text only", args{"a", "a", "b"}, "b"}, + {"action blocks", args{"{{a}}{{.}}", "a", "b"}, "{{a}}{{.}}"}, + {"mixed", args{"a{{a}}a{{a}}a", "a", "b"}, "b{{a}}b{{a}}b"}, + {"invalid template format handled as text", args{"a}}a{{a", "a", "b"}, "b}}b{{b"}, + { + name: "keep path separator in action block", + args: args{`{{index .metadata.labels "app.kubernetes.io/name"}}/{{.metadata.name}}`, "/", BelRune}, + want: "{{index .metadata.labels \"app.kubernetes.io/name\"}}\u0007{{.metadata.name}}", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := replaceTmplText(tt.args.s, tt.args.old, tt.args.new); got != tt.want { + t.Errorf("replaceInTmplText() = %v, want %v", got, tt.want) + } + }) + } +}