github.com/goreleaser/goreleaser@v1.25.1/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/caarlos0/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 src = filepath.ToSlash(src) 22 dst = filepath.ToSlash(dst) 23 return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { 24 if err != nil { 25 return fmt.Errorf("failed to copy %s to %s: %w", src, dst, err) 26 } 27 path = filepath.ToSlash(path) 28 // We have the following: 29 // - src = "a/b" 30 // - dst = "dist/linuxamd64/b" 31 // - path = "a/b/c.txt" 32 // So we join "a/b" with "c.txt" and use it as the destination. 33 dst := filepath.ToSlash(filepath.Join(dst, strings.Replace(path, src, "", 1))) 34 log.WithField("src", path).WithField("dst", dst).Debug("copying file") 35 if info.IsDir() { 36 return os.MkdirAll(dst, info.Mode()) 37 } 38 if info.Mode()&os.ModeSymlink != 0 { 39 return copySymlink(path, dst) 40 } 41 if mode != 0 { 42 return copyFile(path, dst, mode) 43 } 44 return copyFile(path, dst, info.Mode()) 45 }) 46 } 47 48 func copySymlink(src, dst string) error { 49 src, err := os.Readlink(src) 50 if err != nil { 51 return err 52 } 53 return os.Symlink(src, dst) 54 } 55 56 func copyFile(src, dst string, mode os.FileMode) error { 57 original, err := os.Open(src) 58 if err != nil { 59 return fmt.Errorf("failed to open '%s': %w", src, err) 60 } 61 defer original.Close() 62 63 f, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode) 64 if err != nil { 65 return fmt.Errorf("failed to open '%s': %w", dst, err) 66 } 67 defer f.Close() 68 69 if _, err := io.Copy(f, original); err != nil { 70 return fmt.Errorf("failed to copy: %w", err) 71 } 72 return nil 73 }