github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/f/copy.go (about)

     1  package f
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"path/filepath"
     8  	"reflect"
     9  	"time"
    10  )
    11  
    12  // CopyInterface for delegating copy process to type
    13  type CopyInterface interface {
    14  	Copy() interface{}
    15  }
    16  
    17  // CloneInterface for delegating copy process to type
    18  type CloneInterface interface {
    19  	Clone() interface{}
    20  }
    21  
    22  // Copy create a deep copy of whatever is passed to it and returns the copy
    23  // in an interface{}.  The returned value will need to be asserted to the correct type.
    24  func Clone(src interface{}) interface{} {
    25  	if src == nil {
    26  		return nil
    27  	}
    28  
    29  	// Make the interface a reflect.Value
    30  	original := reflect.ValueOf(src)
    31  
    32  	// Make a copy of the same type as the original.
    33  	cpy := reflect.New(original.Type()).Elem()
    34  
    35  	// Recursively copy the original.
    36  	copyRecursive(original, cpy)
    37  
    38  	// Return the copy as an interface.
    39  	return cpy.Interface()
    40  }
    41  
    42  // copyRecursive does the actual copying of the interface. It currently has
    43  // limited support for what it can handle. Add as needed.
    44  func copyRecursive(original, cpy reflect.Value) {
    45  	// check for implement CloneInterface
    46  	if original.CanInterface() {
    47  		if copier, ok := original.Interface().(CopyInterface); ok {
    48  			cpy.Set(reflect.ValueOf(copier.Copy()))
    49  			return
    50  		}
    51  		if copier, ok := original.Interface().(CloneInterface); ok {
    52  			cpy.Set(reflect.ValueOf(copier.Clone()))
    53  			return
    54  		}
    55  	}
    56  
    57  	// handle according to original's Kind
    58  	switch original.Kind() {
    59  	case reflect.Ptr:
    60  		// GetHeader the actual value being pointed to.
    61  		originalValue := original.Elem()
    62  
    63  		// if  it isn't valid, return.
    64  		if !originalValue.IsValid() {
    65  			return
    66  		}
    67  		cpy.Set(reflect.New(originalValue.Type()))
    68  		copyRecursive(originalValue, cpy.Elem())
    69  
    70  	case reflect.Interface:
    71  		// If this is a nil, don't do anything
    72  		if original.IsNil() {
    73  			return
    74  		}
    75  		// GetHeader the value for the interface, not the pointer.
    76  		originalValue := original.Elem()
    77  
    78  		// GetHeader the value by calling Elem().
    79  		copyValue := reflect.New(originalValue.Type()).Elem()
    80  		copyRecursive(originalValue, copyValue)
    81  		cpy.Set(copyValue)
    82  
    83  	case reflect.Struct:
    84  		t, ok := original.Interface().(time.Time)
    85  		if ok {
    86  			cpy.Set(reflect.ValueOf(t))
    87  			return
    88  		}
    89  		// Go through each field of the struct and copy it.
    90  		for i := 0; i < original.NumField(); i++ {
    91  			// The Type's StructField for a given field is checked to see if StructField.PkgPath
    92  			// is set to determine if the field is exported or not because CanSet() returns false
    93  			// for settable fields.  I'm not sure why.
    94  			if original.Type().Field(i).PkgPath != "" {
    95  				continue
    96  			}
    97  			copyRecursive(original.Field(i), cpy.Field(i))
    98  		}
    99  
   100  	case reflect.Slice:
   101  		if original.IsNil() {
   102  			return
   103  		}
   104  		// Make a new slice and copy each element.
   105  		cpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap()))
   106  		for i := 0; i < original.Len(); i++ {
   107  			copyRecursive(original.Index(i), cpy.Index(i))
   108  		}
   109  
   110  	case reflect.Map:
   111  		if original.IsNil() {
   112  			return
   113  		}
   114  		cpy.Set(reflect.MakeMap(original.Type()))
   115  		for _, key := range original.MapKeys() {
   116  			originalValue := original.MapIndex(key)
   117  			copyValue := reflect.New(originalValue.Type()).Elem()
   118  			copyRecursive(originalValue, copyValue)
   119  			copyKey := Clone(key.Interface())
   120  			cpy.SetMapIndex(reflect.ValueOf(copyKey), copyValue)
   121  		}
   122  
   123  	default:
   124  		cpy.Set(original)
   125  	}
   126  }
   127  
   128  // Copy recursively copies the file, directory or symbolic link at src
   129  // to dst. The destination must not exist. Symbolic links are not
   130  // followed.
   131  //
   132  // If the copy fails half way through, the destination might be left
   133  // partially written.
   134  func Copy(srcFile, dstFile string) error {
   135  	srcInfo, srcErr := os.Lstat(srcFile)
   136  	if srcErr != nil {
   137  		return srcErr
   138  	}
   139  	_, dstErr := os.Lstat(dstFile)
   140  	if dstErr == nil {
   141  		return fmt.Errorf("will not overwrite %q", dstFile)
   142  	}
   143  	if !os.IsNotExist(dstErr) {
   144  		return dstErr
   145  	}
   146  	switch mode := srcInfo.Mode(); mode & os.ModeType {
   147  	case os.ModeSymlink:
   148  		return CopySymLink(srcFile, dstFile)
   149  	case os.ModeDir:
   150  		return CopyDir(srcFile, dstFile, mode)
   151  	case 0:
   152  		return CopyFile(srcFile, dstFile, mode)
   153  	default:
   154  		return fmt.Errorf("cannot copy file with mode %v", mode)
   155  	}
   156  }
   157  
   158  func CopySymLink(srcFile, dstFile string) error {
   159  	target, err := os.Readlink(srcFile)
   160  	if err != nil {
   161  		return err
   162  	}
   163  	return os.Symlink(target, dstFile)
   164  }
   165  
   166  func CopyFile(src, dst string, mode os.FileMode) error {
   167  	srcFile, err := os.Open(src)
   168  	if err != nil {
   169  		return err
   170  	}
   171  	defer srcFile.Close()
   172  	dstFile, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode.Perm())
   173  	if err != nil {
   174  		return err
   175  	}
   176  	defer dstFile.Close()
   177  	// Make the actual permissions match the source permissions
   178  	// even in the presence of umask.
   179  	if err := os.Chmod(dstFile.Name(), mode.Perm()); err != nil {
   180  		return err
   181  	}
   182  	if _, err := io.Copy(dstFile, srcFile); err != nil {
   183  		return fmt.Errorf("cannot copy %q to %q: %v", src, dst, err)
   184  	}
   185  	return nil
   186  }
   187  
   188  // CopyDir copy directory.
   189  func CopyDir(src, dst string, mode os.FileMode) error {
   190  	srcFile, err := os.Open(src)
   191  	if err != nil {
   192  		return err
   193  	}
   194  	defer srcFile.Close()
   195  	if mode&0500 == 0 {
   196  		// The source directory doesn't have write permission,
   197  		// so give the new directory write permission anyway
   198  		// so that we have permission to create its contents.
   199  		// We'll make the permissions match at the end.
   200  		mode |= 0500
   201  	}
   202  	if err := os.Mkdir(dst, mode.Perm()); err != nil {
   203  		return err
   204  	}
   205  	for {
   206  		names, err := srcFile.Readdirnames(100)
   207  		for _, name := range names {
   208  			if err := Copy(filepath.Join(src, name), filepath.Join(dst, name)); err != nil {
   209  				return err
   210  			}
   211  		}
   212  		if err == io.EOF {
   213  			break
   214  		}
   215  		if err != nil {
   216  			return fmt.Errorf("error reading directory %q: %v", src, err)
   217  		}
   218  	}
   219  	if err := os.Chmod(dst, mode.Perm()); err != nil {
   220  		return err
   221  	}
   222  	return nil
   223  }