github.com/dougneal/terraform@v0.6.15-0.20170330092735-b6a3840768a4/helper/copy/copy.go (about)

     1  package copy
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  )
    10  
    11  // From: https://gist.github.com/m4ng0squ4sh/92462b38df26839a3ca324697c8cba04
    12  
    13  // CopyFile copies the contents of the file named src to the file named
    14  // by dst. The file will be created if it does not already exist. If the
    15  // destination file exists, all it's contents will be replaced by the contents
    16  // of the source file. The file mode will be copied from the source and
    17  // the copied data is synced/flushed to stable storage.
    18  func CopyFile(src, dst string) (err error) {
    19  	in, err := os.Open(src)
    20  	if err != nil {
    21  		return
    22  	}
    23  	defer in.Close()
    24  
    25  	out, err := os.Create(dst)
    26  	if err != nil {
    27  		return
    28  	}
    29  	defer func() {
    30  		if e := out.Close(); e != nil {
    31  			err = e
    32  		}
    33  	}()
    34  
    35  	_, err = io.Copy(out, in)
    36  	if err != nil {
    37  		return
    38  	}
    39  
    40  	err = out.Sync()
    41  	if err != nil {
    42  		return
    43  	}
    44  
    45  	si, err := os.Stat(src)
    46  	if err != nil {
    47  		return
    48  	}
    49  	err = os.Chmod(dst, si.Mode())
    50  	if err != nil {
    51  		return
    52  	}
    53  
    54  	return
    55  }
    56  
    57  // CopyDir recursively copies a directory tree, attempting to preserve permissions.
    58  // Source directory must exist, destination directory must *not* exist.
    59  // Symlinks are ignored and skipped.
    60  func CopyDir(src string, dst string) (err error) {
    61  	src = filepath.Clean(src)
    62  	dst = filepath.Clean(dst)
    63  
    64  	si, err := os.Stat(src)
    65  	if err != nil {
    66  		return err
    67  	}
    68  	if !si.IsDir() {
    69  		return fmt.Errorf("source is not a directory")
    70  	}
    71  
    72  	_, err = os.Stat(dst)
    73  	if err != nil && !os.IsNotExist(err) {
    74  		return
    75  	}
    76  	if err == nil {
    77  		return fmt.Errorf("destination already exists")
    78  	}
    79  
    80  	err = os.MkdirAll(dst, si.Mode())
    81  	if err != nil {
    82  		return
    83  	}
    84  
    85  	entries, err := ioutil.ReadDir(src)
    86  	if err != nil {
    87  		return
    88  	}
    89  
    90  	for _, entry := range entries {
    91  		srcPath := filepath.Join(src, entry.Name())
    92  		dstPath := filepath.Join(dst, entry.Name())
    93  
    94  		// If the entry is a symlink, we copy the contents
    95  		for entry.Mode()&os.ModeSymlink != 0 {
    96  			target, err := os.Readlink(srcPath)
    97  			if err != nil {
    98  				return err
    99  			}
   100  
   101  			entry, err = os.Stat(target)
   102  			if err != nil {
   103  				return err
   104  			}
   105  		}
   106  
   107  		if entry.IsDir() {
   108  			err = CopyDir(srcPath, dstPath)
   109  			if err != nil {
   110  				return
   111  			}
   112  		} else {
   113  			err = CopyFile(srcPath, dstPath)
   114  			if err != nil {
   115  				return
   116  			}
   117  		}
   118  	}
   119  
   120  	return
   121  }