github.com/chrislusf/greenpack@v3.7.1-0.20170911073826-ad5bd10b7c47+incompatible/cmd/addzid/cpfile.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"path"
     8  )
     9  
    10  // Cp implements a portable version of /bin/cp for use in golang
    11  // code that wants to work on many platforms. If the destinationPath
    12  // directory hierarchy does not exist, we will attempt to make it,
    13  // like mkdir -p would.
    14  func Cp(originPath, destinationPath string) (err error) {
    15  	if !FileExists(originPath) {
    16  		return fmt.Errorf("Cp error: source path '%s' does not exist", originPath)
    17  	}
    18  
    19  	var dirname, target string
    20  
    21  	ostat, err := os.Stat(originPath)
    22  	if err != nil {
    23  		return err
    24  	}
    25  	if !ostat.Mode().IsRegular() {
    26  		return fmt.Errorf("Cp: can only copy regular files, origin is '%s' of mode: '%s'", ostat.Name(), ostat.Mode().String())
    27  	}
    28  
    29  	if FileExists(destinationPath) {
    30  		// okay, good to go
    31  		//fmt.Printf("\n okay, destinationPath '%s' exists as a file\n", destinationPath)
    32  		dirname = path.Dir(destinationPath)
    33  		target = path.Base(destinationPath)
    34  	} else {
    35  		// no such file yet
    36  		//fmt.Printf("\n okay, destinationPath '%s': no such file yet.\n", destinationPath)
    37  
    38  		// set dirname and target
    39  
    40  		// do we end in "/" or "\"?
    41  		if IsDirPath(destinationPath) {
    42  			dirname = destinationPath
    43  			target = path.Base(originPath)
    44  		} else {
    45  			// the final path component is taken to be the target file name, unless
    46  			// it names an existing directory.
    47  			if DirExists(destinationPath) {
    48  				//fmt.Printf("\n okay, destinationPath '%s' exists as a directory\n", destinationPath)
    49  				dirname = path.Dir(destinationPath)
    50  				target = path.Base(originPath)
    51  
    52  			} else {
    53  				dirname = path.Dir(destinationPath)
    54  				target = path.Base(destinationPath)
    55  			}
    56  		}
    57  
    58  		//fmt.Printf("\n dirname = '%s'   target = '%s'\n", dirname, target)
    59  
    60  		// is it a directory that exists?
    61  		if DirExists(dirname) {
    62  			//fmt.Printf("\n okay, dirname '%s' exists as a directory\n", dirname)
    63  		} else {
    64  			//fmt.Printf("\n okay, dirname '%s' is not an existing directory, try to make needed directories\n", dirname)
    65  			// dirname is not an existing directory, try to mkdir -p make the needed dirs.
    66  
    67  			err = os.MkdirAll(dirname, 0755)
    68  			if err != nil {
    69  				return fmt.Errorf("could not create destination directory path(s) with MkdirAll on '%s', error: '%s'", dirname, err)
    70  			} else {
    71  				//fmt.Printf("\n made dirname: '%s'\n", dirname)
    72  			}
    73  		}
    74  
    75  	}
    76  	// INVAR: we should be good to copy to dirname
    77  	//fmt.Printf("\n INVAR: we should be good to copy to dirname: '%s'\n", dirname)
    78  
    79  	fullpath := appendFilename(dirname, target)
    80  
    81  	dstat, err := os.Stat(fullpath)
    82  	if err != nil {
    83  		if !os.IsNotExist(err) {
    84  			return err
    85  		}
    86  	} else {
    87  		// we have an existing file, don't bother writing atop ourselves.
    88  		if os.SameFile(ostat, dstat) {
    89  			return nil // don't error out here, the copy is actually already done.
    90  		}
    91  	}
    92  
    93  	// proceed to copy
    94  	//fmt.Printf("os.Open with originPath = '%s'\n", originPath)
    95  	src, err := os.Open(originPath)
    96  	if err != nil {
    97  		return err
    98  	}
    99  	defer src.Close()
   100  
   101  	//fmt.Printf("os.Create with fullpath = '%s'\n", fullpath)
   102  	dest, err := os.Create(fullpath)
   103  	if err != nil {
   104  		//fmt.Printf("returning early after attempt os.Create with fullpath = '%s'\n", fullpath)
   105  		return err
   106  	}
   107  	defer func() {
   108  		closeError := dest.Close()
   109  		// only substitute closeError if there was
   110  		// no previous earlier error
   111  		if err == nil {
   112  			err = closeError
   113  		}
   114  	}()
   115  	_, err = io.Copy(dest, src)
   116  	if err != nil {
   117  		return err
   118  	}
   119  	return nil
   120  }
   121  
   122  func appendFilename(dir, fn string) string {
   123  	// but don't double // or \\ it
   124  	if IsDirPath(dir) {
   125  		return dir + fn
   126  	}
   127  	return dir + string(os.PathSeparator) + fn
   128  }
   129  
   130  func IsDirPath(dir string) bool {
   131  	n := len(dir)
   132  	if n == 0 {
   133  		return false
   134  	}
   135  	if dir[n-1] == os.PathSeparator {
   136  		return true
   137  	}
   138  	return false
   139  }