github.com/PaulioRandall/go-cookies@v0.1.1/cookies/files.go (about)

     1  package cookies
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"strconv"
    10  	"strings"
    11  )
    12  
    13  // WorkDirHistory is the working directory stack used by Pushd and Popd
    14  // functions.
    15  var WorkDirHistory = []string{}
    16  
    17  // Pushd emulates pushd bash command.
    18  func Pushd(dir string) error {
    19  	curr, e := os.Getwd()
    20  	if e != nil {
    21  		return e
    22  	}
    23  	if e = os.Chdir(dir); e != nil {
    24  		return e
    25  	}
    26  	WorkDirHistory = append(WorkDirHistory, curr)
    27  	return nil
    28  }
    29  
    30  // Popd emulates the popd bash command.
    31  func Popd() error {
    32  	if len(WorkDirHistory) == 0 {
    33  		return nil
    34  	}
    35  	last := len(WorkDirHistory) - 1
    36  	dir := WorkDirHistory[last]
    37  	if e := os.Chdir(dir); e != nil {
    38  		return e
    39  	}
    40  	WorkDirHistory = WorkDirHistory[:last]
    41  	return nil
    42  }
    43  
    44  // FileExists returns true if the file exists, false if not, and an error if
    45  // file existence could not be determined.
    46  func FileExists(f string) (bool, error) {
    47  	_, e := os.Stat(f)
    48  	if os.IsNotExist(e) {
    49  		return false, nil
    50  	}
    51  	return true, e
    52  }
    53  
    54  // IsDir returns true if the file exists and is a directory. An error is
    55  // returned if this could not be determined.
    56  func IsDir(f string) (bool, error) {
    57  	stat, e := os.Stat(f)
    58  	if os.IsNotExist(e) {
    59  		return false, nil
    60  	}
    61  	if e != nil {
    62  		return false, e
    63  	}
    64  	return stat.Mode().IsDir(), nil
    65  }
    66  
    67  // IsRegFile returns true if the file exists and is a regular file. An error is
    68  // returned if this could not be determined.
    69  func IsRegFile(f string) (bool, error) {
    70  	stat, e := os.Stat(f)
    71  	if os.IsNotExist(e) {
    72  		return false, nil
    73  	}
    74  	if e != nil {
    75  		return false, e
    76  	}
    77  	return stat.Mode().IsRegular(), nil
    78  }
    79  
    80  // SameFile returns true if the two files 'a' and 'b' describe the same file
    81  // as determined by os.SameFile. An error is returned if the file info could
    82  // not be retreived for either file.
    83  func SameFile(a, b string) (bool, error) {
    84  	aStat, e := os.Stat(a)
    85  	if e != nil {
    86  		return false, e
    87  	}
    88  	bStat, e := os.Stat(b)
    89  	if e != nil {
    90  		return false, e
    91  	}
    92  	return os.SameFile(aStat, bStat), nil
    93  }
    94  
    95  // CopyFile copies the single file 'src' to 'dst'.
    96  func CopyFile(src, dst string, overwrite bool) error {
    97  
    98  	if ok, e := IsRegFile(src); e != nil || !ok {
    99  		return fmt.Errorf("Missing or not a regular file: %s", src)
   100  	}
   101  
   102  	if !overwrite {
   103  		ok, e := FileExists(dst)
   104  		if e != nil {
   105  			return e
   106  		}
   107  		if ok {
   108  			return fmt.Errorf("Destination already exists: %s", dst)
   109  		}
   110  	}
   111  
   112  	same, e := SameFile(src, dst)
   113  	if e == nil && same {
   114  		return fmt.Errorf("Destination is the same as source: %s == %s", dst, src)
   115  	}
   116  
   117  	return NoCheckCopyFile(src, dst)
   118  }
   119  
   120  // NoCheckCopyFile copies the single file 'src' to 'dst' and doesn't make any
   121  // attempt to check the file paths before hand.
   122  func NoCheckCopyFile(src, dst string) error {
   123  
   124  	srcFile, e := os.Open(src)
   125  	if e != nil {
   126  		return e
   127  	}
   128  	defer srcFile.Close()
   129  
   130  	dstFile, e := os.Create(dst)
   131  	if e != nil {
   132  		return e
   133  	}
   134  	defer dstFile.Close()
   135  
   136  	_, e = io.Copy(dstFile, srcFile)
   137  	if e != nil {
   138  		return e
   139  	}
   140  
   141  	return nil
   142  }
   143  
   144  // FileToQuote returns the bytes of the input file as as a quoted string so it
   145  // may be embedded in source code. Use []byte(quotedString) to decode.
   146  func FileToQuote(file string) (string, error) {
   147  	b, e := ioutil.ReadFile(file)
   148  	if e != nil {
   149  		return "", e
   150  	}
   151  	s := strconv.Quote(string(b))
   152  	return s, nil
   153  }
   154  
   155  // CreateFiles creates the files and directories within 'files' with 'root' as
   156  // the root directory. 'files' contains a set of relative file paths mapped to
   157  // the their required content. If the file is a directory it must be suffixed
   158  // with a '/' and the mapped data will be ignored.
   159  func CreateFiles(root string, mode os.FileMode, files map[string][]byte) error {
   160  
   161  	createFile := func(f string, data []byte) error {
   162  		parent := filepath.Dir(f)
   163  		if e := os.MkdirAll(parent, mode); e != nil { // Create parents if missing
   164  			return e
   165  		}
   166  		return ioutil.WriteFile(f, data, mode)
   167  	}
   168  
   169  	createDir := func(d string) error {
   170  		if exists, e := FileExists(d); e != nil || exists {
   171  			return e
   172  		}
   173  		return os.MkdirAll(d, mode)
   174  	}
   175  
   176  	for p, data := range files {
   177  		f := filepath.Join(root, p)
   178  
   179  		if strings.HasSuffix(p, "/") {
   180  			if e := createDir(f); e != nil {
   181  				return e
   182  			}
   183  			continue
   184  		}
   185  
   186  		if e := createFile(f, data); e != nil {
   187  			return e
   188  		}
   189  	}
   190  
   191  	return nil
   192  }