mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-28 01:41:48 -06:00
2c44a7aacb
copyDir is used in configload/getter.go to copy previously downloaded modules instead of using the go-getter client every time. The go-getter client downloads dotfiles, but copyDir did not copy dotfiles, leading to inconsistent behaviour when reusing the same module source.
116 lines
2.2 KiB
Go
116 lines
2.2 KiB
Go
package configload
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
// copyDir copies the src directory contents into dst. Both directories
|
|
// should already exist.
|
|
func copyDir(dst, src string) error {
|
|
src, err := filepath.EvalSymlinks(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
walkFn := func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if path == src {
|
|
return nil
|
|
}
|
|
|
|
// The "path" has the src prefixed to it. We need to join our
|
|
// destination with the path without the src on it.
|
|
dstPath := filepath.Join(dst, path[len(src):])
|
|
|
|
// we don't want to try and copy the same file over itself.
|
|
if eq, err := sameFile(path, dstPath); eq {
|
|
return nil
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
|
|
// If we have a directory, make that subdirectory, then continue
|
|
// the walk.
|
|
if info.IsDir() {
|
|
if path == filepath.Join(src, dst) {
|
|
// dst is in src; don't walk it.
|
|
return nil
|
|
}
|
|
|
|
if err := os.MkdirAll(dstPath, 0755); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// If the current path is a symlink, recreate the symlink relative to
|
|
// the dst directory
|
|
if info.Mode()&os.ModeSymlink == os.ModeSymlink {
|
|
target, err := os.Readlink(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.Symlink(target, dstPath)
|
|
}
|
|
|
|
// If we have a file, copy the contents.
|
|
srcF, err := os.Open(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer srcF.Close()
|
|
|
|
dstF, err := os.Create(dstPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer dstF.Close()
|
|
|
|
if _, err := io.Copy(dstF, srcF); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Chmod it
|
|
return os.Chmod(dstPath, info.Mode())
|
|
}
|
|
|
|
return filepath.Walk(src, walkFn)
|
|
}
|
|
|
|
// sameFile tried to determine if to paths are the same file.
|
|
// If the paths don't match, we lookup the inode on supported systems.
|
|
func sameFile(a, b string) (bool, error) {
|
|
if a == b {
|
|
return true, nil
|
|
}
|
|
|
|
aIno, err := inode(a)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return false, nil
|
|
}
|
|
return false, err
|
|
}
|
|
|
|
bIno, err := inode(b)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return false, nil
|
|
}
|
|
return false, err
|
|
}
|
|
|
|
if aIno > 0 && aIno == bIno {
|
|
return true, nil
|
|
}
|
|
|
|
return false, nil
|
|
}
|