github.com/solo-io/cue@v0.4.7/internal/copy/copy.go (about)

     1  // Copyright 2019 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package copy provides utilities to copy files and directories.
    16  package copy
    17  
    18  import (
    19  	"fmt"
    20  	"io"
    21  	"io/ioutil"
    22  	"os"
    23  	"path/filepath"
    24  )
    25  
    26  // File creates dst and copies the contents src to it.
    27  func File(src, dst string) error {
    28  	src = filepath.Clean(src)
    29  	dst = filepath.Clean(dst)
    30  
    31  	stat, err := os.Stat(src)
    32  	if err != nil {
    33  		return fmt.Errorf("copy file: %v", err)
    34  	}
    35  	err = copyFile(stat, src, dst)
    36  	if err != nil {
    37  		return fmt.Errorf("copy file: %v", err)
    38  	}
    39  	return nil
    40  }
    41  
    42  // Dir copies a src directory to its destination.
    43  func Dir(src, dst string) error {
    44  	src = filepath.Clean(src)
    45  	dst = filepath.Clean(dst)
    46  
    47  	stat, err := os.Stat(src)
    48  	if err != nil {
    49  		return fmt.Errorf("copy failed: %v", err)
    50  	} else if !stat.IsDir() {
    51  		return fmt.Errorf("copy failed: source is not a directory")
    52  	}
    53  
    54  	err = copyDir(stat, src, dst)
    55  	if err != nil {
    56  		return fmt.Errorf("copy failed: %v", err)
    57  	}
    58  	return nil
    59  }
    60  
    61  func copyDir(info os.FileInfo, src, dst string) error {
    62  	if _, err := os.Stat(dst); err != nil {
    63  		if !os.IsNotExist(err) {
    64  			return fmt.Errorf("dest err %s: %v", dst, err)
    65  		}
    66  		if err := os.MkdirAll(dst, info.Mode()); err != nil {
    67  			return fmt.Errorf("making dest %s: %v", dst, err)
    68  		}
    69  	}
    70  
    71  	entries, err := ioutil.ReadDir(src)
    72  	if err != nil {
    73  		return fmt.Errorf("reading dir %s: %v", src, err)
    74  	}
    75  
    76  	for _, e := range entries {
    77  		srcPath := filepath.Join(src, e.Name())
    78  		dstPath := filepath.Join(dst, e.Name())
    79  
    80  		switch mode := e.Mode(); mode & os.ModeType {
    81  		case os.ModeSymlink:
    82  			err = copySymLink(e, srcPath, dstPath)
    83  		case os.ModeDir:
    84  			err = copyDir(e, srcPath, dstPath)
    85  		default:
    86  			err = copyFile(e, srcPath, dstPath)
    87  		}
    88  		if err != nil {
    89  			return err
    90  		}
    91  	}
    92  	return nil
    93  }
    94  
    95  func copySymLink(info os.FileInfo, src, dst string) error {
    96  	mode := info.Mode()
    97  	link, err := os.Readlink(src)
    98  	if err != nil {
    99  		return err
   100  	}
   101  	err = os.Symlink(link, dst)
   102  	if err != nil {
   103  		return err
   104  	}
   105  	return os.Chmod(dst, mode)
   106  }
   107  
   108  func copyFile(info os.FileInfo, src, dst string) (err error) {
   109  	in, err := os.Open(src)
   110  	if err != nil {
   111  		return fmt.Errorf("error reading %s: %v", src, err)
   112  	}
   113  	defer in.Close()
   114  
   115  	out, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, info.Mode())
   116  	if err != nil {
   117  		return fmt.Errorf("error creating %s: %v", dst, err)
   118  	}
   119  	defer func() {
   120  		cErr := out.Close()
   121  		if err == nil {
   122  			err = cErr
   123  		}
   124  	}()
   125  
   126  	_, err = io.Copy(out, in)
   127  	if err != nil {
   128  		return fmt.Errorf("error copying %s: %v", dst, err)
   129  	}
   130  	return err
   131  }