// Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package unittest import ( "errors" "io" "os" "path" "strings" "code.gitea.io/gitea/modules/util" ) // Copy copies file from source to target path. func Copy(src, dest string) error { // Gather file information to set back later. si, err := os.Lstat(src) if err != nil { return err } // Handle symbolic link. if si.Mode()&os.ModeSymlink != 0 { target, err := os.Readlink(src) if err != nil { return err } // NOTE: os.Chmod and os.Chtimes don't recognize symbolic link, // which will lead "no such file or directory" error. return os.Symlink(target, dest) } sr, err := os.Open(src) if err != nil { return err } defer sr.Close() dw, err := os.Create(dest) if err != nil { return err } defer dw.Close() if _, err = io.Copy(dw, sr); err != nil { return err } // Set back file information. if err = os.Chtimes(dest, si.ModTime(), si.ModTime()); err != nil { return err } return os.Chmod(dest, si.Mode()) } // CopyDir copy files recursively from source to target directory. // // The filter accepts a function that process the path info. // and should return true for need to filter. // // It returns error when error occurs in underlying functions. func CopyDir(srcPath, destPath string, filters ...func(filePath string) bool) error { // Check if target directory exists. if _, err := os.Stat(destPath); !errors.Is(err, os.ErrNotExist) { return util.NewAlreadyExistErrorf("file or directory already exists: %s", destPath) } err := os.MkdirAll(destPath, os.ModePerm) if err != nil { return err } // Gather directory info. infos, err := util.StatDir(srcPath, true) if err != nil { return err } var filter func(filePath string) bool if len(filters) > 0 { filter = filters[0] } for _, info := range infos { if filter != nil && filter(info) { continue } curPath := path.Join(destPath, info) if strings.HasSuffix(info, "/") { err = os.MkdirAll(curPath, os.ModePerm) } else { err = Copy(path.Join(srcPath, info), curPath) } if err != nil { return err } } return nil }