github.com/ahmet2mir/goreleaser@v0.180.3-0.20210927151101-8e5ee5a9b8c5/internal/gio/copy.go (about) 1 package gio 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "path/filepath" 8 "strings" 9 10 "github.com/apex/log" 11 ) 12 13 // Copy recursively copies src into dst with src's file modes. 14 func Copy(src, dst string) error { 15 return CopyWithMode(src, dst, 0) 16 } 17 18 // CopyWithMode recursively copies src into dst with the given mode. 19 // The given mode applies only to files. Their parent dirs will have the same mode as their src counterparts. 20 func CopyWithMode(src, dst string, mode os.FileMode) error { 21 return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { 22 if err != nil { 23 return fmt.Errorf("failed to copy %s to %s: %w", src, dst, err) 24 } 25 // We have the following: 26 // - src = "a/b" 27 // - dst = "dist/linuxamd64/b" 28 // - path = "a/b/c.txt" 29 // So we join "a/b" with "c.txt" and use it as the destination. 30 dst := filepath.Join(dst, strings.Replace(path, src, "", 1)) 31 log.WithFields(log.Fields{ 32 "src": path, 33 "dst": dst, 34 }).Debug("copying file") 35 if info.IsDir() { 36 return os.MkdirAll(dst, info.Mode()) 37 } 38 if mode != 0 { 39 return copyFile(path, dst, mode) 40 } 41 return copyFile(path, dst, info.Mode()) 42 }) 43 } 44 45 func copyFile(src, dst string, mode os.FileMode) error { 46 original, err := os.Open(src) 47 if err != nil { 48 return fmt.Errorf("failed to open '%s': %w", src, err) 49 } 50 defer original.Close() 51 52 new, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode) 53 if err != nil { 54 return fmt.Errorf("failed to open '%s': %w", dst, err) 55 } 56 defer new.Close() 57 58 if _, err := io.Copy(new, original); err != nil { 59 return fmt.Errorf("failed to copy: %w", err) 60 } 61 return nil 62 }