github.com/gsquire/gb@v0.4.4-0.20161112235727-3982dc872064/internal/fileutils/fileutils.go (about) 1 // package fileutils provides utililty methods to copy and move files and directories. 2 package fileutils 3 4 import ( 5 "fmt" 6 "io" 7 "os" 8 "path/filepath" 9 "runtime" 10 "strings" 11 12 "github.com/pkg/errors" 13 ) 14 15 const debugCopypath = false 16 const debugCopyfile = false 17 18 // Copypath copies the contents of src to dst, excluding any file or 19 // directory that starts with a period. 20 func Copypath(dst string, src string) error { 21 err := filepath.Walk(src, func(path string, info os.FileInfo, err error) error { 22 if err != nil { 23 return err 24 } 25 26 if strings.HasPrefix(filepath.Base(path), ".") { 27 if info.IsDir() { 28 return filepath.SkipDir 29 } 30 return nil 31 } 32 33 if info.IsDir() { 34 return nil 35 } 36 37 if info.Mode()&os.ModeSymlink != 0 { 38 if debugCopypath { 39 fmt.Printf("skipping symlink: %v\n", path) 40 } 41 return nil 42 } 43 44 dst := filepath.Join(dst, path[len(src):]) 45 return Copyfile(dst, path) 46 }) 47 if err != nil { 48 // if there was an error during copying, remove the partial copy. 49 RemoveAll(dst) 50 } 51 return err 52 } 53 54 func Copyfile(dst, src string) error { 55 err := mkdir(filepath.Dir(dst)) 56 if err != nil { 57 return errors.Wrap(err, "copyfile: mkdirall") 58 } 59 r, err := os.Open(src) 60 if err != nil { 61 return errors.Wrapf(err, "copyfile: open(%q)", src) 62 } 63 defer r.Close() 64 w, err := os.Create(dst) 65 if err != nil { 66 return errors.Wrapf(err, "copyfile: create(%q)", dst) 67 } 68 defer w.Close() 69 if debugCopyfile { 70 fmt.Printf("copyfile(dst: %v, src: %v)\n", dst, src) 71 } 72 _, err = io.Copy(w, r) 73 return err 74 } 75 76 // RemoveAll removes path and any children it contains. Unlike os.RemoveAll it 77 // deletes read only files on Windows. 78 func RemoveAll(path string) error { 79 if runtime.GOOS == "windows" { 80 // Simple case: if Remove works, we're done. 81 err := os.Remove(path) 82 if err == nil || os.IsNotExist(err) { 83 return nil 84 } 85 // make sure all files are writable so we can delete them 86 filepath.Walk(path, func(path string, info os.FileInfo, err error) error { 87 if err != nil { 88 // walk gave us some error, give it back. 89 return err 90 } 91 mode := info.Mode() 92 if mode|0200 == mode { 93 return nil 94 } 95 return os.Chmod(path, mode|0200) 96 }) 97 } 98 return os.RemoveAll(path) 99 } 100 101 func mkdir(path string) error { 102 return os.MkdirAll(path, 0755) 103 }