github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/builder/dockerfile/dispatchers_windows.go (about)

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