Just ${xxx:+...} and ${xxx:-...} for now
Signed-off-by: Doug Davis <dug@us.ibm.com>
| ... | ... |
@@ -157,7 +157,40 @@ func (sw *shellWord) processDollar() (string, error) {
|
| 157 | 157 |
sw.next() |
| 158 | 158 |
return sw.getEnv(name), nil |
| 159 | 159 |
} |
| 160 |
- return "", fmt.Errorf("Unsupported ${} substitution: %s", sw.word)
|
|
| 160 |
+ if ch == ':' {
|
|
| 161 |
+ // Special ${xx:...} format processing
|
|
| 162 |
+ // Yes it allows for recursive $'s in the ... spot |
|
| 163 |
+ |
|
| 164 |
+ sw.next() // skip over : |
|
| 165 |
+ modifier := sw.next() |
|
| 166 |
+ |
|
| 167 |
+ word, err := sw.processStopOn('}')
|
|
| 168 |
+ if err != nil {
|
|
| 169 |
+ return "", err |
|
| 170 |
+ } |
|
| 171 |
+ |
|
| 172 |
+ // Grab the current value of the variable in question so we |
|
| 173 |
+ // can use to to determine what to do based on the modifier |
|
| 174 |
+ newValue := sw.getEnv(name) |
|
| 175 |
+ |
|
| 176 |
+ switch modifier {
|
|
| 177 |
+ case '+': |
|
| 178 |
+ if newValue != "" {
|
|
| 179 |
+ newValue = word |
|
| 180 |
+ } |
|
| 181 |
+ return newValue, nil |
|
| 182 |
+ |
|
| 183 |
+ case '-': |
|
| 184 |
+ if newValue == "" {
|
|
| 185 |
+ newValue = word |
|
| 186 |
+ } |
|
| 187 |
+ return newValue, nil |
|
| 188 |
+ |
|
| 189 |
+ default: |
|
| 190 |
+ return "", fmt.Errorf("Unsupported modifier (%c) in substitution: %s", modifier, sw.word)
|
|
| 191 |
+ } |
|
| 192 |
+ } |
|
| 193 |
+ return "", fmt.Errorf("Missing ':' in substitution: %s", sw.word)
|
|
| 161 | 194 |
} |
| 162 | 195 |
// $xxx case |
| 163 | 196 |
name := sw.processName() |
| ... | ... |
@@ -30,6 +30,17 @@ he${hi} | he
|
| 30 | 30 |
he${hi}xx | hexx
|
| 31 | 31 |
he${PWD} | he/home
|
| 32 | 32 |
he${.} | error
|
| 33 |
+he${XXX:-000}xx | he000xx
|
|
| 34 |
+he${PWD:-000}xx | he/homexx
|
|
| 35 |
+he${XXX:-$PWD}xx | he/homexx
|
|
| 36 |
+he${XXX:-${PWD:-yyy}}xx | he/homexx
|
|
| 37 |
+he${XXX:-${YYY:-yyy}}xx | heyyyxx
|
|
| 38 |
+he${XXX:YYY} | error
|
|
| 39 |
+he${XXX:+${PWD}}xx | hexx
|
|
| 40 |
+he${PWD:+${XXX}}xx | hexx
|
|
| 41 |
+he${PWD:+${SHELL}}xx | hebashxx
|
|
| 42 |
+he${XXX:+000}xx | hexx
|
|
| 43 |
+he${PWD:+000}xx | he000xx
|
|
| 33 | 44 |
'he${XX}' | he${XX}
|
| 34 | 45 |
"he${PWD}" | he/home
|
| 35 | 46 |
"he'$PWD'" | he'/home' |
| ... | ... |
@@ -41,3 +52,7 @@ he\$PWD | he$PWD |
| 41 | 41 |
"he\$PWD" | he$PWD |
| 42 | 42 |
'he\$PWD' | he\$PWD |
| 43 | 43 |
he${PWD | error
|
| 44 |
+he${PWD:=000}xx | error
|
|
| 45 |
+he${PWD:+${PWD}:}xx | he/home:xx
|
|
| 46 |
+he${XXX:-\$PWD:}xx | he$PWD:xx
|
|
| 47 |
+he${XXX:-\${PWD}z}xx | he${PWDz}xx
|
| ... | ... |
@@ -113,18 +113,30 @@ images. |
| 113 | 113 |
> replacement at the time. After 1.3 this behavior will be preserved and |
| 114 | 114 |
> canonical. |
| 115 | 115 |
|
| 116 |
-Environment variables (declared with [the `ENV` statement](#env)) can also be used in |
|
| 117 |
-certain instructions as variables to be interpreted by the `Dockerfile`. Escapes |
|
| 118 |
-are also handled for including variable-like syntax into a statement literally. |
|
| 116 |
+Environment variables (declared with [the `ENV` statement](#env)) can also be |
|
| 117 |
+used in certain instructions as variables to be interpreted by the |
|
| 118 |
+`Dockerfile`. Escapes are also handled for including variable-like syntax |
|
| 119 |
+into a statement literally. |
|
| 119 | 120 |
|
| 120 | 121 |
Environment variables are notated in the `Dockerfile` either with |
| 121 | 122 |
`$variable_name` or `${variable_name}`. They are treated equivalently and the
|
| 122 | 123 |
brace syntax is typically used to address issues with variable names with no |
| 123 | 124 |
whitespace, like `${foo}_bar`.
|
| 124 | 125 |
|
| 126 |
+The `${variable_name}` syntax also supports a few of the standard `bash`
|
|
| 127 |
+modifiers as specified below: |
|
| 128 |
+ |
|
| 129 |
+* `${variable:-word}` indicates that if `variable` is set then the result
|
|
| 130 |
+ will be that value. If `variable` is not set then `word` will be the result. |
|
| 131 |
+* `${variable:+word}` indiates that if `variable` is set then `word` will be
|
|
| 132 |
+ the result, otherwise the result is the empty string. |
|
| 133 |
+ |
|
| 134 |
+In all cases, `word` can be any string, including additional environment |
|
| 135 |
+variables. |
|
| 136 |
+ |
|
| 125 | 137 |
Escaping is possible by adding a `\` before the variable: `\$foo` or `\${foo}`,
|
| 126 | 138 |
for example, will translate to `$foo` and `${foo}` literals respectively.
|
| 127 |
- |
|
| 139 |
+ |
|
| 128 | 140 |
Example (parsed representation is displayed after the `#`): |
| 129 | 141 |
|
| 130 | 142 |
FROM busybox |
| ... | ... |
@@ -214,13 +214,19 @@ func TestBuildEnvironmentReplacementAddCopy(t *testing.T) {
|
| 214 | 214 |
ENV baz foo |
| 215 | 215 |
ENV quux bar |
| 216 | 216 |
ENV dot . |
| 217 |
+ ENV fee fff |
|
| 218 |
+ ENV gee ggg |
|
| 217 | 219 |
|
| 218 | 220 |
ADD ${baz} ${dot}
|
| 219 | 221 |
COPY ${quux} ${dot}
|
| 222 |
+ ADD ${zzz:-${fee}} ${dot}
|
|
| 223 |
+ COPY ${zzz:-${gee}} ${dot}
|
|
| 220 | 224 |
`, |
| 221 | 225 |
map[string]string{
|
| 222 | 226 |
"foo": "test1", |
| 223 | 227 |
"bar": "test2", |
| 228 |
+ "fff": "test3", |
|
| 229 |
+ "ggg": "test4", |
|
| 224 | 230 |
}) |
| 225 | 231 |
|
| 226 | 232 |
if err != nil {
|
| ... | ... |
@@ -286,6 +292,11 @@ func TestBuildEnvironmentReplacementEnv(t *testing.T) {
|
| 286 | 286 |
if parts[1] != "zzz" {
|
| 287 | 287 |
t.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1])
|
| 288 | 288 |
} |
| 289 |
+ } else if strings.HasPrefix(parts[0], "env") {
|
|
| 290 |
+ envCount++ |
|
| 291 |
+ if parts[1] != "foo" {
|
|
| 292 |
+ t.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1])
|
|
| 293 |
+ } |
|
| 289 | 294 |
} |
| 290 | 295 |
} |
| 291 | 296 |
|
| ... | ... |
@@ -4069,6 +4080,27 @@ RUN [ "$abc" = "'foo'" ] |
| 4069 | 4069 |
ENV abc \"foo\" |
| 4070 | 4070 |
RUN [ "$abc" = '"foo"' ] |
| 4071 | 4071 |
|
| 4072 |
+ENV abc=ABC |
|
| 4073 |
+RUN [ "$abc" = "ABC" ] |
|
| 4074 |
+ENV def=${abc:-DEF}
|
|
| 4075 |
+RUN [ "$def" = "ABC" ] |
|
| 4076 |
+ENV def=${ccc:-DEF}
|
|
| 4077 |
+RUN [ "$def" = "DEF" ] |
|
| 4078 |
+ENV def=${ccc:-${def}xx}
|
|
| 4079 |
+RUN [ "$def" = "DEFxx" ] |
|
| 4080 |
+ENV def=${def:+ALT}
|
|
| 4081 |
+RUN [ "$def" = "ALT" ] |
|
| 4082 |
+ENV def=${def:+${abc}:}
|
|
| 4083 |
+RUN [ "$def" = "ABC:" ] |
|
| 4084 |
+ENV def=${ccc:-\$abc:}
|
|
| 4085 |
+RUN [ "$def" = '$abc:' ] |
|
| 4086 |
+ENV def=${ccc:-\${abc}:}
|
|
| 4087 |
+RUN [ "$def" = '${abc:}' ]
|
|
| 4088 |
+ENV mypath=${mypath:+$mypath:}/home
|
|
| 4089 |
+RUN [ "$mypath" = '/home' ] |
|
| 4090 |
+ENV mypath=${mypath:+$mypath:}/away
|
|
| 4091 |
+RUN [ "$mypath" = '/home:/away' ] |
|
| 4092 |
+ |
|
| 4072 | 4093 |
ENV e1=bar |
| 4073 | 4094 |
ENV e2=$e1 |
| 4074 | 4095 |
ENV e3=$e11 |