You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

fscopy.go 2.1KB

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