github.com/solo-io/cue@v0.4.7/internal/copy/copy.go (about) 1 // Copyright 2019 CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package copy provides utilities to copy files and directories. 16 package copy 17 18 import ( 19 "fmt" 20 "io" 21 "io/ioutil" 22 "os" 23 "path/filepath" 24 ) 25 26 // File creates dst and copies the contents src to it. 27 func File(src, dst string) error { 28 src = filepath.Clean(src) 29 dst = filepath.Clean(dst) 30 31 stat, err := os.Stat(src) 32 if err != nil { 33 return fmt.Errorf("copy file: %v", err) 34 } 35 err = copyFile(stat, src, dst) 36 if err != nil { 37 return fmt.Errorf("copy file: %v", err) 38 } 39 return nil 40 } 41 42 // Dir copies a src directory to its destination. 43 func Dir(src, dst string) error { 44 src = filepath.Clean(src) 45 dst = filepath.Clean(dst) 46 47 stat, err := os.Stat(src) 48 if err != nil { 49 return fmt.Errorf("copy failed: %v", err) 50 } else if !stat.IsDir() { 51 return fmt.Errorf("copy failed: source is not a directory") 52 } 53 54 err = copyDir(stat, src, dst) 55 if err != nil { 56 return fmt.Errorf("copy failed: %v", err) 57 } 58 return nil 59 } 60 61 func copyDir(info os.FileInfo, src, dst string) error { 62 if _, err := os.Stat(dst); err != nil { 63 if !os.IsNotExist(err) { 64 return fmt.Errorf("dest err %s: %v", dst, err) 65 } 66 if err := os.MkdirAll(dst, info.Mode()); err != nil { 67 return fmt.Errorf("making dest %s: %v", dst, err) 68 } 69 } 70 71 entries, err := ioutil.ReadDir(src) 72 if err != nil { 73 return fmt.Errorf("reading dir %s: %v", src, err) 74 } 75 76 for _, e := range entries { 77 srcPath := filepath.Join(src, e.Name()) 78 dstPath := filepath.Join(dst, e.Name()) 79 80 switch mode := e.Mode(); mode & os.ModeType { 81 case os.ModeSymlink: 82 err = copySymLink(e, srcPath, dstPath) 83 case os.ModeDir: 84 err = copyDir(e, srcPath, dstPath) 85 default: 86 err = copyFile(e, srcPath, dstPath) 87 } 88 if err != nil { 89 return err 90 } 91 } 92 return nil 93 } 94 95 func copySymLink(info os.FileInfo, src, dst string) error { 96 mode := info.Mode() 97 link, err := os.Readlink(src) 98 if err != nil { 99 return err 100 } 101 err = os.Symlink(link, dst) 102 if err != nil { 103 return err 104 } 105 return os.Chmod(dst, mode) 106 } 107 108 func copyFile(info os.FileInfo, src, dst string) (err error) { 109 in, err := os.Open(src) 110 if err != nil { 111 return fmt.Errorf("error reading %s: %v", src, err) 112 } 113 defer in.Close() 114 115 out, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, info.Mode()) 116 if err != nil { 117 return fmt.Errorf("error creating %s: %v", dst, err) 118 } 119 defer func() { 120 cErr := out.Close() 121 if err == nil { 122 err = cErr 123 } 124 }() 125 126 _, err = io.Copy(out, in) 127 if err != nil { 128 return fmt.Errorf("error copying %s: %v", dst, err) 129 } 130 return err 131 }