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