Browse Source

Merge pull request #11149 from duglin/8667-AdvancedVars

Add support for advanced ${} uses
Tibor Vass 10 năm trước cách đây
mục cha
commit
9707286a5c

+ 34 - 1
builder/shell_parser.go

@@ -157,7 +157,40 @@ func (sw *shellWord) processDollar() (string, error) {
 			sw.next()
 			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
 	name := sw.processName()

+ 15 - 0
builder/words

@@ -30,6 +30,17 @@ he${hi}                  |     he
 he${hi}xx                |     hexx
 he${PWD}                 |     he/home
 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${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                  |     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

+ 16 - 4
docs/sources/reference/builder.md

@@ -113,18 +113,30 @@ images.
 > replacement at the time. After 1.3 this behavior will be preserved and
 > canonical.
 
-Environment variables (declared with [the `ENV` statement](#env)) can also be used in
-certain instructions as variables to be interpreted by the `Dockerfile`. Escapes
-are also handled for including variable-like syntax into a statement literally.
+Environment variables (declared with [the `ENV` statement](#env)) can also be
+used in certain instructions as variables to be interpreted by the
+`Dockerfile`. Escapes are also handled for including variable-like syntax
+into a statement literally.
 
 Environment variables are notated in the `Dockerfile` either with
 `$variable_name` or `${variable_name}`. They are treated equivalently and the
 brace syntax is typically used to address issues with variable names with no
 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}`,
 for example, will translate to `$foo` and `${foo}` literals respectively.
- 
+
 Example (parsed representation is displayed after the `#`):
 
     FROM busybox

+ 32 - 0
integration-cli/docker_cli_build_test.go

@@ -214,13 +214,19 @@ func TestBuildEnvironmentReplacementAddCopy(t *testing.T) {
   ENV baz foo
   ENV quux bar
   ENV dot .
+  ENV fee fff
+  ENV gee ggg
 
   ADD ${baz} ${dot}
   COPY ${quux} ${dot}
+  ADD ${zzz:-${fee}} ${dot}
+  COPY ${zzz:-${gee}} ${dot}
   `,
 		map[string]string{
 			"foo": "test1",
 			"bar": "test2",
+			"fff": "test3",
+			"ggg": "test4",
 		})
 
 	if err != nil {
@@ -286,6 +292,11 @@ func TestBuildEnvironmentReplacementEnv(t *testing.T) {
 			if parts[1] != "zzz" {
 				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\"
 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    e2=$e1
 ENV    e3=$e11