| package fs | |
| import ( | |
| "fmt" | |
| "io" | |
| "io/fs" | |
| "os" | |
| "path" | |
| ) | |
| // CopyFile copies a source file to a destination file. | |
| func CopyFile(src string, dst string, mode fs.FileMode) error { | |
| srcFile, err := os.Open(src) | |
| if err != nil { | |
| return fmt.Errorf("could not open source file for copying: %v", err) | |
| } | |
| defer srcFile.Close() | |
| dstFile, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode) | |
| if err != nil { | |
| return fmt.Errorf("could not open destination file for copying: %v", err) | |
| } | |
| defer dstFile.Close() | |
| _, err = io.Copy(dstFile, srcFile) | |
| if err != nil { | |
| return fmt.Errorf("error while copying file %s to %s: %v", src, dst, err) | |
| } | |
| return nil | |
| } | |
| // CopyDir copies a source directory to a target directory, preserving file | |
| // permissions. | |
| // This should be faster than calling `cp -r <src> <dst>` for small directories. | |
| func CopyDir(src string, dst string, mode fs.FileMode) error { | |
| entries, err := os.ReadDir(src) | |
| if err != nil { | |
| return fmt.Errorf("failed to read directory for copying: %v", err) | |
| } | |
| err = os.MkdirAll(dst, mode) | |
| if err != nil { | |
| return err | |
| } | |
| for _, entry := range entries { | |
| entrySrc := path.Join(src, entry.Name()) | |
| entryDst := path.Join(dst, entry.Name()) | |
| entryInfo, err := entry.Info() | |
| if err != nil { | |
| return err | |
| } | |
| entryMode := entryInfo.Mode() | |
| if entryInfo.IsDir() { | |
| err = CopyDir(entrySrc, entryDst, entryMode) | |
| } else { | |
| err = CopyFile(entrySrc, entryDst, entryMode) | |
| } | |
| if err != nil { | |
| return err | |
| } | |
| } | |
| return nil | |
| } | |
| // IsDir returns whether or not a path exists and is a directory or is a | |
| // symlink to a directory. | |
| func IsDir(path string) bool { | |
| info, err := os.Stat(path) | |
| if err != nil { | |
| return false | |
| } | |
| return info.Mode().IsDir() | |
| } | |
| // IsFile returns whether or not a path exists and is a file or is a | |
| // symlink to a file. | |
| func IsFile(path string) bool { | |
| info, err := os.Stat(path) | |
| if err != nil { | |
| return false | |
| } | |
| return info.Mode().IsRegular() | |
| } |