github.com/gsquire/gb@v0.4.4-0.20161112235727-3982dc872064/internal/fileutils/fileutils.go (about)

     1  // package fileutils provides utililty methods to copy and move files and directories.
     2  package fileutils
     3  
     4  import (
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"path/filepath"
     9  	"runtime"
    10  	"strings"
    11  
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  const debugCopypath = false
    16  const debugCopyfile = false
    17  
    18  // Copypath copies the contents of src to dst, excluding any file or
    19  // directory that starts with a period.
    20  func Copypath(dst string, src string) error {
    21  	err := filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
    22  		if err != nil {
    23  			return err
    24  		}
    25  
    26  		if strings.HasPrefix(filepath.Base(path), ".") {
    27  			if info.IsDir() {
    28  				return filepath.SkipDir
    29  			}
    30  			return nil
    31  		}
    32  
    33  		if info.IsDir() {
    34  			return nil
    35  		}
    36  
    37  		if info.Mode()&os.ModeSymlink != 0 {
    38  			if debugCopypath {
    39  				fmt.Printf("skipping symlink: %v\n", path)
    40  			}
    41  			return nil
    42  		}
    43  
    44  		dst := filepath.Join(dst, path[len(src):])
    45  		return Copyfile(dst, path)
    46  	})
    47  	if err != nil {
    48  		// if there was an error during copying, remove the partial copy.
    49  		RemoveAll(dst)
    50  	}
    51  	return err
    52  }
    53  
    54  func Copyfile(dst, src string) error {
    55  	err := mkdir(filepath.Dir(dst))
    56  	if err != nil {
    57  		return errors.Wrap(err, "copyfile: mkdirall")
    58  	}
    59  	r, err := os.Open(src)
    60  	if err != nil {
    61  		return errors.Wrapf(err, "copyfile: open(%q)", src)
    62  	}
    63  	defer r.Close()
    64  	w, err := os.Create(dst)
    65  	if err != nil {
    66  		return errors.Wrapf(err, "copyfile: create(%q)", dst)
    67  	}
    68  	defer w.Close()
    69  	if debugCopyfile {
    70  		fmt.Printf("copyfile(dst: %v, src: %v)\n", dst, src)
    71  	}
    72  	_, err = io.Copy(w, r)
    73  	return err
    74  }
    75  
    76  // RemoveAll removes path and any children it contains. Unlike os.RemoveAll it
    77  // deletes read only files on Windows.
    78  func RemoveAll(path string) error {
    79  	if runtime.GOOS == "windows" {
    80  		// Simple case: if Remove works, we're done.
    81  		err := os.Remove(path)
    82  		if err == nil || os.IsNotExist(err) {
    83  			return nil
    84  		}
    85  		// make sure all files are writable so we can delete them
    86  		filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
    87  			if err != nil {
    88  				// walk gave us some error, give it back.
    89  				return err
    90  			}
    91  			mode := info.Mode()
    92  			if mode|0200 == mode {
    93  				return nil
    94  			}
    95  			return os.Chmod(path, mode|0200)
    96  		})
    97  	}
    98  	return os.RemoveAll(path)
    99  }
   100  
   101  func mkdir(path string) error {
   102  	return os.MkdirAll(path, 0755)
   103  }