Преглед на файлове

Merge pull request #11149 from duglin/8667-AdvancedVars

Add support for advanced ${} uses
Tibor Vass преди 10 години
родител
ревизия
9707286a5c
променени са 4 файла, в които са добавени 97 реда и са изтрити 5 реда
  1. 34 1
      builder/shell_parser.go
  2. 15 0
      builder/words
  3. 16 4
      docs/sources/reference/builder.md
  4. 32 0
      integration-cli/docker_cli_build_test.go

+ 34 - 1
builder/shell_parser.go

@@ -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()

+ 15 - 0
builder/words

@@ -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

+ 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
 > 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
-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
 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

+ 32 - 0
integration-cli/docker_cli_build_test.go

@@ -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