Переглянути джерело

Merge pull request #19985 from Microsoft/CombineSetupWorkingDir

Combine SetupWorkingDirectory for Linux and Windows
David Calavera 9 роки тому
батько
коміт
d6870238e3

+ 27 - 1
container/container.go

@@ -22,6 +22,7 @@ import (
 	"github.com/docker/docker/pkg/promise"
 	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/docker/pkg/symlink"
+	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/volume"
 	containertypes "github.com/docker/engine-api/types/container"
@@ -183,6 +184,30 @@ func (container *Container) WriteHostConfig() error {
 	return json.NewEncoder(f).Encode(&container.HostConfig)
 }
 
+// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir
+func (container *Container) SetupWorkingDirectory() error {
+	if container.Config.WorkingDir == "" {
+		return nil
+	}
+	container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir)
+
+	pth, err := container.GetResourcePath(container.Config.WorkingDir)
+	if err != nil {
+		return err
+	}
+
+	if err := system.MkdirAll(pth, 0755); err != nil {
+		pthInfo, err2 := os.Stat(pth)
+		if err2 == nil && pthInfo != nil && !pthInfo.IsDir() {
+			return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir)
+		}
+
+		return err
+	}
+
+	return nil
+}
+
 // GetResourcePath evaluates `path` in the scope of the container's BaseFS, with proper path
 // sanitisation. Symlinks are all scoped to the BaseFS of the container, as
 // though the container's BaseFS was `/`.
@@ -199,7 +224,8 @@ func (container *Container) WriteHostConfig() error {
 func (container *Container) GetResourcePath(path string) (string, error) {
 	// IMPORTANT - These are paths on the OS where the daemon is running, hence
 	// any filepath operations must be done in an OS agnostic way.
-	cleanPath := filepath.Join(string(os.PathSeparator), path)
+
+	cleanPath := cleanResourcePath(path)
 	r, e := symlink.FollowSymlinkInScope(filepath.Join(container.BaseFS, cleanPath), container.BaseFS)
 	return r, e
 }

+ 5 - 28
container/container_unix.go

@@ -398,34 +398,6 @@ func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epC
 	return createOptions, nil
 }
 
-// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir
-func (container *Container) SetupWorkingDirectory() error {
-	if container.Config.WorkingDir == "" {
-		return nil
-	}
-	container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir)
-
-	pth, err := container.GetResourcePath(container.Config.WorkingDir)
-	if err != nil {
-		return err
-	}
-
-	pthInfo, err := os.Stat(pth)
-	if err != nil {
-		if !os.IsNotExist(err) {
-			return err
-		}
-
-		if err := system.MkdirAll(pth, 0755); err != nil {
-			return err
-		}
-	}
-	if pthInfo != nil && !pthInfo.IsDir() {
-		return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir)
-	}
-	return nil
-}
-
 // appendNetworkMounts appends any network mounts to the array of mount points passed in
 func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) {
 	for _, mnt := range container.NetworkMounts() {
@@ -755,3 +727,8 @@ func (container *Container) TmpfsMounts() []execdriver.Mount {
 	}
 	return mounts
 }
+
+// cleanResourcePath cleans a resource path and prepares to combine with mnt path
+func cleanResourcePath(path string) string {
+	return filepath.Join(string(os.PathSeparator), path)
+}

+ 15 - 6
container/container_windows.go

@@ -3,6 +3,9 @@
 package container
 
 import (
+	"os"
+	"path/filepath"
+
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/volume"
 	"github.com/docker/engine-api/types/container"
@@ -22,12 +25,6 @@ func (container *Container) CreateDaemonEnvironment(linkedEnv []string) []string
 	return container.Config.Env
 }
 
-// SetupWorkingDirectory initializes the container working directory.
-// This is a NOOP In windows.
-func (container *Container) SetupWorkingDirectory() error {
-	return nil
-}
-
 // UnmountIpcMounts unmount Ipc related mounts.
 // This is a NOOP on windows.
 func (container *Container) UnmountIpcMounts(unmount func(pth string) error) {
@@ -59,3 +56,15 @@ func (container *Container) UpdateContainer(hostConfig *container.HostConfig) er
 func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) {
 	return volumeMounts, nil
 }
+
+// cleanResourcePath cleans a resource path by removing C:\ syntax, and prepares
+// to combine with a volume path
+func cleanResourcePath(path string) string {
+	if len(path) >= 2 {
+		c := path[0]
+		if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
+			path = path[2:]
+		}
+	}
+	return filepath.Join(string(os.PathSeparator), path)
+}

+ 17 - 0
integration-cli/docker_cli_build_test.go

@@ -6484,3 +6484,20 @@ func (s *DockerSuite) TestBuildFailsGitNotCallable(c *check.C) {
 	c.Assert(err, checker.NotNil)
 	c.Assert(out, checker.Contains, "unable to prepare context: unable to find 'git': ")
 }
+
+// TestBuildWorkdirWindowsPath tests that a Windows style path works as a workdir
+func (s *DockerSuite) TestBuildWorkdirWindowsPath(c *check.C) {
+	testRequires(c, DaemonIsWindows)
+	name := "testbuildworkdirwindowspath"
+
+	_, err := buildImage(name, `
+	FROM windowsservercore
+	RUN mkdir C:\\work
+	WORKDIR C:\\work
+	RUN if "%CD%" NEQ "C:\work" exit -1
+	`, true)
+
+	if err != nil {
+		c.Fatal(err)
+	}
+}

+ 1 - 1
integration-cli/docker_cli_run_test.go

@@ -1723,7 +1723,7 @@ func (s *DockerSuite) TestRunWorkdirExistsAndIsFile(c *check.C) {
 	expected := "Cannot mkdir: /bin/cat is not a directory"
 	if daemonPlatform == "windows" {
 		existingFile = `\windows\system32\ntdll.dll`
-		expected = "The directory name is invalid"
+		expected = `Cannot mkdir: \windows\system32\ntdll.dll is not a directory.`
 	}
 
 	out, exitCode, err := dockerCmdWithError("run", "-w", existingFile, "busybox")