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

Commit 929680e

Browse files
committed
adding ability to parse default bash variables such as ${foo:-bar} in the compose file
Signed-off-by: GodFather <[email protected]>
1 parent 68ce73f commit 929680e

File tree

2 files changed

+75
-1
lines changed

2 files changed

+75
-1
lines changed

config/interpolation.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@ import (
88
"github.com/Sirupsen/logrus"
99
)
1010

11+
var defaultValues = make(map[string]string)
12+
1113
func isNum(c uint8) bool {
1214
return c >= '0' && c <= '9'
1315
}
1416

17+
func validVariableDefault(c uint8, line string, pos int) bool {
18+
return c == ':' && line[pos+1] == '-'
19+
}
20+
1521
func validVariableNameChar(c uint8) bool {
1622
return c == '_' ||
1723
c >= 'A' && c <= 'Z' ||
@@ -36,6 +42,22 @@ func parseVariable(line string, pos int, mapping func(string) string) (string, i
3642
return mapping(buffer.String()), pos, true
3743
}
3844

45+
func parseDefaultValue(line string, pos int) (string, int, bool) {
46+
var buffer bytes.Buffer
47+
48+
for ; pos < len(line); pos++ {
49+
c := line[pos]
50+
if c == '}' {
51+
return buffer.String(), pos - 1, true
52+
}
53+
err := buffer.WriteByte(c)
54+
if err != nil {
55+
return "", pos, false
56+
}
57+
}
58+
return "", 0, false
59+
}
60+
3961
func parseVariableWithBraces(line string, pos int, mapping func(string) string) (string, int, bool) {
4062
var buffer bytes.Buffer
4163

@@ -49,10 +71,13 @@ func parseVariableWithBraces(line string, pos int, mapping func(string) string)
4971
if bufferString == "" {
5072
return "", 0, false
5173
}
52-
5374
return mapping(buffer.String()), pos, true
5475
case validVariableNameChar(c):
5576
buffer.WriteByte(c)
77+
case validVariableDefault(c, line, pos):
78+
defaultValue := ""
79+
defaultValue, pos, _ = parseDefaultValue(line, pos+2)
80+
defaultValues[buffer.String()] = defaultValue
5681
default:
5782
return "", 0, false
5883
}
@@ -143,10 +168,19 @@ func Interpolate(key string, data *interface{}, environmentLookup EnvironmentLoo
143168
values := environmentLookup.Lookup(s, nil)
144169

145170
if len(values) == 0 {
171+
if val, ok := defaultValues[s]; ok {
172+
return val
173+
}
146174
logrus.Warnf("The %s variable is not set. Substituting a blank string.", s)
147175
return ""
148176
}
149177

178+
if strings.SplitN(values[0], "=", 2)[1] == "" {
179+
if val, ok := defaultValues[s]; ok {
180+
return val
181+
}
182+
}
183+
150184
// Use first result if many are given
151185
value := values[0]
152186

config/interpolation_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,14 @@ func TestParseLine(t *testing.T) {
3535
"split_VaLue": "WORKED",
3636
"9aNumber": "WORKED",
3737
"a9Number": "WORKED",
38+
"defTest": "WORKED",
3839
}
3940

4041
testInterpolatedLine(t, "WORKED", "$lower", variables)
4142
testInterpolatedLine(t, "WORKED", "${MiXeD}", variables)
4243
testInterpolatedLine(t, "WORKED", "${split_VaLue}", variables)
44+
// make sure variable name is parsed correctly with default value
45+
testInterpolatedLine(t, "WORKED", "${defTest:-sometest}", variables)
4346
// Starting with a number isn't valid
4447
testInterpolatedLine(t, "", "$9aNumber", variables)
4548
testInterpolatedLine(t, "WORKED", "$a9Number", variables)
@@ -198,6 +201,43 @@ func TestInterpolate(t *testing.T) {
198201
"HOST_PORT": "=",
199202
"LABEL_VALUE": "myvalue==",
200203
})
204+
// same as above but with default values
205+
testInterpolatedConfig(t,
206+
`web:
207+
# unbracketed name
208+
image: busybox
209+
210+
# array element
211+
ports:
212+
- "80:8000"
213+
214+
# dictionary item value
215+
labels:
216+
mylabel: "myvalue"
217+
218+
# unset value
219+
hostname: "host-"
220+
221+
# escaped interpolation
222+
command: "${ESCAPED}"`,
223+
224+
`web:
225+
# unbracketed name
226+
image: ${IMAGE:-busybox}
227+
228+
# array element
229+
ports:
230+
- "${HOST_PORT:-80}:8000"
231+
232+
# dictionary item value
233+
labels:
234+
mylabel: "${LABEL_VALUE:-myvalue}"
235+
236+
# unset value
237+
hostname: "host-${UNSET_VALUE}"
238+
239+
# escaped interpolation
240+
command: "$${ESCAPED}"`, map[string]string{})
201241

202242
testInvalidInterpolatedConfig(t,
203243
`web:

0 commit comments

Comments
 (0)