Skip to content

Commit c75eeb4

Browse files
John Howardvieux
authored andcommitted
COPY file . after WORKDIR (now always created)
Signed-off-by: John Howard <jhoward@microsoft.com> (cherry picked from commit 286ab6d) Signed-off-by: Victor Vieux <victorvieux@gmail.com>
1 parent 10d2d8a commit c75eeb4

File tree

5 files changed

+76
-9
lines changed

5 files changed

+76
-9
lines changed

builder/builder.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ type Backend interface {
129129
ContainerWait(containerID string, timeout time.Duration) (int, error)
130130
// ContainerUpdateCmdOnBuild updates container.Path and container.Args
131131
ContainerUpdateCmdOnBuild(containerID string, cmd []string) error
132+
// ContainerCreateWorkdir creates the workdir (currently only used on Windows)
133+
ContainerCreateWorkdir(containerID string) error
132134

133135
// ContainerCopy copies/extracts a source FileInfo to a destination path inside a container
134136
// specified by a container object.

builder/dockerfile/dispatchers.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818

1919
"github.com/Sirupsen/logrus"
2020
"github.com/docker/docker/api"
21+
"github.com/docker/docker/api/types"
2122
"github.com/docker/docker/api/types/container"
2223
"github.com/docker/docker/api/types/strslice"
2324
"github.com/docker/docker/builder"
@@ -279,12 +280,26 @@ func workdir(b *Builder, args []string, attributes map[string]bool, original str
279280
return err
280281
}
281282

282-
// NOTE: You won't find the "mkdir" for the directory in here. Rather we
283-
// just set the value in the image's runConfig.WorkingDir property
284-
// and container.SetupWorkingDirectory() will create it automatically
285-
// for us the next time the image is used to create a container.
283+
// For performance reasons, we explicitly do a create/mkdir now
284+
// This avoids having an unnecessary expensive mount/unmount calls
285+
// (on Windows in particular) during each container create.
286+
// Prior to 1.13, the mkdir was deferred and not executed at this step.
287+
if b.disableCommit {
288+
// Don't call back into the daemon if we're going through docker commit --change "WORKDIR /foo".
289+
// We've already updated the runConfig and that's enough.
290+
return nil
291+
}
292+
b.runConfig.Image = b.image
293+
container, err := b.docker.ContainerCreate(types.ContainerCreateConfig{Config: b.runConfig}, true)
294+
if err != nil {
295+
return err
296+
}
297+
b.tmpContainers[container.ID] = struct{}{}
298+
if err := b.docker.ContainerCreateWorkdir(container.ID); err != nil {
299+
return err
300+
}
286301

287-
return b.commit("", b.runConfig.Cmd, fmt.Sprintf("WORKDIR %v", b.runConfig.WorkingDir))
302+
return b.commit(container.ID, b.runConfig.Cmd, "WORKDIR "+b.runConfig.WorkingDir)
288303
}
289304

290305
// RUN some command yo

daemon/workdir.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package daemon
2+
3+
// ContainerCreateWorkdir creates the working directory. This is solves the
4+
// issue arising from https://github.com/docker/docker/issues/27545,
5+
// which was initially fixed by https://github.com/docker/docker/pull/27884. But that fix
6+
// was too expensive in terms of performance on Windows. Instead,
7+
// https://github.com/docker/docker/pull/28514 introduces this new functionality
8+
// where the builder calls into the backend here to create the working directory.
9+
func (daemon *Daemon) ContainerCreateWorkdir(cID string) error {
10+
container, err := daemon.GetContainer(cID)
11+
if err != nil {
12+
return err
13+
}
14+
err = daemon.Mount(container)
15+
if err != nil {
16+
return err
17+
}
18+
defer daemon.Unmount(container)
19+
rootUID, rootGID := daemon.GetRemappedUIDGID()
20+
return container.SetupWorkingDirectory(rootUID, rootGID)
21+
}

integration-cli/docker_cli_build_test.go

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1878,8 +1878,8 @@ func (s *DockerSuite) TestBuildWindowsAddCopyPathProcessing(c *check.C) {
18781878
WORKDIR /wc2
18791879
ADD wc2 c:/wc2
18801880
WORKDIR c:/
1881-
RUN sh -c "[ $(cat c:/wc1) = 'hellowc1' ]"
1882-
RUN sh -c "[ $(cat c:/wc2) = 'worldwc2' ]"
1881+
RUN sh -c "[ $(cat c:/wc1/wc1) = 'hellowc1' ]"
1882+
RUN sh -c "[ $(cat c:/wc2/wc2) = 'worldwc2' ]"
18831883
18841884
# Trailing slash on COPY/ADD, Windows-style path.
18851885
WORKDIR /wd1
@@ -7283,3 +7283,31 @@ func (s *DockerSuite) TestBuildWindowsUser(c *check.C) {
72837283
}
72847284
c.Assert(strings.ToLower(out), checker.Contains, "username=user")
72857285
}
7286+
7287+
// Verifies if COPY file . when WORKDIR is set to a non-existing directory,
7288+
// the directory is created and the file is copied into the directory,
7289+
// as opposed to the file being copied as a file with the name of the
7290+
// directory. Fix for 27545 (found on Windows, but regression good for Linux too).
7291+
// Note 27545 was reverted in 28505, but a new fix was added subsequently in 28514.
7292+
func (s *DockerSuite) TestBuildCopyFileDotWithWorkdir(c *check.C) {
7293+
name := "testbuildcopyfiledotwithworkdir"
7294+
ctx, err := fakeContext(`FROM busybox
7295+
WORKDIR /foo
7296+
COPY file .
7297+
RUN ["cat", "/foo/file"]
7298+
`,
7299+
map[string]string{})
7300+
7301+
if err != nil {
7302+
c.Fatal(err)
7303+
}
7304+
defer ctx.Close()
7305+
7306+
if err := ctx.Add("file", "content"); err != nil {
7307+
c.Fatal(err)
7308+
}
7309+
7310+
if _, err = buildImageFromContext(name, ctx, true); err != nil {
7311+
c.Fatal(err)
7312+
}
7313+
}

integration-cli/docker_cli_commit_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ func (s *DockerSuite) TestCommitWithHostBindMount(c *check.C) {
104104
}
105105

106106
func (s *DockerSuite) TestCommitChange(c *check.C) {
107-
testRequires(c, DaemonIsLinux)
108107
dockerCmd(c, "run", "--name", "test", "busybox", "true")
109108

110109
imageID, _ := dockerCmd(c, "commit",
@@ -122,12 +121,14 @@ func (s *DockerSuite) TestCommitChange(c *check.C) {
122121
"test", "test-commit")
123122
imageID = strings.TrimSpace(imageID)
124123

124+
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
125+
prefix = strings.ToUpper(prefix) // Force C: as that's how WORKDIR is normalised on Windows
125126
expected := map[string]string{
126127
"Config.ExposedPorts": "map[8080/tcp:{}]",
127128
"Config.Env": "[DEBUG=true test=1 PATH=/foo]",
128129
"Config.Labels": "map[foo:bar]",
129130
"Config.Cmd": "[/bin/sh]",
130-
"Config.WorkingDir": "/opt",
131+
"Config.WorkingDir": prefix + slash + "opt",
131132
"Config.Entrypoint": "[/bin/sh]",
132133
"Config.User": "testuser",
133134
"Config.Volumes": "map[/var/lib/docker:{}]",

0 commit comments

Comments
 (0)