Skip to content

Commit 1d28bd2

Browse files
committed
cfgparser: add optional splitting of ENV variable values on comma via env_split
1 parent 798c411 commit 1d28bd2

File tree

3 files changed

+66
-6
lines changed

3 files changed

+66
-6
lines changed

docs/reference/config-syntax.md

+10-2
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,16 @@ directive0 {env:VAR}
8787
Parse is forgiving and incomplete variable placeholder (e.g. '{env:VAR') will
8888
be left as-is. Variables are expanded inside quotes too.
8989

90+
Environment values that are comma separated can optionally be split to space separated strings using {env_split:COMMA_SEPARATED_VARIABLE_NAME}
91+
92+
```
93+
# SEP_VAR=foo,bar,baz
94+
95+
directive1 {env_split:SEP_VAR}
96+
```
97+
98+
In this usage the value of `directive1` would be `foo bar baz` (and `{env:SEP_VAR}` would be `foo,bar,baz`)
99+
90100
## Snippets & imports
91101

92102
You can reuse blocks of configuration by defining them as "snippets". Snippet
@@ -196,5 +206,3 @@ No-op module. It doesn't need to be configured explicitly and can be referenced
196206
using "dummy" name. It can act as a delivery target or auth.
197207
provider. In the latter case, it will accept any credentials, allowing any
198208
client to authenticate using any username and password (use with care!).
199-
200-

framework/cfgparser/env.go

+14-4
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,21 @@ func expandEnvironment(nodes []Node) []Node {
4646
return newNodes
4747
}
4848

49-
var unixEnvvarRe = regexp.MustCompile(`{env:([^\$]+)}`)
49+
var unixEnvvarRe = regexp.MustCompile(`\{(env|env_split):([^\}]+)\}`)
5050

5151
func removeUnexpandedEnvvars(s string) string {
52-
s = unixEnvvarRe.ReplaceAllString(s, "")
53-
return s
52+
return unixEnvvarRe.ReplaceAllStringFunc(s, func(match string) string {
53+
matches := unixEnvvarRe.FindStringSubmatch(match)
54+
if len(matches) != 3 {
55+
return match // Not a valid pattern
56+
}
57+
key, mode := matches[2], matches[1]
58+
value := os.Getenv(key)
59+
if mode == "env_split" {
60+
value = strings.ReplaceAll(value, ",", " ")
61+
}
62+
return value
63+
})
5464
}
5565

5666
func buildEnvReplacer() *strings.Replacer {
@@ -61,7 +71,7 @@ func buildEnvReplacer() *strings.Replacer {
6171
key := parts[0]
6272
value := parts[1]
6373

64-
pairs = append(pairs, "{env:"+key+"}", value)
74+
pairs = append(pairs, "{env:"+key+"}", value, "{envSplit:"+key+"}", value)
6575
}
6676
return strings.NewReplacer(pairs...)
6777
}

framework/cfgparser/parse_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,47 @@ var cases = []struct {
342342
},
343343
false,
344344
},
345+
{
346+
"environment variable split at comma expansion",
347+
`a {env_split:TESTING_VARIABLE_SPLIT}`,
348+
[]Node{
349+
{
350+
Name: "a",
351+
Args: []string{"value1 value2 value3"},
352+
Children: nil,
353+
File: "test",
354+
Line: 1,
355+
},
356+
},
357+
false,
358+
},
359+
{
360+
"environment variable mixed usage",
361+
`mixed {env:TESTING_VARIABLE} {env_split:TESTING_VARIABLE_SPLIT}`,
362+
[]Node{
363+
{
364+
Name: "mixed",
365+
Args: []string{"ABCDEF", "value1 value2 value3"},
366+
Children: nil,
367+
File: "test",
368+
Line: 1,
369+
},
370+
},
371+
false,
372+
},
373+
{
374+
"environment variable not split on comma",
375+
`not_split {env:TESTING_VARIABLE_SPLIT}`,
376+
[]Node{
377+
{
378+
Name: "not_split",
379+
Args: []string{"value1,value2,value3"},
380+
File: "test",
381+
Line: 1,
382+
},
383+
},
384+
false,
385+
},
345386
{
346387
"snippet expansion",
347388
`(foo) { a }
@@ -581,6 +622,7 @@ func printTree(t *testing.T, root Node, indent int) {
581622
func TestRead(t *testing.T) {
582623
os.Setenv("TESTING_VARIABLE", "ABCDEF")
583624
os.Setenv("TESTING_VARIABLE2", "ABC2 DEF2")
625+
os.Setenv("TESTING_VARIABLE_SPLIT", "value1,value2,value3")
584626

585627
for _, case_ := range cases {
586628
case_ := case_

0 commit comments

Comments
 (0)