package common import ( "fmt" "io" "io/fs" "log" "os" "sync" ) // From https://opensource.com/article/18/6/copying-files-go func CopyFile(src string, dst string) error { source, err := os.Open(src) if err != nil { return err } defer source.Close() destination, err := os.Create(dst) if err != nil { return err } defer destination.Close() _, err = io.Copy(destination, source) return err } func Copy(opts CopyOpts) { if !opts.info.Mode().IsRegular() { log.Fatalf("%s is not a regular file", opts.src) } if opts.hardlink { // hardlink this file if opts.verbose { fmt.Printf("hardlink %v => %v\n", opts.src, opts.dst) } err := os.Link(opts.src, opts.dst) if err != nil { // fallback to copy if opts.verbose { fmt.Printf("hardlink failed: %v\n", err) fmt.Printf("copy (fallback) %v => %v\n", opts.src, opts.dst) } err = CopyFile(opts.src, opts.dst) if err != nil { log.Fatal(err) } } } else { // copy this file if opts.verbose { fmt.Printf("copy %v => %v\n", opts.src, opts.dst) } err := CopyFile(opts.src, opts.dst) if err != nil { log.Fatal(err) } } } type CopyWorker struct { queue <-chan CopyOpts } func NewCopyWorker(queue <-chan CopyOpts) *CopyWorker { return &CopyWorker{queue: queue} } func (w *CopyWorker) Run(wg *sync.WaitGroup) { defer wg.Done() for opts := range w.queue { Copy(opts) } } type CopyOpts struct { src, dst string info fs.FileInfo hardlink bool verbose bool } func NewCopyOpts(src string, dst string, info fs.FileInfo, hardlink bool, verbose bool) CopyOpts { return CopyOpts{src: src, dst: dst, info: info, hardlink: hardlink, verbose: verbose} }