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  }