directory.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package sources
  2. import (
  3. "github.com/rs/zerolog/log"
  4. "io/fs"
  5. "os"
  6. "path/filepath"
  7. "github.com/fatih/semgroup"
  8. )
  9. type ScanTarget struct {
  10. Path string
  11. Symlink string
  12. }
  13. func DirectoryTargets(source string, s *semgroup.Group, followSymlinks bool) (<-chan ScanTarget, error) {
  14. paths := make(chan ScanTarget)
  15. s.Go(func() error {
  16. defer close(paths)
  17. return filepath.Walk(source,
  18. func(path string, fInfo os.FileInfo, err error) error {
  19. logger := log.With().Str("path", path).Logger()
  20. if err != nil {
  21. if os.IsPermission(err) {
  22. // This seems to only fail on directories at this stage.
  23. logger.Warn().Msg("Skipping directory: permission denied")
  24. return filepath.SkipDir
  25. }
  26. return err
  27. }
  28. if fInfo.Name() == ".git" && fInfo.IsDir() {
  29. return filepath.SkipDir
  30. }
  31. if fInfo.Size() == 0 {
  32. return nil
  33. }
  34. if fInfo.Mode().IsRegular() {
  35. paths <- ScanTarget{
  36. Path: path,
  37. Symlink: "",
  38. }
  39. }
  40. if fInfo.Mode().Type() == fs.ModeSymlink {
  41. if !followSymlinks {
  42. log.Debug().Str("path", path).Msg("Skipping symlink")
  43. return nil
  44. }
  45. realPath, err := filepath.EvalSymlinks(path)
  46. if err != nil {
  47. return err
  48. }
  49. realPathFileInfo, _ := os.Stat(realPath)
  50. if realPathFileInfo.IsDir() {
  51. log.Debug().Msgf("found symlinked directory: %s -> %s [skipping]", path, realPath)
  52. return nil
  53. }
  54. paths <- ScanTarget{
  55. Path: realPath,
  56. Symlink: path,
  57. }
  58. }
  59. return nil
  60. })
  61. })
  62. return paths, nil
  63. }