go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/projects/blogctl/pkg/engine/copy.go (about) 1 /* 2 3 Copyright (c) 2023 - Present. Will Charczuk. All rights reserved. 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository. 5 6 */ 7 8 package engine 9 10 import ( 11 "io" 12 "io/ioutil" 13 "os" 14 "path/filepath" 15 ) 16 17 // Copy copies src to dest, doesn't matter if src is a directory or a file 18 func Copy(src, dest string) error { 19 info, err := os.Lstat(src) 20 if err != nil { 21 return err 22 } 23 return copy(src, dest, info) 24 } 25 26 // copy dispatches copy-funcs according to the mode. 27 // Because this "copy" could be called recursively, 28 // "info" MUST be given here, NOT nil. 29 func copy(src, dest string, info os.FileInfo) error { 30 if info.Mode()&os.ModeSymlink != 0 { 31 return lcopy(src, dest, info) 32 } 33 if info.IsDir() { 34 return dcopy(src, dest, info) 35 } 36 return fcopy(src, dest, info) 37 } 38 39 // fcopy is for just a file, 40 // with considering existence of parent directory 41 // and file permission. 42 func fcopy(src, dest string, info os.FileInfo) error { 43 if err := os.MkdirAll(filepath.Dir(dest), os.ModePerm); err != nil { 44 return err 45 } 46 47 f, err := os.Create(dest) 48 if err != nil { 49 return err 50 } 51 defer f.Close() 52 53 if err = os.Chmod(f.Name(), info.Mode()); err != nil { 54 return err 55 } 56 57 s, err := os.Open(src) 58 if err != nil { 59 return err 60 } 61 defer s.Close() 62 63 _, err = io.Copy(f, s) 64 return err 65 } 66 67 // dcopy is for a directory, 68 // with scanning contents inside the directory 69 // and pass everything to "copy" recursively. 70 func dcopy(srcdir, destdir string, info os.FileInfo) error { 71 if err := os.MkdirAll(destdir, info.Mode()); err != nil { 72 return err 73 } 74 75 contents, err := ioutil.ReadDir(srcdir) 76 if err != nil { 77 return err 78 } 79 80 for _, content := range contents { 81 cs, cd := filepath.Join(srcdir, content.Name()), filepath.Join(destdir, content.Name()) 82 if err := copy(cs, cd, content); err != nil { 83 return err 84 } 85 } 86 return nil 87 } 88 89 // lcopy is for a symlink, 90 // with just creating a new symlink by replicating src symlink. 91 func lcopy(src, dest string, _ os.FileInfo) error { 92 src, err := os.Readlink(src) 93 if err != nil { 94 return err 95 } 96 return os.Symlink(src, dest) 97 }