Add support for more advanced ${xxx:...} syntax

Just ${xxx:+...} and ${xxx:-...} for now

Signed-off-by: Doug Davis <dug@us.ibm.com>
This commit is contained in:
Doug Davis 2015-01-28 18:28:48 -08:00
parent 7dd79dcc7b
commit 39908fc6d9
4 changed files with 97 additions and 5 deletions

View File

@ -157,7 +157,40 @@ func (sw *shellWord) processDollar() (string, error) {
sw.next() sw.next()
return sw.getEnv(name), nil return sw.getEnv(name), nil
} }
return "", fmt.Errorf("Unsupported ${} substitution: %s", sw.word) if ch == ':' {
// Special ${xx:...} format processing
// Yes it allows for recursive $'s in the ... spot
sw.next() // skip over :
modifier := sw.next()
word, err := sw.processStopOn('}')
if err != nil {
return "", err
}
// Grab the current value of the variable in question so we
// can use to to determine what to do based on the modifier
newValue := sw.getEnv(name)
switch modifier {
case '+':
if newValue != "" {
newValue = word
}
return newValue, nil
case '-':
if newValue == "" {
newValue = word
}
return newValue, nil
default:
return "", fmt.Errorf("Unsupported modifier (%c) in substitution: %s", modifier, sw.word)
}
}
return "", fmt.Errorf("Missing ':' in substitution: %s", sw.word)
} }
// $xxx case // $xxx case
name := sw.processName() name := sw.processName()

View File

@ -30,6 +30,17 @@ he${hi} | he
he${hi}xx | hexx he${hi}xx | hexx
he${PWD} | he/home he${PWD} | he/home
he${.} | error he${.} | error
he${XXX:-000}xx | he000xx
he${PWD:-000}xx | he/homexx
he${XXX:-$PWD}xx | he/homexx
he${XXX:-${PWD:-yyy}}xx | he/homexx
he${XXX:-${YYY:-yyy}}xx | heyyyxx
he${XXX:YYY} | error
he${XXX:+${PWD}}xx | hexx
he${PWD:+${XXX}}xx | hexx
he${PWD:+${SHELL}}xx | hebashxx
he${XXX:+000}xx | hexx
he${PWD:+000}xx | he000xx
'he${XX}' | he${XX} 'he${XX}' | he${XX}
"he${PWD}" | he/home "he${PWD}" | he/home
"he'$PWD'" | he'/home' "he'$PWD'" | he'/home'
@ -41,3 +52,7 @@ he\$PWD | he$PWD
"he\$PWD" | he$PWD "he\$PWD" | he$PWD
'he\$PWD' | he\$PWD 'he\$PWD' | he\$PWD
he${PWD | error he${PWD | error
he${PWD:=000}xx | error
he${PWD:+${PWD}:}xx | he/home:xx
he${XXX:-\$PWD:}xx | he$PWD:xx
he${XXX:-\${PWD}z}xx | he${PWDz}xx

View File

@ -113,18 +113,30 @@ images.
> replacement at the time. After 1.3 this behavior will be preserved and > replacement at the time. After 1.3 this behavior will be preserved and
> canonical. > canonical.
Environment variables (declared with [the `ENV` statement](#env)) can also be used in Environment variables (declared with [the `ENV` statement](#env)) can also be
certain instructions as variables to be interpreted by the `Dockerfile`. Escapes used in certain instructions as variables to be interpreted by the
are also handled for including variable-like syntax into a statement literally. `Dockerfile`. Escapes are also handled for including variable-like syntax
into a statement literally.
Environment variables are notated in the `Dockerfile` either with Environment variables are notated in the `Dockerfile` either with
`$variable_name` or `${variable_name}`. They are treated equivalently and the `$variable_name` or `${variable_name}`. They are treated equivalently and the
brace syntax is typically used to address issues with variable names with no brace syntax is typically used to address issues with variable names with no
whitespace, like `${foo}_bar`. whitespace, like `${foo}_bar`.
The `${variable_name}` syntax also supports a few of the standard `bash`
modifiers as specified below:
* `${variable:-word}` indicates that if `variable` is set then the result
will be that value. If `variable` is not set then `word` will be the result.
* `${variable:+word}` indiates that if `variable` is set then `word` will be
the result, otherwise the result is the empty string.
In all cases, `word` can be any string, including additional environment
variables.
Escaping is possible by adding a `\` before the variable: `\$foo` or `\${foo}`, Escaping is possible by adding a `\` before the variable: `\$foo` or `\${foo}`,
for example, will translate to `$foo` and `${foo}` literals respectively. for example, will translate to `$foo` and `${foo}` literals respectively.
Example (parsed representation is displayed after the `#`): Example (parsed representation is displayed after the `#`):
FROM busybox FROM busybox

View File

@ -214,13 +214,19 @@ func TestBuildEnvironmentReplacementAddCopy(t *testing.T) {
ENV baz foo ENV baz foo
ENV quux bar ENV quux bar
ENV dot . ENV dot .
ENV fee fff
ENV gee ggg
ADD ${baz} ${dot} ADD ${baz} ${dot}
COPY ${quux} ${dot} COPY ${quux} ${dot}
ADD ${zzz:-${fee}} ${dot}
COPY ${zzz:-${gee}} ${dot}
`, `,
map[string]string{ map[string]string{
"foo": "test1", "foo": "test1",
"bar": "test2", "bar": "test2",
"fff": "test3",
"ggg": "test4",
}) })
if err != nil { if err != nil {
@ -286,6 +292,11 @@ func TestBuildEnvironmentReplacementEnv(t *testing.T) {
if parts[1] != "zzz" { if parts[1] != "zzz" {
t.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1]) t.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1])
} }
} else if strings.HasPrefix(parts[0], "env") {
envCount++
if parts[1] != "foo" {
t.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1])
}
} }
} }
@ -4069,6 +4080,27 @@ RUN [ "$abc" = "'foo'" ]
ENV abc \"foo\" ENV abc \"foo\"
RUN [ "$abc" = '"foo"' ] RUN [ "$abc" = '"foo"' ]
ENV abc=ABC
RUN [ "$abc" = "ABC" ]
ENV def=${abc:-DEF}
RUN [ "$def" = "ABC" ]
ENV def=${ccc:-DEF}
RUN [ "$def" = "DEF" ]
ENV def=${ccc:-${def}xx}
RUN [ "$def" = "DEFxx" ]
ENV def=${def:+ALT}
RUN [ "$def" = "ALT" ]
ENV def=${def:+${abc}:}
RUN [ "$def" = "ABC:" ]
ENV def=${ccc:-\$abc:}
RUN [ "$def" = '$abc:' ]
ENV def=${ccc:-\${abc}:}
RUN [ "$def" = '${abc:}' ]
ENV mypath=${mypath:+$mypath:}/home
RUN [ "$mypath" = '/home' ]
ENV mypath=${mypath:+$mypath:}/away
RUN [ "$mypath" = '/home:/away' ]
ENV e1=bar ENV e1=bar
ENV e2=$e1 ENV e2=$e1
ENV e3=$e11 ENV e3=$e11