2016-05-02 18:33:59 -07:00
package dockerfile
import (
"fmt"
"os"
"path/filepath"
2016-05-03 13:56:59 -07:00
"regexp"
2016-05-02 18:33:59 -07:00
"strings"
"github.com/docker/docker/pkg/system"
)
// normaliseWorkdir normalises a user requested working directory in a
// platform sematically consistent way.
func normaliseWorkdir ( current string , requested string ) ( string , error ) {
if requested == "" {
return "" , fmt . Errorf ( "cannot normalise nothing" )
}
current = filepath . FromSlash ( current )
requested = filepath . FromSlash ( requested )
// Target semantics is C:\somefolder, specifically in the format:
// UPPERCASEDriveLetter-Colon-Backslash-FolderName. We are already
// guaranteed that `current`, if set, is consistent. This allows us to
// cope correctly with any of the following in a Dockerfile:
// WORKDIR a --> C:\a
// WORKDIR c:\\foo --> C:\foo
// WORKDIR \\foo --> C:\foo
// WORKDIR /foo --> C:\foo
// WORKDIR c:\\foo \ WORKDIR bar --> C:\foo --> C:\foo\bar
// WORKDIR C:/foo \ WORKDIR bar --> C:\foo --> C:\foo\bar
// WORKDIR C:/foo \ WORKDIR \\bar --> C:\foo --> C:\bar
// WORKDIR /foo \ WORKDIR c:/bar --> C:\foo --> C:\bar
if len ( current ) == 0 || system . IsAbs ( requested ) {
if ( requested [ 0 ] == os . PathSeparator ) ||
( len ( requested ) > 1 && string ( requested [ 1 ] ) != ":" ) ||
( len ( requested ) == 1 ) {
requested = filepath . Join ( ` C:\ ` , requested )
}
} else {
requested = filepath . Join ( current , requested )
}
// Upper-case drive letter
return ( strings . ToUpper ( string ( requested [ 0 ] ) ) + requested [ 1 : ] ) , nil
}
2016-05-03 13:56:59 -07:00
func errNotJSON ( command , original string ) error {
// For Windows users, give a hint if it looks like it might contain
// a path which hasn't been escaped such as ["c:\windows\system32\prog.exe", "-param"],
// as JSON must be escaped. Unfortunate...
//
// Specifically looking for quote-driveletter-colon-backslash, there's no
// double backslash and a [] pair. No, this is not perfect, but it doesn't
// have to be. It's simply a hint to make life a little easier.
extra := ""
original = filepath . FromSlash ( strings . ToLower ( strings . Replace ( strings . ToLower ( original ) , strings . ToLower ( command ) + " " , "" , - 1 ) ) )
if len ( regexp . MustCompile ( ` "[a-z]:\\.* ` ) . FindStringSubmatch ( original ) ) > 0 &&
! strings . Contains ( original , ` \\ ` ) &&
strings . Contains ( original , "[" ) &&
strings . Contains ( original , "]" ) {
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 )
}
return fmt . Errorf ( "%s requires the arguments to be in JSON form%s" , command , extra )
}