code.gitea.io/gitea@v1.21.7/models/unittest/fscopy.go (about)

     1  // Copyright 2022 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package unittest
     5  
     6  import (
     7  	"errors"
     8  	"io"
     9  	"os"
    10  	"path"
    11  	"strings"
    12  
    13  	"code.gitea.io/gitea/modules/util"
    14  )
    15  
    16  // Copy copies file from source to target path.
    17  func Copy(src, dest string) error {
    18  	// Gather file information to set back later.
    19  	si, err := os.Lstat(src)
    20  	if err != nil {
    21  		return err
    22  	}
    23  
    24  	// Handle symbolic link.
    25  	if si.Mode()&os.ModeSymlink != 0 {
    26  		target, err := os.Readlink(src)
    27  		if err != nil {
    28  			return err
    29  		}
    30  		// NOTE: os.Chmod and os.Chtimes don't recognize symbolic link,
    31  		// which will lead "no such file or directory" error.
    32  		return os.Symlink(target, dest)
    33  	}
    34  
    35  	sr, err := os.Open(src)
    36  	if err != nil {
    37  		return err
    38  	}
    39  	defer sr.Close()
    40  
    41  	dw, err := os.Create(dest)
    42  	if err != nil {
    43  		return err
    44  	}
    45  	defer dw.Close()
    46  
    47  	if _, err = io.Copy(dw, sr); err != nil {
    48  		return err
    49  	}
    50  
    51  	// Set back file information.
    52  	if err = os.Chtimes(dest, si.ModTime(), si.ModTime()); err != nil {
    53  		return err
    54  	}
    55  	return os.Chmod(dest, si.Mode())
    56  }
    57  
    58  // CopyDir copy files recursively from source to target directory.
    59  //
    60  // The filter accepts a function that process the path info.
    61  // and should return true for need to filter.
    62  //
    63  // It returns error when error occurs in underlying functions.
    64  func CopyDir(srcPath, destPath string, filters ...func(filePath string) bool) error {
    65  	// Check if target directory exists.
    66  	if _, err := os.Stat(destPath); !errors.Is(err, os.ErrNotExist) {
    67  		return util.NewAlreadyExistErrorf("file or directory already exists: %s", destPath)
    68  	}
    69  
    70  	err := os.MkdirAll(destPath, os.ModePerm)
    71  	if err != nil {
    72  		return err
    73  	}
    74  
    75  	// Gather directory info.
    76  	infos, err := util.StatDir(srcPath, true)
    77  	if err != nil {
    78  		return err
    79  	}
    80  
    81  	var filter func(filePath string) bool
    82  	if len(filters) > 0 {
    83  		filter = filters[0]
    84  	}
    85  
    86  	for _, info := range infos {
    87  		if filter != nil && filter(info) {
    88  			continue
    89  		}
    90  
    91  		curPath := path.Join(destPath, info)
    92  		if strings.HasSuffix(info, "/") {
    93  			err = os.MkdirAll(curPath, os.ModePerm)
    94  		} else {
    95  			err = Copy(path.Join(srcPath, info), curPath)
    96  		}
    97  		if err != nil {
    98  			return err
    99  		}
   100  	}
   101  	return nil
   102  }