diff --git a/integration/dockerfiles/Dockerfile_test_copy_root_multistage b/integration/dockerfiles/Dockerfile_test_copy_root_multistage new file mode 100644 index 0000000000..b97d041433 --- /dev/null +++ b/integration/dockerfiles/Dockerfile_test_copy_root_multistage @@ -0,0 +1,9 @@ +FROM debian:10.13 as base +COPY . . + +FROM scratch as second +ENV foopath context/foo +COPY --from=0 $foopath context/b* /foo/ + +FROM second as third +COPY --from=base / /new/foo diff --git a/pkg/executor/copy_multistage_test.go b/pkg/executor/copy_multistage_test.go index 450b3056f0..ce1caec125 100644 --- a/pkg/executor/copy_multistage_test.go +++ b/pkg/executor/copy_multistage_test.go @@ -82,6 +82,7 @@ COPY --from=first copied/bam.txt output/` testutil.CheckDeepEqual(t, 1, len(files)) testutil.CheckDeepEqual(t, files[0].Name(), "bam.txt") }) + t.Run("copy directory across multistage into a directory", func(t *testing.T) { testDir, fn := setupMultistageTests(t) defer fn() @@ -117,6 +118,40 @@ COPY --from=first copied another` //testutil.CheckDeepEqual(t, linkName, "bam.txt") }) + t.Run("copy root across multistage", func(t *testing.T) { + testDir, fn := setupMultistageTests(t) + defer fn() + dockerFile := ` +FROM scratch as first +COPY foo copied +ENV test test + +From scratch as second +COPY --from=first / output/` + ioutil.WriteFile(filepath.Join(testDir, "workspace", "Dockerfile"), []byte(dockerFile), 0755) + opts := &config.KanikoOptions{ + DockerfilePath: filepath.Join(testDir, "workspace", "Dockerfile"), + SrcContext: filepath.Join(testDir, "workspace"), + SnapshotMode: constants.SnapshotModeFull, + } + _, err := DoBuild(opts) + testutil.CheckNoError(t, err) + + filesUnderRoot, err := ioutil.ReadDir(filepath.Join(testDir, "output/")) + if err != nil { + t.Fatal(err) + } + testutil.CheckDeepEqual(t, 3, len(filesUnderRoot)) + + files, err := ioutil.ReadDir(filepath.Join(testDir, "output/workspace/foo")) + if err != nil { + t.Fatal(err) + } + testutil.CheckDeepEqual(t, 2, len(files)) + testutil.CheckDeepEqual(t, "bam.link", files[0].Name()) + testutil.CheckDeepEqual(t, "bam.txt", files[1].Name()) + }) + } func setupMultistageTests(t *testing.T) (string, func()) { diff --git a/pkg/util/fs_util.go b/pkg/util/fs_util.go index 8818207a60..1058e0d182 100644 --- a/pkg/util/fs_util.go +++ b/pkg/util/fs_util.go @@ -81,6 +81,13 @@ var ignorelist = append([]IgnoreListEntry{}, defaultIgnoreList...) var volumes = []string{} +// skipKanikoDir opts to skip the '/kaniko' dir for otiai10.copy which should be ignored in root +var skipKanikoDir = otiai10Cpy.Options{ + Skip: func(info os.FileInfo, src, dest string) (bool, error) { + return strings.HasSuffix(src, "/kaniko"), nil + }, +} + type FileContext struct { Root string ExcludedFiles []string @@ -956,7 +963,7 @@ func CopyFileOrSymlink(src string, destDir string, root string) error { } return os.Symlink(link, destFile) } - if err := otiai10Cpy.Copy(src, destFile); err != nil { + if err := otiai10Cpy.Copy(src, destFile, skipKanikoDir); err != nil { return errors.Wrap(err, "copying file") } if err := CopyOwnership(src, destDir, root); err != nil {