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  }