From 9e845cb116ce6081443c70707aa6a76f4af3f9cf Mon Sep 17 00:00:00 2001 From: Deluan Date: Mon, 18 May 2020 14:37:01 -0400 Subject: [PATCH] Skip scanning folders if they contain a `.ndignore` file. Closes #297 --- consts/consts.go | 3 ++- scanner/change_detector.go | 22 ++++++++++++++-------- scanner/change_detector_test.go | 12 ++++++++++++ tests/fixtures/ignored_folder/.ndignore | 0 4 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 tests/fixtures/ignored_folder/.ndignore diff --git a/consts/consts.go b/consts/consts.go index d8f667bdd..1664dc514 100644 --- a/consts/consts.go +++ b/consts/consts.go @@ -28,7 +28,8 @@ const ( RequestThrottleBacklogLimit = 100 RequestThrottleBacklogTimeout = time.Minute - I18nFolder = "i18n" + I18nFolder = "i18n" + SkipScanFile = ".ndignore" ) // Cache options diff --git a/scanner/change_detector.go b/scanner/change_detector.go index 459975d0d..dc64d6eee 100644 --- a/scanner/change_detector.go +++ b/scanner/change_detector.go @@ -5,6 +5,7 @@ import ( "path/filepath" "time" + "github.com/deluan/navidrome/consts" "github.com/deluan/navidrome/log" ) @@ -66,7 +67,7 @@ func (s *ChangeDetector) loadDir(dirPath string) (children []string, lastUpdated if err != nil { continue } - if isDir { + if isDir && !IsDirIgnored(dirPath, f) { children = append(children, filepath.Join(dirPath, f.Name())) } else { if f.ModTime().After(lastUpdated) { @@ -77,24 +78,29 @@ func (s *ChangeDetector) loadDir(dirPath string) (children []string, lastUpdated return } -// IsDirOrSymlinkToDir returns true if and only if the Dirent represents a file -// system directory, or a symbolic link to a directory. Note that if the Dirent +// IsDirOrSymlinkToDir returns true if and only if the dirent represents a file +// system directory, or a symbolic link to a directory. Note that if the dirent // is not a directory but is a symbolic link, this method will resolve by // sending a request to the operating system to follow the symbolic link. // Copied from github.com/karrick/godirwalk -func IsDirOrSymlinkToDir(baseDir string, info os.FileInfo) (bool, error) { - if info.IsDir() { +func IsDirOrSymlinkToDir(baseDir string, dirent os.FileInfo) (bool, error) { + if dirent.IsDir() { return true, nil } - if info.Mode()&os.ModeSymlink == 0 { + if dirent.Mode()&os.ModeSymlink == 0 { return false, nil } // Does this symlink point to a directory? - info, err := os.Stat(filepath.Join(baseDir, info.Name())) + dirent, err := os.Stat(filepath.Join(baseDir, dirent.Name())) if err != nil { return false, err } - return info.IsDir(), nil + return dirent.IsDir(), nil +} + +func IsDirIgnored(baseDir string, dirent os.FileInfo) bool { + _, err := os.Stat(filepath.Join(baseDir, dirent.Name(), consts.SkipScanFile)) + return err == nil } func (s *ChangeDetector) loadMap(dirMap dirInfoMap, path string, since time.Time, maybe bool) error { diff --git a/scanner/change_detector_test.go b/scanner/change_detector_test.go index d68afb618..556e5806d 100644 --- a/scanner/change_detector_test.go +++ b/scanner/change_detector_test.go @@ -129,6 +129,18 @@ var _ = Describe("ChangeDetector", func() { Expect(IsDirOrSymlinkToDir("tests/fixtures", dir)).To(BeFalse()) }) }) + + Describe("IsDirIgnored", func() { + baseDir := filepath.Join("tests", "fixtures") + It("returns false for normal dirs", func() { + dir, _ := os.Stat(filepath.Join(baseDir, "empty_folder")) + Expect(IsDirIgnored(baseDir, dir)).To(BeFalse()) + }) + It("returns true when folder contains .ndignore file", func() { + dir, _ := os.Stat(filepath.Join(baseDir, "ignored_folder")) + Expect(IsDirIgnored(baseDir, dir)).To(BeTrue()) + }) + }) }) // I hate time-based tests.... diff --git a/tests/fixtures/ignored_folder/.ndignore b/tests/fixtures/ignored_folder/.ndignore new file mode 100644 index 000000000..e69de29bb