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 }