github.com/kekek/gb@v0.4.5-0.20170222120241-d4ba64b0b297/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  // Copyfile copies file to destination creating destination directory if needed
    55  func Copyfile(dst, src string) error {
    56  	err := mkdir(filepath.Dir(dst))
    57  	if err != nil {
    58  		return errors.Wrap(err, "copyfile: mkdirall")
    59  	}
    60  	r, err := os.Open(src)
    61  	if err != nil {
    62  		return errors.Wrapf(err, "copyfile: open(%q)", src)
    63  	}
    64  	defer r.Close()
    65  	w, err := os.Create(dst)
    66  	if err != nil {
    67  		return errors.Wrapf(err, "copyfile: create(%q)", dst)
    68  	}
    69  	defer w.Close()
    70  	if debugCopyfile {
    71  		fmt.Printf("copyfile(dst: %v, src: %v)\n", dst, src)
    72  	}
    73  	_, err = io.Copy(w, r)
    74  	return err
    75  }
    76  
    77  // RemoveAll removes path and any children it contains. Unlike os.RemoveAll it
    78  // deletes read only files on Windows.
    79  func RemoveAll(path string) error {
    80  	if runtime.GOOS == "windows" {
    81  		// Simple case: if Remove works, we're done.
    82  		err := os.Remove(path)
    83  		if err == nil || os.IsNotExist(err) {
    84  			return nil
    85  		}
    86  		// make sure all files are writable so we can delete them
    87  		filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
    88  			if err != nil {
    89  				// walk gave us some error, give it back.
    90  				return err
    91  			}
    92  			mode := info.Mode()
    93  			if mode|0200 == mode {
    94  				return nil
    95  			}
    96  			return os.Chmod(path, mode|0200)
    97  		})
    98  	}
    99  	return os.RemoveAll(path)
   100  }
   101  
   102  func mkdir(path string) error {
   103  	return os.MkdirAll(path, 0755)
   104  }