github.com/lazyboychen7/engine@v17.12.1-ce-rc2+incompatible/builder/dockerfile/dispatchers_windows.go (about) 1 package dockerfile 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "path" 8 "path/filepath" 9 "regexp" 10 "strings" 11 12 "github.com/docker/docker/pkg/system" 13 ) 14 15 var pattern = regexp.MustCompile(`^[a-zA-Z]:\.$`) 16 17 // normalizeWorkdir normalizes a user requested working directory in a 18 // platform semantically consistent way. 19 func normalizeWorkdir(platform string, current string, requested string) (string, error) { 20 if platform == "" { 21 platform = "windows" 22 } 23 if platform == "windows" { 24 return normalizeWorkdirWindows(current, requested) 25 } 26 return normalizeWorkdirUnix(current, requested) 27 } 28 29 // normalizeWorkdirUnix normalizes a user requested working directory in a 30 // platform semantically consistent way. 31 func normalizeWorkdirUnix(current string, requested string) (string, error) { 32 if requested == "" { 33 return "", errors.New("cannot normalize nothing") 34 } 35 current = strings.Replace(current, string(os.PathSeparator), "/", -1) 36 requested = strings.Replace(requested, string(os.PathSeparator), "/", -1) 37 if !path.IsAbs(requested) { 38 return path.Join(`/`, current, requested), nil 39 } 40 return requested, nil 41 } 42 43 // normalizeWorkdirWindows normalizes a user requested working directory in a 44 // platform semantically consistent way. 45 func normalizeWorkdirWindows(current string, requested string) (string, error) { 46 if requested == "" { 47 return "", errors.New("cannot normalize nothing") 48 } 49 50 // `filepath.Clean` will replace "" with "." so skip in that case 51 if current != "" { 52 current = filepath.Clean(current) 53 } 54 if requested != "" { 55 requested = filepath.Clean(requested) 56 } 57 58 // If either current or requested in Windows is: 59 // C: 60 // C:. 61 // then an error will be thrown as the definition for the above 62 // refers to `current directory on drive C:` 63 // Since filepath.Clean() will automatically normalize the above 64 // to `C:.`, we only need to check the last format 65 if pattern.MatchString(current) { 66 return "", fmt.Errorf("%s is not a directory. If you are specifying a drive letter, please add a trailing '\\'", current) 67 } 68 if pattern.MatchString(requested) { 69 return "", fmt.Errorf("%s is not a directory. If you are specifying a drive letter, please add a trailing '\\'", requested) 70 } 71 72 // Target semantics is C:\somefolder, specifically in the format: 73 // UPPERCASEDriveLetter-Colon-Backslash-FolderName. We are already 74 // guaranteed that `current`, if set, is consistent. This allows us to 75 // cope correctly with any of the following in a Dockerfile: 76 // WORKDIR a --> C:\a 77 // WORKDIR c:\\foo --> C:\foo 78 // WORKDIR \\foo --> C:\foo 79 // WORKDIR /foo --> C:\foo 80 // WORKDIR c:\\foo \ WORKDIR bar --> C:\foo --> C:\foo\bar 81 // WORKDIR C:/foo \ WORKDIR bar --> C:\foo --> C:\foo\bar 82 // WORKDIR C:/foo \ WORKDIR \\bar --> C:\foo --> C:\bar 83 // WORKDIR /foo \ WORKDIR c:/bar --> C:\foo --> C:\bar 84 if len(current) == 0 || system.IsAbs(requested) { 85 if (requested[0] == os.PathSeparator) || 86 (len(requested) > 1 && string(requested[1]) != ":") || 87 (len(requested) == 1) { 88 requested = filepath.Join(`C:\`, requested) 89 } 90 } else { 91 requested = filepath.Join(current, requested) 92 } 93 // Upper-case drive letter 94 return (strings.ToUpper(string(requested[0])) + requested[1:]), nil 95 } 96 97 // equalEnvKeys compare two strings and returns true if they are equal. On 98 // Windows this comparison is case insensitive. 99 func equalEnvKeys(from, to string) bool { 100 return strings.ToUpper(from) == strings.ToUpper(to) 101 }