Windows: Builder case insensitive env
Signed-off-by: John Howard <jhoward@microsoft.com>
(cherry picked from commit 49f392ff6b
)
Signed-off-by: Victor Vieux <victorvieux@gmail.com>
This commit is contained in:
parent
0dd3ae8ed0
commit
68cfaf216d
6 changed files with 177 additions and 122 deletions
|
@ -71,14 +71,20 @@ func env(b *Builder, args []string, attributes map[string]bool, original string)
|
|||
if len(args[j]) == 0 {
|
||||
return errBlankCommandNames("ENV")
|
||||
}
|
||||
|
||||
newVar := args[j] + "=" + args[j+1] + ""
|
||||
commitStr += " " + newVar
|
||||
|
||||
gotOne := false
|
||||
for i, envVar := range b.runConfig.Env {
|
||||
envParts := strings.SplitN(envVar, "=", 2)
|
||||
if envParts[0] == args[j] {
|
||||
compareFrom := envParts[0]
|
||||
compareTo := args[j]
|
||||
if runtime.GOOS == "windows" {
|
||||
// Case insensitive environment variables on Windows
|
||||
compareFrom = strings.ToUpper(compareFrom)
|
||||
compareTo = strings.ToUpper(compareTo)
|
||||
}
|
||||
if compareFrom == compareTo {
|
||||
b.runConfig.Env[i] = newVar
|
||||
gotOne = true
|
||||
break
|
||||
|
|
|
@ -1,112 +1,116 @@
|
|||
hello | hello
|
||||
he'll'o | hello
|
||||
he'llo | hello
|
||||
he\'llo | he'llo
|
||||
he\\'llo | he\llo
|
||||
abc\tdef | abctdef
|
||||
"abc\tdef" | abc\tdef
|
||||
'abc\tdef' | abc\tdef
|
||||
hello\ | hello
|
||||
hello\\ | hello\
|
||||
"hello | hello
|
||||
"hello\" | hello"
|
||||
"hel'lo" | hel'lo
|
||||
'hello | hello
|
||||
'hello\' | hello\
|
||||
"''" | ''
|
||||
$. | $.
|
||||
$1 |
|
||||
he$1x | hex
|
||||
he$.x | he$.x
|
||||
he$pwd. | he.
|
||||
he$PWD | he/home
|
||||
he\$PWD | he$PWD
|
||||
he\\$PWD | he\/home
|
||||
he\${} | he${}
|
||||
he\${}xx | he${}xx
|
||||
he${} | he
|
||||
he${}xx | hexx
|
||||
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'
|
||||
"$PWD" | /home
|
||||
'$PWD' | $PWD
|
||||
'\$PWD' | \$PWD
|
||||
'"hello"' | "hello"
|
||||
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
|
||||
안녕하세요 | 안녕하세요
|
||||
안'녕'하세요 | 안녕하세요
|
||||
안'녕하세요 | 안녕하세요
|
||||
안녕\'하세요 | 안녕'하세요
|
||||
안\\'녕하세요 | 안\녕하세요
|
||||
안녕\t하세요 | 안녕t하세요
|
||||
"안녕\t하세요" | 안녕\t하세요
|
||||
'안녕\t하세요 | 안녕\t하세요
|
||||
안녕하세요\ | 안녕하세요
|
||||
안녕하세요\\ | 안녕하세요\
|
||||
"안녕하세요 | 안녕하세요
|
||||
"안녕하세요\" | 안녕하세요"
|
||||
"안녕'하세요" | 안녕'하세요
|
||||
'안녕하세요 | 안녕하세요
|
||||
'안녕하세요\' | 안녕하세요\
|
||||
안녕$1x | 안녕x
|
||||
안녕$.x | 안녕$.x
|
||||
안녕$pwd. | 안녕.
|
||||
안녕$PWD | 안녕/home
|
||||
안녕\$PWD | 안녕$PWD
|
||||
안녕\\$PWD | 안녕\/home
|
||||
안녕\${} | 안녕${}
|
||||
안녕\${}xx | 안녕${}xx
|
||||
안녕${} | 안녕
|
||||
안녕${}xx | 안녕xx
|
||||
안녕${hi} | 안녕
|
||||
안녕${hi}xx | 안녕xx
|
||||
안녕${PWD} | 안녕/home
|
||||
안녕${.} | error
|
||||
안녕${XXX:-000}xx | 안녕000xx
|
||||
안녕${PWD:-000}xx | 안녕/homexx
|
||||
안녕${XXX:-$PWD}xx | 안녕/homexx
|
||||
안녕${XXX:-${PWD:-yyy}}xx | 안녕/homexx
|
||||
안녕${XXX:-${YYY:-yyy}}xx | 안녕yyyxx
|
||||
안녕${XXX:YYY} | error
|
||||
안녕${XXX:+${PWD}}xx | 안녕xx
|
||||
안녕${PWD:+${XXX}}xx | 안녕xx
|
||||
안녕${PWD:+${SHELL}}xx | 안녕bashxx
|
||||
안녕${XXX:+000}xx | 안녕xx
|
||||
안녕${PWD:+000}xx | 안녕000xx
|
||||
'안녕${XX}' | 안녕${XX}
|
||||
"안녕${PWD}" | 안녕/home
|
||||
"안녕'$PWD'" | 안녕'/home'
|
||||
'"안녕"' | "안녕"
|
||||
안녕\$PWD | 안녕$PWD
|
||||
"안녕\$PWD" | 안녕$PWD
|
||||
'안녕\$PWD' | 안녕\$PWD
|
||||
안녕${PWD | error
|
||||
안녕${PWD:=000}xx | error
|
||||
안녕${PWD:+${PWD}:}xx | 안녕/home:xx
|
||||
안녕${XXX:-\$PWD:}xx | 안녕$PWD:xx
|
||||
안녕${XXX:-\${PWD}z}xx | 안녕${PWDz}xx
|
||||
$KOREAN | 한국어
|
||||
안녕$KOREAN | 안녕한국어
|
||||
A|hello | hello
|
||||
A|he'll'o | hello
|
||||
A|he'llo | hello
|
||||
A|he\'llo | he'llo
|
||||
A|he\\'llo | he\llo
|
||||
A|abc\tdef | abctdef
|
||||
A|"abc\tdef" | abc\tdef
|
||||
A|'abc\tdef' | abc\tdef
|
||||
A|hello\ | hello
|
||||
A|hello\\ | hello\
|
||||
A|"hello | hello
|
||||
A|"hello\" | hello"
|
||||
A|"hel'lo" | hel'lo
|
||||
A|'hello | hello
|
||||
A|'hello\' | hello\
|
||||
A|"''" | ''
|
||||
A|$. | $.
|
||||
A|$1 |
|
||||
A|he$1x | hex
|
||||
A|he$.x | he$.x
|
||||
# Next one is different on Windows as $pwd==$PWD
|
||||
U|he$pwd. | he.
|
||||
W|he$pwd. | he/home.
|
||||
A|he$PWD | he/home
|
||||
A|he\$PWD | he$PWD
|
||||
A|he\\$PWD | he\/home
|
||||
A|he\${} | he${}
|
||||
A|he\${}xx | he${}xx
|
||||
A|he${} | he
|
||||
A|he${}xx | hexx
|
||||
A|he${hi} | he
|
||||
A|he${hi}xx | hexx
|
||||
A|he${PWD} | he/home
|
||||
A|he${.} | error
|
||||
A|he${XXX:-000}xx | he000xx
|
||||
A|he${PWD:-000}xx | he/homexx
|
||||
A|he${XXX:-$PWD}xx | he/homexx
|
||||
A|he${XXX:-${PWD:-yyy}}xx | he/homexx
|
||||
A|he${XXX:-${YYY:-yyy}}xx | heyyyxx
|
||||
A|he${XXX:YYY} | error
|
||||
A|he${XXX:+${PWD}}xx | hexx
|
||||
A|he${PWD:+${XXX}}xx | hexx
|
||||
A|he${PWD:+${SHELL}}xx | hebashxx
|
||||
A|he${XXX:+000}xx | hexx
|
||||
A|he${PWD:+000}xx | he000xx
|
||||
A|'he${XX}' | he${XX}
|
||||
A|"he${PWD}" | he/home
|
||||
A|"he'$PWD'" | he'/home'
|
||||
A|"$PWD" | /home
|
||||
A|'$PWD' | $PWD
|
||||
A|'\$PWD' | \$PWD
|
||||
A|'"hello"' | "hello"
|
||||
A|he\$PWD | he$PWD
|
||||
A|"he\$PWD" | he$PWD
|
||||
A|'he\$PWD' | he\$PWD
|
||||
A|he${PWD | error
|
||||
A|he${PWD:=000}xx | error
|
||||
A|he${PWD:+${PWD}:}xx | he/home:xx
|
||||
A|he${XXX:-\$PWD:}xx | he$PWD:xx
|
||||
A|he${XXX:-\${PWD}z}xx | he${PWDz}xx
|
||||
A|안녕하세요 | 안녕하세요
|
||||
A|안'녕'하세요 | 안녕하세요
|
||||
A|안'녕하세요 | 안녕하세요
|
||||
A|안녕\'하세요 | 안녕'하세요
|
||||
A|안\\'녕하세요 | 안\녕하세요
|
||||
A|안녕\t하세요 | 안녕t하세요
|
||||
A|"안녕\t하세요" | 안녕\t하세요
|
||||
A|'안녕\t하세요 | 안녕\t하세요
|
||||
A|안녕하세요\ | 안녕하세요
|
||||
A|안녕하세요\\ | 안녕하세요\
|
||||
A|"안녕하세요 | 안녕하세요
|
||||
A|"안녕하세요\" | 안녕하세요"
|
||||
A|"안녕'하세요" | 안녕'하세요
|
||||
A|'안녕하세요 | 안녕하세요
|
||||
A|'안녕하세요\' | 안녕하세요\
|
||||
A|안녕$1x | 안녕x
|
||||
A|안녕$.x | 안녕$.x
|
||||
# Next one is different on Windows as $pwd==$PWD
|
||||
U|안녕$pwd. | 안녕.
|
||||
W|안녕$pwd. | 안녕/home.
|
||||
A|안녕$PWD | 안녕/home
|
||||
A|안녕\$PWD | 안녕$PWD
|
||||
A|안녕\\$PWD | 안녕\/home
|
||||
A|안녕\${} | 안녕${}
|
||||
A|안녕\${}xx | 안녕${}xx
|
||||
A|안녕${} | 안녕
|
||||
A|안녕${}xx | 안녕xx
|
||||
A|안녕${hi} | 안녕
|
||||
A|안녕${hi}xx | 안녕xx
|
||||
A|안녕${PWD} | 안녕/home
|
||||
A|안녕${.} | error
|
||||
A|안녕${XXX:-000}xx | 안녕000xx
|
||||
A|안녕${PWD:-000}xx | 안녕/homexx
|
||||
A|안녕${XXX:-$PWD}xx | 안녕/homexx
|
||||
A|안녕${XXX:-${PWD:-yyy}}xx | 안녕/homexx
|
||||
A|안녕${XXX:-${YYY:-yyy}}xx | 안녕yyyxx
|
||||
A|안녕${XXX:YYY} | error
|
||||
A|안녕${XXX:+${PWD}}xx | 안녕xx
|
||||
A|안녕${PWD:+${XXX}}xx | 안녕xx
|
||||
A|안녕${PWD:+${SHELL}}xx | 안녕bashxx
|
||||
A|안녕${XXX:+000}xx | 안녕xx
|
||||
A|안녕${PWD:+000}xx | 안녕000xx
|
||||
A|'안녕${XX}' | 안녕${XX}
|
||||
A|"안녕${PWD}" | 안녕/home
|
||||
A|"안녕'$PWD'" | 안녕'/home'
|
||||
A|'"안녕"' | "안녕"
|
||||
A|안녕\$PWD | 안녕$PWD
|
||||
A|"안녕\$PWD" | 안녕$PWD
|
||||
A|'안녕\$PWD' | 안녕\$PWD
|
||||
A|안녕${PWD | error
|
||||
A|안녕${PWD:=000}xx | error
|
||||
A|안녕${PWD:+${PWD}:}xx | 안녕/home:xx
|
||||
A|안녕${XXX:-\$PWD:}xx | 안녕$PWD:xx
|
||||
A|안녕${XXX:-\${PWD}z}xx | 안녕${PWDz}xx
|
||||
A|$KOREAN | 한국어
|
||||
A|안녕$KOREAN | 안녕한국어
|
||||
|
|
|
@ -8,6 +8,7 @@ package dockerfile
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
"text/scanner"
|
||||
"unicode"
|
||||
|
@ -298,9 +299,16 @@ func (sw *shellWord) processName() string {
|
|||
}
|
||||
|
||||
func (sw *shellWord) getEnv(name string) string {
|
||||
if runtime.GOOS == "windows" {
|
||||
// Case-insensitive environment variables on Windows
|
||||
name = strings.ToUpper(name)
|
||||
}
|
||||
for _, env := range sw.envs {
|
||||
i := strings.Index(env, "=")
|
||||
if i < 0 {
|
||||
if runtime.GOOS == "windows" {
|
||||
env = strings.ToUpper(env)
|
||||
}
|
||||
if name == env {
|
||||
// Should probably never get here, but just in case treat
|
||||
// it like "var" and "var=" are the same
|
||||
|
@ -308,7 +316,11 @@ func (sw *shellWord) getEnv(name string) string {
|
|||
}
|
||||
continue
|
||||
}
|
||||
if name != env[:i] {
|
||||
compareName := env[:i]
|
||||
if runtime.GOOS == "windows" {
|
||||
compareName = strings.ToUpper(compareName)
|
||||
}
|
||||
if name != compareName {
|
||||
continue
|
||||
}
|
||||
return env[i+1:]
|
||||
|
|
|
@ -3,12 +3,14 @@ package dockerfile
|
|||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestShellParser4EnvVars(t *testing.T) {
|
||||
fn := "envVarTest"
|
||||
lineCount := 0
|
||||
|
||||
file, err := os.Open(fn)
|
||||
if err != nil {
|
||||
|
@ -20,6 +22,7 @@ func TestShellParser4EnvVars(t *testing.T) {
|
|||
envs := []string{"PWD=/home", "SHELL=bash", "KOREAN=한국어"}
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
lineCount++
|
||||
|
||||
// Trim comments and blank lines
|
||||
i := strings.Index(line, "#")
|
||||
|
@ -33,21 +36,30 @@ func TestShellParser4EnvVars(t *testing.T) {
|
|||
}
|
||||
|
||||
words := strings.Split(line, "|")
|
||||
if len(words) != 2 {
|
||||
if len(words) != 3 {
|
||||
t.Fatalf("Error in '%s' - should be exactly one | in:%q", fn, line)
|
||||
}
|
||||
|
||||
words[0] = strings.TrimSpace(words[0])
|
||||
words[1] = strings.TrimSpace(words[1])
|
||||
words[2] = strings.TrimSpace(words[2])
|
||||
|
||||
newWord, err := ProcessWord(words[0], envs, '\\')
|
||||
|
||||
if err != nil {
|
||||
newWord = "error"
|
||||
// Key W=Windows; A=All; U=Unix
|
||||
if (words[0] != "W") && (words[0] != "A") && (words[0] != "U") {
|
||||
t.Fatalf("Invalid tag %s at line %d of %s. Must be W, A or U", words[0], lineCount, fn)
|
||||
}
|
||||
|
||||
if newWord != words[1] {
|
||||
t.Fatalf("Error. Src: %s Calc: %s Expected: %s", words[0], newWord, words[1])
|
||||
if ((words[0] == "W" || words[0] == "A") && runtime.GOOS == "windows") ||
|
||||
((words[0] == "U" || words[0] == "A") && runtime.GOOS != "windows") {
|
||||
newWord, err := ProcessWord(words[1], envs, '\\')
|
||||
|
||||
if err != nil {
|
||||
newWord = "error"
|
||||
}
|
||||
|
||||
if newWord != words[2] {
|
||||
t.Fatalf("Error. Src: %s Calc: %s Expected: %s at line %d", words[1], newWord, words[2], lineCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,11 @@ func merge(userConf, imageConf *containertypes.Config) error {
|
|||
imageEnvKey := strings.Split(imageEnv, "=")[0]
|
||||
for _, userEnv := range userConf.Env {
|
||||
userEnvKey := strings.Split(userEnv, "=")[0]
|
||||
if runtime.GOOS == "windows" {
|
||||
// Case insensitive environment variables on Windows
|
||||
imageEnvKey = strings.ToUpper(imageEnvKey)
|
||||
userEnvKey = strings.ToUpper(userEnvKey)
|
||||
}
|
||||
if imageEnvKey == userEnvKey {
|
||||
found = true
|
||||
break
|
||||
|
|
|
@ -7311,3 +7311,19 @@ RUN ["cat", "/foo/file"]
|
|||
c.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Case-insensitive environment variables on Windows
|
||||
func (s *DockerSuite) TestBuildWindowsEnvCaseInsensitive(c *check.C) {
|
||||
testRequires(c, DaemonIsWindows)
|
||||
name := "testbuildwindowsenvcaseinsensitive"
|
||||
if _, err := buildImage(name, `
|
||||
FROM `+WindowsBaseImage+`
|
||||
ENV FOO=bar foo=bar
|
||||
`, true); err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
res := inspectFieldJSON(c, name, "Config.Env")
|
||||
if res != `["foo=bar"]` { // Should not have FOO=bar in it - takes the last one processed. And only one entry as deduped.
|
||||
c.Fatalf("Case insensitive environment variables on Windows failed. Got %s", res)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue