Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit ca73c93

Browse files
committed
Make defaults work with nested env variables ie: ${FOO:-${HOME}/bar}
Signed-off-by: GodFather <[email protected]>
1 parent 0e8984f commit ca73c93

File tree

2 files changed

+66
-15
lines changed

2 files changed

+66
-15
lines changed

config/interpolation.go

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,26 +42,46 @@ func parseVariable(line string, pos int, mapping func(string) string) (string, i
4242
return mapping(buffer.String()), pos, true
4343
}
4444

45-
func parseDefaultValue(line string, pos int) (string, int, bool) {
45+
func parseDefaultValue(line string, pos int, mapping func(string) string) (string, int, bool) {
4646
var buffer bytes.Buffer
47+
success := false
48+
replaced := ""
4749

50+
fmt.Printf("INCOMING: %v\n", string(line[pos]))
4851
// only skip :, :- and - at the beginning
4952
for ; pos < len(line); pos++ {
5053
c := line[pos]
54+
fmt.Printf("SKIP: %v\n", string(c))
5155
if c == ':' || c == '-' {
5256
continue
5357
}
5458
break
5559
}
5660
for ; pos < len(line); pos++ {
5761
c := line[pos]
58-
if c == '}' {
62+
switch {
63+
case c == '$':
64+
if line[pos-1] != '\\' {
65+
fmt.Printf("NESTED: %v pos: %v\n", string(c), pos)
66+
replaced, pos, success = parseInterpolationExpression(line, pos + 1, mapping)
67+
_, err := buffer.WriteString(replaced)
68+
fmt.Printf("REPLACED: %v pos: %v\n", replaced, pos)
69+
if success == false || err != nil {
70+
return "", 0, false
71+
}
72+
}
73+
case c == '}':
74+
fmt.Printf("ENDIT: %v\n", string(c))
5975
return buffer.String(), pos - 1, true
76+
default:
77+
fmt.Printf("APPEND: %v\n", string(c))
78+
// err := buffer.WriteByte(c)
79+
if err := buffer.WriteByte(c); err != nil {
80+
return "", pos, false
81+
}
82+
fmt.Printf("APPEND: %v\n", string(c))
6083
}
61-
err := buffer.WriteByte(c)
62-
if err != nil {
63-
return "", pos, false
64-
}
84+
fmt.Printf("BUFFER: %v\n", string(buffer.String()))
6585
}
6686
return "", 0, false
6787
}
@@ -71,11 +91,11 @@ func parseVariableWithBraces(line string, pos int, mapping func(string) string)
7191

7292
for ; pos < len(line); pos++ {
7393
c := line[pos]
94+
fmt.Printf("val: %v\n", string(c))
7495

7596
switch {
7697
case c == '}':
7798
bufferString := buffer.String()
78-
7999
if bufferString == "" {
80100
return "", 0, false
81101
}
@@ -84,7 +104,7 @@ func parseVariableWithBraces(line string, pos int, mapping func(string) string)
84104
buffer.WriteByte(c)
85105
case validVariableDefault(c, line, pos):
86106
defaultValue := ""
87-
defaultValue, pos, _ = parseDefaultValue(line, pos)
107+
defaultValue, pos, _ = parseDefaultValue(line, pos, mapping)
88108
defaultValues[buffer.String()] = defaultValue
89109
default:
90110
return "", 0, false

config/interpolation_test.go

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ func testInterpolatedLine(t *testing.T, expectedLine, interpolatedLine string, e
1515
return envVariables[s]
1616
})
1717

18+
fmt.Printf("EXPECTED: %s and ACTUAL: %s\n", expectedLine, interpolatedLine)
1819
assert.Equal(t, expectedLine, interpolatedLine)
1920
}
2021

@@ -26,10 +27,25 @@ func testInvalidInterpolatedLine(t *testing.T, line string) {
2627
assert.Equal(t, false, success)
2728
}
2829

29-
func testInterpolatedDefault(t *testing.T, line string, delim string, expectedVar string, expectedVal string) {
30-
envVar, _ := parseLine(line, func(env string) string { return env })
30+
func testInterpolatedDefault(t *testing.T, line string, delim string, expectedVar string, expectedVal string, envVariables map[string]string) {
31+
envVar, _ := parseLine(line, func(s string) string {
32+
fmt.Printf("request: %v\n", s)
33+
if val, ok := envVariables[s]; ok {
34+
return val
35+
}
36+
return s
37+
})
38+
3139
pos := strings.Index(line, delim)
32-
envDefault, _, _ := parseDefaultValue(line, pos)
40+
envDefault, _, _ := parseDefaultValue(line, pos, func(s string) string {
41+
fmt.Printf("request: %v\n", s)
42+
if val, ok := envVariables[s]; ok {
43+
return val
44+
}
45+
return s
46+
})
47+
fmt.Printf("EXPECTED: %s and ACTUAL: %s\n", expectedVal, envDefault)
48+
fmt.Printf("EXPECTED: %s and ACTUAL: %s\n", expectedVar, envVar)
3349
assert.Equal(t, expectedVal, envDefault)
3450
assert.Equal(t, expectedVar, envVar)
3551
}
@@ -45,16 +61,25 @@ func TestParseLine(t *testing.T) {
4561
"9aNumber": "WORKED",
4662
"a9Number": "WORKED",
4763
"defTest": "WORKED",
64+
"test_domain": "127.0.0.1:27017",
65+
"HOME": "/home/foo",
66+
"test_tilde": "~/.home/test",
4867
}
4968

50-
testInterpolatedDefault(t, "${defVar:-defVal}", ":-", "defVar", "defVal")
51-
testInterpolatedDefault(t, "${defVar2-defVal2}", "-", "defVar2", "defVal2")
52-
testInterpolatedDefault(t, "${defVar:-def:Val}", ":-", "defVar", "def:Val")
53-
testInterpolatedDefault(t, "${defVar:-def-Val}", ":-", "defVar", "def-Val")
69+
testInterpolatedDefault(t, "${defVar:-defVal}", ":-", "defVar", "defVal", variables)
70+
testInterpolatedDefault(t, "${defVar2-defVal2}", "-", "defVar2", "defVal2", variables)
71+
testInterpolatedDefault(t, "${defVar:-def:Val}", ":-", "defVar", "def:Val", variables)
72+
testInterpolatedDefault(t, "${defVar:-def-Val}", ":-", "defVar", "def-Val", variables)
73+
testInterpolatedDefault(t, "${defVar:-~/foo/bar}", ":-", "defVar", "~/foo/bar", variables)
74+
testInterpolatedDefault(t, "${defVar:-${HOME}/.bar/test}", ":-", "defVar", "/home/foo/.bar/test", variables)
75+
testInterpolatedDefault(t, "${defVar:-127.0.0.1:27017}", ":-", "defVar", "127.0.0.1:27017", variables)
5476

5577
testInterpolatedLine(t, "WORKED", "$lower", variables)
5678
testInterpolatedLine(t, "WORKED", "${MiXeD}", variables)
5779
testInterpolatedLine(t, "WORKED", "${split_VaLue}", variables)
80+
testInterpolatedLine(t, "127.0.0.1:27017", "${test_domain}", variables)
81+
testInterpolatedLine(t, "~/.home/test", "${test_tilde}", variables)
82+
testInterpolatedLine(t, "~/.home/test", "${test_tilde}", variables)
5883
// make sure variable name is parsed correctly with default value
5984
testInterpolatedLine(t, "WORKED", "${defTest:-sometest}", variables)
6085
testInterpolatedLine(t, "WORKED", "${defTest-sometest}", variables)
@@ -190,6 +215,8 @@ func TestInterpolate(t *testing.T) {
190215
# dictionary item value
191216
labels:
192217
mylabel: "myvalue=="
218+
domainlable: "127.0.0.1:27017"
219+
tildelabel: "~/.home/test"
193220
194221
# unset value
195222
hostname: "host-"
@@ -207,6 +234,8 @@ func TestInterpolate(t *testing.T) {
207234
# dictionary item value
208235
labels:
209236
mylabel: "${LABEL_VALUE}"
237+
domainlable: "${TEST_DOMAIN}"
238+
tildelabel: "${TILDE_DIR}"
210239
211240
# unset value
212241
hostname: "host-${UNSET_VALUE}"
@@ -215,6 +244,8 @@ func TestInterpolate(t *testing.T) {
215244
command: "$${ESCAPED}"`, map[string]string{
216245
"IMAGE": "=busybox",
217246
"HOST_PORT": "=",
247+
"TEST_DOMAIN": "127.0.0.1:27017",
248+
"TILDE_DIR": "~/.home/test",
218249
"LABEL_VALUE": "myvalue==",
219250
})
220251
// same as above but with default values

0 commit comments

Comments
 (0)