Merge pull request #315 from thaJeztah/19.03_backport_fix_copy_on_windows

[19.03 backport] Builder: fix "COPY --from" to non-existing directory on Windows [ENGCORE-935]
This commit is contained in:
Andrew Hsu 2019-08-08 10:27:44 -07:00 committed by GitHub
commit c7139be62b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 2 deletions

View file

@ -556,13 +556,15 @@ func copyFile(archiver Archiver, source, dest *copyEndpoint, identity *idtools.I
return errors.Wrapf(err, "failed to create new directory")
}
} else {
// Normal containers
if identity == nil {
if err := os.MkdirAll(filepath.Dir(dest.path), 0755); err != nil {
// Use system.MkdirAll here, which is a custom version of os.MkdirAll
// modified for use on Windows to handle volume GUID paths (\\?\{dae8d3ac-b9a1-11e9-88eb-e8554b2ba1db}\path\)
if err := system.MkdirAll(filepath.Dir(dest.path), 0755, ""); err != nil {
return err
}
} else {
if err := idtools.MkdirAllAndChownNew(filepath.Dir(dest.path), 0755, *identity); err != nil {
// Normal containers
return errors.Wrapf(err, "failed to create new directory")
}
}

View file

@ -343,6 +343,7 @@ Function Run-IntegrationTests() {
Write-Host "Running $($PWD.Path)"
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = "$($PWD.Path)\test.exe"
$pinfo.WorkingDirectory = "$($PWD.Path)"
$pinfo.RedirectStandardError = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = $env:INTEGRATION_TESTFLAGS

View file

@ -135,6 +135,58 @@ func buildContainerIdsFilter(buildOutput io.Reader) (filters.Args, error) {
}
}
// TestBuildMultiStageCopy verifies that copying between stages works correctly.
//
// Regression test for docker/for-win#4349, ENGCORE-935, where creating the target
// directory failed on Windows, because `os.MkdirAll()` was called with a volume
// GUID path (\\?\Volume{dae8d3ac-b9a1-11e9-88eb-e8554b2ba1db}\newdir\hello}),
// which currently isn't supported by Golang.
func TestBuildMultiStageCopy(t *testing.T) {
ctx := context.Background()
dockerfile, err := ioutil.ReadFile("testdata/Dockerfile." + t.Name())
assert.NilError(t, err)
source := fakecontext.New(t, "", fakecontext.WithDockerfile(string(dockerfile)))
defer source.Close()
apiclient := testEnv.APIClient()
for _, target := range []string{"copy_to_root", "copy_to_newdir", "copy_to_newdir_nested", "copy_to_existingdir", "copy_to_newsubdir"} {
t.Run(target, func(t *testing.T) {
imgName := strings.ToLower(t.Name())
resp, err := apiclient.ImageBuild(
ctx,
source.AsTarReader(t),
types.ImageBuildOptions{
Remove: true,
ForceRemove: true,
Target: target,
Tags: []string{imgName},
},
)
assert.NilError(t, err)
out := bytes.NewBuffer(nil)
assert.NilError(t, err)
_, err = io.Copy(out, resp.Body)
_ = resp.Body.Close()
if err != nil {
t.Log(out)
}
assert.NilError(t, err)
// verify the image was successfully built
_, _, err = apiclient.ImageInspectWithRaw(ctx, imgName)
if err != nil {
t.Log(out)
}
assert.NilError(t, err)
})
}
}
func TestBuildMultiStageParentConfig(t *testing.T) {
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.35"), "broken in earlier versions")
skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME")

View file

@ -0,0 +1,20 @@
FROM busybox AS base
RUN mkdir existingdir
FROM base AS source
RUN echo "Hello World" > /hello
FROM base AS copy_to_root
COPY --from=source /hello /hello
FROM base AS copy_to_newdir
COPY --from=source /hello /newdir/hello
FROM base AS copy_to_newdir_nested
COPY --from=source /hello /newdir/newsubdir/hello
FROM base AS copy_to_existingdir
COPY --from=source /hello /existingdir/hello
FROM base AS copy_to_newsubdir
COPY --from=source /hello /existingdir/newsubdir/hello