diff --git a/pkg/commands/copy.go b/pkg/commands/copy.go index c4102ef81..1ced9e40e 100644 --- a/pkg/commands/copy.go +++ b/pkg/commands/copy.go @@ -82,14 +82,13 @@ func (c *CopyCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bu return err } - // If the destination dir is a symlink we need to resolve the path and use - // that instead of the symlink path - destPath, err = resolveIfSymlink(destPath) - if err != nil { - return err - } - if fi.IsDir() { + // If the destination dir is a symlink we need to resolve the path and use + // that instead of the symlink path + destPath, err = resolveIfSymlink(destPath) + if err != nil { + return err + } copiedFiles, err := util.CopyDir(fullPath, destPath, c.buildcontext, uid, gid) if err != nil { return err diff --git a/pkg/commands/copy_test.go b/pkg/commands/copy_test.go index c69d007db..09bec8e79 100755 --- a/pkg/commands/copy_test.go +++ b/pkg/commands/copy_test.go @@ -442,3 +442,139 @@ func TestGetUserGroup(t *testing.T) { }) } } + +func TestCopyCommand_ExecuteCommand_Extended(t *testing.T) { + setupDirs := func(t *testing.T) (string, string) { + testDir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatal(err) + } + + targetDir := filepath.Join(testDir, "bar") + + if err := os.MkdirAll(targetDir, 0777); err != nil { + t.Fatal(err) + } + + targetPath := filepath.Join(targetDir, "bam.txt") + + if err := ioutil.WriteFile(targetPath, []byte("woof"), 0777); err != nil { + t.Fatal(err) + } + + return testDir, filepath.Base(targetDir) + } + + t.Run("copy dir to another dir", func(t *testing.T) { + testDir, targetDir := setupDirs(t) + defer os.RemoveAll(testDir) + + cmd := CopyCommand{ + cmd: &instructions.CopyCommand{ + SourcesAndDest: []string{targetDir, "dest"}, + }, + buildcontext: testDir, + } + + cfg := &v1.Config{ + Cmd: nil, + Env: []string{}, + WorkingDir: testDir, + } + + err := cmd.ExecuteCommand(cfg, dockerfile.NewBuildArgs([]string{})) + testutil.CheckNoError(t, err) + }) + + t.Run("copy file to a dir", func(t *testing.T) { + testDir, targetDir := setupDirs(t) + defer os.RemoveAll(testDir) + cmd := CopyCommand{ + cmd: &instructions.CopyCommand{ + SourcesAndDest: []string{filepath.Join(targetDir, "bam.txt"), "dest/"}, + }, + buildcontext: testDir, + } + + cfg := &v1.Config{ + Cmd: nil, + Env: []string{}, + WorkingDir: testDir, + } + + err := cmd.ExecuteCommand(cfg, dockerfile.NewBuildArgs([]string{})) + testutil.CheckNoError(t, err) + }) + + t.Run("copy file to a filepath", func(t *testing.T) { + testDir, targetDir := setupDirs(t) + defer os.RemoveAll(testDir) + cmd := CopyCommand{ + cmd: &instructions.CopyCommand{ + SourcesAndDest: []string{filepath.Join(targetDir, "bam.txt"), "dest"}, + }, + buildcontext: testDir, + } + + cfg := &v1.Config{ + Cmd: nil, + Env: []string{}, + WorkingDir: testDir, + } + + err := cmd.ExecuteCommand(cfg, dockerfile.NewBuildArgs([]string{})) + testutil.CheckNoError(t, err) + }) + t.Run("copy file to a dir without trailing /", func(t *testing.T) { + testDir, targetDir := setupDirs(t) + defer os.RemoveAll(testDir) + + destDir := filepath.Join(testDir, "dest") + if err := os.MkdirAll(destDir, 0777); err != nil { + t.Fatal(err) + } + + cmd := CopyCommand{ + cmd: &instructions.CopyCommand{ + SourcesAndDest: []string{filepath.Join(targetDir, "bam.txt"), "dest"}, + }, + buildcontext: testDir, + } + + cfg := &v1.Config{ + Cmd: nil, + Env: []string{}, + WorkingDir: testDir, + } + + err := cmd.ExecuteCommand(cfg, dockerfile.NewBuildArgs([]string{})) + testutil.CheckNoError(t, err) + }) + t.Run("copy symlink file to a dir", func(t *testing.T) { + testDir, targetDir := setupDirs(t) + defer os.RemoveAll(testDir) + + another := filepath.Join(testDir, "another") + if err := os.MkdirAll(another, 0777); err != nil { + t.Fatal(err) + } + symlink := filepath.Join(another, "sym.link") + os.Symlink(filepath.Join(targetDir, "bam.txt"), symlink) + + cmd := CopyCommand{ + cmd: &instructions.CopyCommand{ + SourcesAndDest: []string{symlink, "dest"}, + }, + buildcontext: testDir, + } + + cfg := &v1.Config{ + Cmd: nil, + Env: []string{}, + WorkingDir: testDir, + } + + err := cmd.ExecuteCommand(cfg, dockerfile.NewBuildArgs([]string{})) + testutil.CheckNoError(t, err) + }) +} \ No newline at end of file diff --git a/pkg/filesystem/resolve.go b/pkg/filesystem/resolve.go index 63beff748..920473eb5 100644 --- a/pkg/filesystem/resolve.go +++ b/pkg/filesystem/resolve.go @@ -17,6 +17,7 @@ limitations under the License. package filesystem import ( + "fmt" "os" "path/filepath" @@ -126,6 +127,7 @@ func resolveSymlinkAncestor(path string) (string, error) { return "", errors.New("dest path must be abs") } + fmt.Println(path) last := "" newPath := filepath.Clean(path) @@ -133,7 +135,7 @@ loop: for newPath != "/" { fi, err := os.Lstat(newPath) if err != nil { - return "", errors.Wrap(err, "failed to lstat") + return "", errors.Wrap(err, "resolvePaths: failed to lstat") } if util.IsSymlink(fi) { diff --git a/pkg/util/command_util.go b/pkg/util/command_util.go index 23f035ec4..96f899398 100644 --- a/pkg/util/command_util.go +++ b/pkg/util/command_util.go @@ -171,14 +171,14 @@ func DestinationFilepath(src, dest, cwd string) (string, error) { _, srcFileName := filepath.Split(src) newDest := dest - if IsDestDir(newDest) { - newDest = filepath.Join(newDest, srcFileName) - } - if !filepath.IsAbs(newDest) { newDest = filepath.Join(cwd, newDest) } + if IsDestDir(newDest) { + newDest = filepath.Join(newDest, srcFileName) + } + if len(srcFileName) <= 0 && !strings.HasSuffix(newDest, "/") { newDest += "/" } diff --git a/pkg/util/fs_util.go b/pkg/util/fs_util.go index 40c705dd8..770eef252 100644 --- a/pkg/util/fs_util.go +++ b/pkg/util/fs_util.go @@ -505,15 +505,16 @@ func FilepathExists(path string) bool { func CreateFile(path string, reader io.Reader, perm os.FileMode, uid uint32, gid uint32) error { // Create directory path if it doesn't exist if err := createParentDirectory(path); err != nil { - return err + return errors.Wrap(err, "creating parent dir") } + dest, err := os.Create(path) if err != nil { - return err + return errors.Wrap(err, "creating file") } defer dest.Close() if _, err := io.Copy(dest, reader); err != nil { - return err + return errors.Wrap(err, "copying file") } return setFilePermissions(path, perm, int(uid), int(gid)) } @@ -614,9 +615,9 @@ func CopySymlink(src, dest, buildcontext string, uid int64, gid int64) (bool, er logrus.Debugf("%s found in .dockerignore, ignoring", src) return true, nil } - link, err := filepath.EvalSymlinks(src) + link, err := os.Readlink(src) if err != nil { - return false, err + logrus.Debugf("could not evaluate %s, probably a dead link", src) } if FilepathExists(dest) { if err := os.RemoveAll(dest); err != nil { @@ -626,7 +627,7 @@ func CopySymlink(src, dest, buildcontext string, uid int64, gid int64) (bool, er if err := createParentDirectory(dest); err != nil { return false, err } - return CopyFile(link, dest, buildcontext, uid, gid) + return true, os.Symlink(link, dest) } // CopyFile copies the file at src to dest diff --git a/testutil/util.go b/testutil/util.go index a1e72dd08..c983b53e4 100644 --- a/testutil/util.go +++ b/testutil/util.go @@ -68,6 +68,12 @@ func CheckError(t *testing.T, shouldErr bool, err error) { } } +func CheckNoError(t *testing.T, err error) { + if err != nil { + t.Error(err) + } +} + func checkErr(shouldErr bool, err error) error { if err == nil && shouldErr { return fmt.Errorf("Expected error, but returned none")