diff --git a/pkg/executionscommon/executionscommon.go b/pkg/executionscommon/executionscommon.go index d9868b67..6a2edce7 100644 --- a/pkg/executionscommon/executionscommon.go +++ b/pkg/executionscommon/executionscommon.go @@ -345,6 +345,7 @@ func LookupPackageDownloadString(value bool) string { // splitVariableString is a derivative of splitPackageOverrideString in release create. // it is required because the builtin go strings.SplitN can't handle more than one delimeter character. // otherwise it works the same, but caps the number of splits at 'n' + func splitVariableString(s string, n int) []string { // pass 1: collect spans; golang strings.FieldsFunc says it's much more efficient this way type span struct { @@ -355,8 +356,15 @@ func splitVariableString(s string, n int) []string { // Find the field start and end indices. start := 0 // we always start the first span at the beginning of the string + escaped := false + for idx, ch := range s { - if ch == ':' || ch == '=' { + if ch == '\\' && !escaped { + escaped = true + continue + } + + if (ch == ':' || ch == '=') && (!escaped) { if start >= 0 { // we found a delimiter and we are already in a span; end the span and start a new one if len(spans) == n-1 { // we're about to append the last span, break so the 'last field' code consumes the rest of the string break @@ -369,6 +377,8 @@ func splitVariableString(s string, n int) []string { start = idx } } + } else { + escaped = false } } @@ -382,9 +392,31 @@ func splitVariableString(s string, n int) []string { for i, span := range spans { a[i] = s[span.start:span.end] } + + // the parts + for i, part := range a { + a[i] = unescape(part) + } + return a } +func unescape(s string) string { + result := make([]rune, 0, len(s)) + escaped := false + + for _, ch := range s { + if ch == '\\' && !escaped { + escaped = true + continue + } + result = append(result, ch) + escaped = false + } + + return string(result) +} + // ScheduledStartTimeAnswerFormatter is passed to the DatePicker so that if the user selects a time within the next // one minute after 'now', it will show the answer as the string "Now" rather than the actual datetime string func ScheduledStartTimeAnswerFormatter(datePicker *surveyext.DatePicker, t time.Time) string { diff --git a/pkg/executionscommon/executionscommon_test.go b/pkg/executionscommon/executionscommon_test.go index 8750c72f..8fb92941 100644 --- a/pkg/executionscommon/executionscommon_test.go +++ b/pkg/executionscommon/executionscommon_test.go @@ -336,6 +336,7 @@ func TestParseVariableStringArray(t *testing.T) { {name: "foo=bar,baz=qux", input: []string{"foo=bar", "baz=qux"}, expect: map[string]string{"foo": "bar", "baz": "qux"}}, {name: "foo:bar:more=stuff", input: []string{"foo:bar:more=stuff"}, expect: map[string]string{"foo": "bar:more=stuff"}}, + {name: "foo\\:bar:more=stuff", input: []string{"foo\\:bar:more=stuff"}, expect: map[string]string{"foo:bar": "more=stuff"}}, {name: "trims whitespace", input: []string{" foo : \tbar "}, expect: map[string]string{"foo": "bar"}},