/vendor/github.com/docker/docker/builder/dockerfile/dispatchers_windows.go

https://gitlab.com/unofficial-mirrors/openshift-origin · Go · 120 lines · 73 code · 11 blank · 36 comment · 26 complexity · b87edf7c466c3597cc1d932e42f625ce MD5 · raw file

  1. package dockerfile
  2. import (
  3. "errors"
  4. "fmt"
  5. "os"
  6. "path"
  7. "path/filepath"
  8. "regexp"
  9. "strings"
  10. "github.com/docker/docker/pkg/system"
  11. )
  12. var pattern = regexp.MustCompile(`^[a-zA-Z]:\.$`)
  13. // normalizeWorkdir normalizes a user requested working directory in a
  14. // platform semantically consistent way.
  15. func normalizeWorkdir(platform string, current string, requested string) (string, error) {
  16. if platform == "" {
  17. platform = "windows"
  18. }
  19. if platform == "windows" {
  20. return normalizeWorkdirWindows(current, requested)
  21. }
  22. return normalizeWorkdirUnix(current, requested)
  23. }
  24. // normalizeWorkdirUnix normalizes a user requested working directory in a
  25. // platform semantically consistent way.
  26. func normalizeWorkdirUnix(current string, requested string) (string, error) {
  27. if requested == "" {
  28. return "", errors.New("cannot normalize nothing")
  29. }
  30. current = strings.Replace(current, string(os.PathSeparator), "/", -1)
  31. requested = strings.Replace(requested, string(os.PathSeparator), "/", -1)
  32. if !path.IsAbs(requested) {
  33. return path.Join(`/`, current, requested), nil
  34. }
  35. return requested, nil
  36. }
  37. // normalizeWorkdirWindows normalizes a user requested working directory in a
  38. // platform semantically consistent way.
  39. func normalizeWorkdirWindows(current string, requested string) (string, error) {
  40. if requested == "" {
  41. return "", errors.New("cannot normalize nothing")
  42. }
  43. // `filepath.Clean` will replace "" with "." so skip in that case
  44. if current != "" {
  45. current = filepath.Clean(current)
  46. }
  47. if requested != "" {
  48. requested = filepath.Clean(requested)
  49. }
  50. // If either current or requested in Windows is:
  51. // C:
  52. // C:.
  53. // then an error will be thrown as the definition for the above
  54. // refers to `current directory on drive C:`
  55. // Since filepath.Clean() will automatically normalize the above
  56. // to `C:.`, we only need to check the last format
  57. if pattern.MatchString(current) {
  58. return "", fmt.Errorf("%s is not a directory. If you are specifying a drive letter, please add a trailing '\\'", current)
  59. }
  60. if pattern.MatchString(requested) {
  61. return "", fmt.Errorf("%s is not a directory. If you are specifying a drive letter, please add a trailing '\\'", requested)
  62. }
  63. // Target semantics is C:\somefolder, specifically in the format:
  64. // UPPERCASEDriveLetter-Colon-Backslash-FolderName. We are already
  65. // guaranteed that `current`, if set, is consistent. This allows us to
  66. // cope correctly with any of the following in a Dockerfile:
  67. // WORKDIR a --> C:\a
  68. // WORKDIR c:\\foo --> C:\foo
  69. // WORKDIR \\foo --> C:\foo
  70. // WORKDIR /foo --> C:\foo
  71. // WORKDIR c:\\foo \ WORKDIR bar --> C:\foo --> C:\foo\bar
  72. // WORKDIR C:/foo \ WORKDIR bar --> C:\foo --> C:\foo\bar
  73. // WORKDIR C:/foo \ WORKDIR \\bar --> C:\foo --> C:\bar
  74. // WORKDIR /foo \ WORKDIR c:/bar --> C:\foo --> C:\bar
  75. if len(current) == 0 || system.IsAbs(requested) {
  76. if (requested[0] == os.PathSeparator) ||
  77. (len(requested) > 1 && string(requested[1]) != ":") ||
  78. (len(requested) == 1) {
  79. requested = filepath.Join(`C:\`, requested)
  80. }
  81. } else {
  82. requested = filepath.Join(current, requested)
  83. }
  84. // Upper-case drive letter
  85. return (strings.ToUpper(string(requested[0])) + requested[1:]), nil
  86. }
  87. func errNotJSON(command, original string) error {
  88. // For Windows users, give a hint if it looks like it might contain
  89. // a path which hasn't been escaped such as ["c:\windows\system32\prog.exe", "-param"],
  90. // as JSON must be escaped. Unfortunate...
  91. //
  92. // Specifically looking for quote-driveletter-colon-backslash, there's no
  93. // double backslash and a [] pair. No, this is not perfect, but it doesn't
  94. // have to be. It's simply a hint to make life a little easier.
  95. extra := ""
  96. original = filepath.FromSlash(strings.ToLower(strings.Replace(strings.ToLower(original), strings.ToLower(command)+" ", "", -1)))
  97. if len(regexp.MustCompile(`"[a-z]:\\.*`).FindStringSubmatch(original)) > 0 &&
  98. !strings.Contains(original, `\\`) &&
  99. strings.Contains(original, "[") &&
  100. strings.Contains(original, "]") {
  101. extra = fmt.Sprintf(`. It looks like '%s' includes a file path without an escaped back-slash. JSON requires back-slashes to be escaped such as ["c:\\path\\to\\file.exe", "/parameter"]`, original)
  102. }
  103. return fmt.Errorf("%s requires the arguments to be in JSON form%s", command, extra)
  104. }
  105. // equalEnvKeys compare two strings and returns true if they are equal. On
  106. // Windows this comparison is case insensitive.
  107. func equalEnvKeys(from, to string) bool {
  108. return strings.ToUpper(from) == strings.ToUpper(to)
  109. }