github.com/kekek/gb@v0.4.5-0.20170222120241-d4ba64b0b297/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 // Copyfile copies file to destination creating destination directory if needed 55 func Copyfile(dst, src string) error { 56 err := mkdir(filepath.Dir(dst)) 57 if err != nil { 58 return errors.Wrap(err, "copyfile: mkdirall") 59 } 60 r, err := os.Open(src) 61 if err != nil { 62 return errors.Wrapf(err, "copyfile: open(%q)", src) 63 } 64 defer r.Close() 65 w, err := os.Create(dst) 66 if err != nil { 67 return errors.Wrapf(err, "copyfile: create(%q)", dst) 68 } 69 defer w.Close() 70 if debugCopyfile { 71 fmt.Printf("copyfile(dst: %v, src: %v)\n", dst, src) 72 } 73 _, err = io.Copy(w, r) 74 return err 75 } 76 77 // RemoveAll removes path and any children it contains. Unlike os.RemoveAll it 78 // deletes read only files on Windows. 79 func RemoveAll(path string) error { 80 if runtime.GOOS == "windows" { 81 // Simple case: if Remove works, we're done. 82 err := os.Remove(path) 83 if err == nil || os.IsNotExist(err) { 84 return nil 85 } 86 // make sure all files are writable so we can delete them 87 filepath.Walk(path, func(path string, info os.FileInfo, err error) error { 88 if err != nil { 89 // walk gave us some error, give it back. 90 return err 91 } 92 mode := info.Mode() 93 if mode|0200 == mode { 94 return nil 95 } 96 return os.Chmod(path, mode|0200) 97 }) 98 } 99 return os.RemoveAll(path) 100 } 101 102 func mkdir(path string) error { 103 return os.MkdirAll(path, 0755) 104 }