github.com/jenkins-x/jx-api@v0.0.24/cmd/codegen/util/files.go (about) 1 package util 2 3 import ( 4 "fmt" 5 "io" 6 "io/ioutil" 7 "net/http" 8 "os" 9 "path/filepath" 10 "time" 11 12 "github.com/jenkins-x/jx-logging/pkg/log" 13 14 "github.com/pkg/errors" 15 ) 16 17 // BackupGoModAndGoSum creates backup copies of go.mod and go.sum and returns a function to run at the end of execution 18 // to revert the go.mod and go.sum in the repo to the backups. 19 func BackupGoModAndGoSum() (func(), error) { 20 defaultCleanupFunc := func() {} 21 wd, err := os.Getwd() 22 if err != nil { 23 return defaultCleanupFunc, errors.Wrapf(err, "getting current directory") 24 } 25 origMod := filepath.Join(wd, "go.mod") 26 origSum := filepath.Join(wd, "go.sum") 27 modExists, err := FileExists(origMod) 28 if err != nil { 29 return defaultCleanupFunc, errors.Wrapf(err, "checking if %s exists", origMod) 30 } 31 sumExists, err := FileExists(origSum) 32 if err != nil { 33 return defaultCleanupFunc, errors.Wrapf(err, "checking if %s exists", origSum) 34 } 35 if modExists && sumExists { 36 tmpDir, err := ioutil.TempDir("", "go-mod-backup-") 37 if err != nil { 38 return defaultCleanupFunc, errors.Wrapf(err, "creating go mod backup directory") 39 } 40 tmpMod := filepath.Join(tmpDir, "go.mod") 41 tmpSum := filepath.Join(tmpDir, "go.sum") 42 err = CopyFile(origMod, tmpMod) 43 if err != nil { 44 return defaultCleanupFunc, errors.Wrapf(err, "copying %s to %s", origMod, tmpMod) 45 } 46 err = CopyFile(origSum, tmpSum) 47 if err != nil { 48 return defaultCleanupFunc, errors.Wrapf(err, "copying %s to %s", origSum, tmpSum) 49 } 50 51 return func() { 52 err := CopyFile(tmpMod, origMod) 53 if err != nil { 54 log.Logger().WithError(err).Errorf("restoring backup go.mod from %s", tmpMod) 55 } 56 err = CopyFile(tmpSum, origSum) 57 if err != nil { 58 log.Logger().WithError(err).Errorf("restoring backup go.sum from %s", tmpSum) 59 } 60 err = os.RemoveAll(tmpDir) 61 if err != nil { 62 log.Logger().WithError(err).Errorf("removing go mod backup directory %s", tmpDir) 63 } 64 }, nil 65 } 66 return defaultCleanupFunc, nil 67 } 68 69 // DeleteDirContents removes all the contents of the given directory 70 func DeleteDirContents(dir string) error { 71 files, err := filepath.Glob(filepath.Join(dir, "*")) 72 if err != nil { 73 return err 74 } 75 for _, file := range files { 76 // lets ignore the top level dir 77 if dir != file { 78 err = os.RemoveAll(file) 79 if err != nil { 80 return err 81 } 82 } 83 } 84 return nil 85 } 86 87 // FileExists returns true if the specified path exist, false otherwise. An error is returned if and file system 88 // operation fails. 89 func FileExists(path string) (bool, error) { 90 _, err := os.Stat(path) 91 if err == nil { 92 return true, nil 93 } 94 if os.IsNotExist(err) { 95 return false, nil 96 } 97 return true, errors.Wrapf(err, "failed to check if file exists %s", path) 98 } 99 100 // DirExists checks if path exists and is a directory 101 func DirExists(path string) (bool, error) { 102 info, err := os.Stat(path) 103 if err == nil { 104 return info.IsDir(), nil 105 } else if os.IsNotExist(err) { 106 return false, nil 107 } 108 return false, err 109 } 110 111 // DeleteFile deletes a file from the operating system. This should NOT be used to delete any sensitive information 112 // because it can easily be recovered. Use DestroyFile to delete sensitive information 113 func DeleteFile(fileName string) (err error) { 114 if fileName != "" { 115 exists, err := FileExists(fileName) 116 if err != nil { 117 return fmt.Errorf("could not check if file exists %s due to %s", fileName, err) 118 } 119 120 if exists { 121 err = os.Remove(fileName) 122 if err != nil { 123 return errors.Wrapf(err, "could not remove file due to %s", fileName) 124 } 125 } 126 } else { 127 return fmt.Errorf("filename is not valid") 128 } 129 return nil 130 } 131 132 // CopyFile copies a file from the specified source src to dst. 133 // credit https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04 134 func CopyFile(src, dst string) (err error) { 135 in, err := os.Open(src) 136 if err != nil { 137 return 138 } 139 defer in.Close() //nolint:errcheck 140 141 out, err := os.Create(dst) 142 if err != nil { 143 return 144 } 145 defer func() { 146 if e := out.Close(); e != nil { 147 err = e 148 } 149 }() 150 151 _, err = io.Copy(out, in) 152 if err != nil { 153 return 154 } 155 156 err = out.Sync() 157 if err != nil { 158 return 159 } 160 161 si, err := os.Stat(src) 162 if err != nil { 163 return 164 } 165 err = os.Chmod(dst, si.Mode()) 166 if err != nil { 167 return 168 } 169 170 return nil 171 } 172 173 // CopyDirPreserve copies from the src dir to the dst dir if the file does NOT already exist in dst 174 func CopyDirPreserve(src string, dst string) error { 175 src = filepath.Clean(src) 176 dst = filepath.Clean(dst) 177 178 si, err := os.Stat(src) 179 if err != nil { 180 return errors.Wrapf(err, "checking %s exists", src) 181 } 182 if !si.IsDir() { 183 return fmt.Errorf("source is not a directory") 184 } 185 186 _, err = os.Stat(dst) 187 if err != nil && !os.IsNotExist(err) { 188 return errors.Wrapf(err, "checking %s exists", dst) 189 } 190 191 err = os.MkdirAll(dst, si.Mode()) 192 if err != nil { 193 return errors.Wrapf(err, "creating %s", dst) 194 } 195 196 entries, err := ioutil.ReadDir(src) 197 if err != nil { 198 return errors.Wrapf(err, "reading files in %s", src) 199 } 200 201 for _, entry := range entries { 202 srcPath := filepath.Join(src, entry.Name()) 203 dstPath := filepath.Join(dst, entry.Name()) 204 205 if entry.IsDir() { 206 err = CopyDirPreserve(srcPath, dstPath) 207 if err != nil { 208 return errors.Wrapf(err, "recursively copying %s", entry.Name()) 209 } 210 } else { 211 // Skip symlinks. 212 if entry.Mode()&os.ModeSymlink != 0 { 213 continue 214 } 215 if _, err := os.Stat(dstPath); os.IsNotExist(err) { 216 err = CopyFile(srcPath, dstPath) 217 if err != nil { 218 return errors.Wrapf(err, "copying %s to %s", srcPath, dstPath) 219 } 220 } else if err != nil { 221 return errors.Wrapf(err, "checking if %s exists", dstPath) 222 } 223 } 224 } 225 return nil 226 } 227 228 // DownloadFile downloads a file from the given URL 229 func DownloadFile(filepath string, url string) (err error) { 230 // Create the file 231 out, err := os.Create(filepath) 232 if err != nil { 233 return err 234 } 235 defer out.Close() //nolint:errcheck 236 237 // Get the data 238 resp, err := GetClientWithTimeout(time.Hour * 2).Get(url) 239 if err != nil { 240 return err 241 } 242 defer resp.Body.Close() //nolint:errcheck 243 244 if resp.StatusCode != http.StatusOK { 245 err := fmt.Errorf("download of %s failed with return code %d", url, resp.StatusCode) 246 return err 247 } 248 249 // Writer the body to file 250 _, err = io.Copy(out, resp.Body) 251 if err != nil { 252 return err 253 } 254 255 // make it executable 256 err = os.Chmod(filepath, 0755) 257 if err != nil { 258 return err 259 } 260 return nil 261 } 262 263 // GetClientWithTimeout returns a client with JX default transport and user specified timeout 264 func GetClientWithTimeout(duration time.Duration) *http.Client { 265 client := http.Client{} 266 return &client 267 }