diff --git a/v2/internal/fs/fs.go b/v2/internal/fs/fs.go index d49b22f26..aa0fceeeb 100644 --- a/v2/internal/fs/fs.go +++ b/v2/internal/fs/fs.go @@ -215,10 +215,10 @@ func DirIsEmpty(dir string) (bool, error) { return false, err // Either not empty or error, suits both cases } -// Credit: https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04 // CopyDir recursively copies a directory tree, attempting to preserve permissions. // Source directory must exist, destination directory must *not* exist. // Symlinks are ignored and skipped. +// Credit: https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04 func CopyDir(src string, dst string) (err error) { src = filepath.Clean(src) dst = filepath.Clean(dst) @@ -273,3 +273,68 @@ func CopyDir(src string, dst string) (err error) { return } + +// CopyDirExtended recursively copies a directory tree, attempting to preserve permissions. +// Source directory must exist, destination directory must *not* exist. It ignores any files or +// directories that are given through the ignore parameter. +// Symlinks are ignored and skipped. +// Credit: https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04 +func CopyDirExtended(src string, dst string, ignore []string) (err error) { + + ignoreList := slicer.String(ignore) + src = filepath.Clean(src) + dst = filepath.Clean(dst) + + si, err := os.Stat(src) + if err != nil { + return err + } + if !si.IsDir() { + return fmt.Errorf("source is not a directory") + } + + _, err = os.Stat(dst) + if err != nil && !os.IsNotExist(err) { + return + } + if err == nil { + return fmt.Errorf("destination already exists") + } + + err = MkDirs(dst) + if err != nil { + return + } + + entries, err := ioutil.ReadDir(src) + if err != nil { + return + } + + for _, entry := range entries { + if ignoreList.Contains(entry.Name()) { + continue + } + srcPath := filepath.Join(src, entry.Name()) + dstPath := filepath.Join(dst, entry.Name()) + + if entry.IsDir() { + err = CopyDir(srcPath, dstPath) + if err != nil { + return + } + } else { + // Skip symlinks. + if entry.Mode()&os.ModeSymlink != 0 { + continue + } + + err = CopyFile(srcPath, dstPath) + if err != nil { + return + } + } + } + + return +}