go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/projects/blogctl/pkg/engine/copy.go (about)

     1  /*
     2  
     3  Copyright (c) 2023 - Present. Will Charczuk. All rights reserved.
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository.
     5  
     6  */
     7  
     8  package engine
     9  
    10  import (
    11  	"io"
    12  	"io/ioutil"
    13  	"os"
    14  	"path/filepath"
    15  )
    16  
    17  // Copy copies src to dest, doesn't matter if src is a directory or a file
    18  func Copy(src, dest string) error {
    19  	info, err := os.Lstat(src)
    20  	if err != nil {
    21  		return err
    22  	}
    23  	return copy(src, dest, info)
    24  }
    25  
    26  // copy dispatches copy-funcs according to the mode.
    27  // Because this "copy" could be called recursively,
    28  // "info" MUST be given here, NOT nil.
    29  func copy(src, dest string, info os.FileInfo) error {
    30  	if info.Mode()&os.ModeSymlink != 0 {
    31  		return lcopy(src, dest, info)
    32  	}
    33  	if info.IsDir() {
    34  		return dcopy(src, dest, info)
    35  	}
    36  	return fcopy(src, dest, info)
    37  }
    38  
    39  // fcopy is for just a file,
    40  // with considering existence of parent directory
    41  // and file permission.
    42  func fcopy(src, dest string, info os.FileInfo) error {
    43  	if err := os.MkdirAll(filepath.Dir(dest), os.ModePerm); err != nil {
    44  		return err
    45  	}
    46  
    47  	f, err := os.Create(dest)
    48  	if err != nil {
    49  		return err
    50  	}
    51  	defer f.Close()
    52  
    53  	if err = os.Chmod(f.Name(), info.Mode()); err != nil {
    54  		return err
    55  	}
    56  
    57  	s, err := os.Open(src)
    58  	if err != nil {
    59  		return err
    60  	}
    61  	defer s.Close()
    62  
    63  	_, err = io.Copy(f, s)
    64  	return err
    65  }
    66  
    67  // dcopy is for a directory,
    68  // with scanning contents inside the directory
    69  // and pass everything to "copy" recursively.
    70  func dcopy(srcdir, destdir string, info os.FileInfo) error {
    71  	if err := os.MkdirAll(destdir, info.Mode()); err != nil {
    72  		return err
    73  	}
    74  
    75  	contents, err := ioutil.ReadDir(srcdir)
    76  	if err != nil {
    77  		return err
    78  	}
    79  
    80  	for _, content := range contents {
    81  		cs, cd := filepath.Join(srcdir, content.Name()), filepath.Join(destdir, content.Name())
    82  		if err := copy(cs, cd, content); err != nil {
    83  			return err
    84  		}
    85  	}
    86  	return nil
    87  }
    88  
    89  // lcopy is for a symlink,
    90  // with just creating a new symlink by replicating src symlink.
    91  func lcopy(src, dest string, _ os.FileInfo) error {
    92  	src, err := os.Readlink(src)
    93  	if err != nil {
    94  		return err
    95  	}
    96  	return os.Symlink(src, dest)
    97  }