From 5a6329cc343a16df1b0441fc6d1932b6aed68edd Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Thu, 31 Jul 2025 16:06:53 -0300 Subject: [PATCH] feat: support .crushignore as well as .gitignore Signed-off-by: Carlos Alexandro Becker --- internal/fsext/fileutil.go | 27 ++++++++++++++++++--- internal/fsext/ignore_test.go | 44 +++++++++++++++++++++++++++++++++++ internal/fsext/ls.go | 14 +++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 internal/fsext/ignore_test.go diff --git a/internal/fsext/fileutil.go b/internal/fsext/fileutil.go index 462dcc67..a5b23c5b 100644 --- a/internal/fsext/fileutil.go +++ b/internal/fsext/fileutil.go @@ -107,8 +107,9 @@ func SkipHidden(path string) bool { // FastGlobWalker provides gitignore-aware file walking with fastwalk type FastGlobWalker struct { - gitignore *ignore.GitIgnore - rootPath string + gitignore *ignore.GitIgnore + crushignore *ignore.GitIgnore + rootPath string } func NewFastGlobWalker(searchPath string) *FastGlobWalker { @@ -124,6 +125,14 @@ func NewFastGlobWalker(searchPath string) *FastGlobWalker { } } + // Load crushignore if it exists + crushignorePath := filepath.Join(searchPath, ".crushignore") + if _, err := os.Stat(crushignorePath); err == nil { + if ci, err := ignore.CompileIgnoreFile(crushignorePath); err == nil { + walker.crushignore = ci + } + } + return walker } @@ -132,13 +141,25 @@ func (w *FastGlobWalker) shouldSkip(path string) bool { return true } + relPath, err := filepath.Rel(w.rootPath, path) + if err != nil { + relPath = path + } + + // Check gitignore patterns if available if w.gitignore != nil { - relPath, err := filepath.Rel(w.rootPath, path) if err == nil && w.gitignore.MatchesPath(relPath) { return true } } + // Check crushignore patterns if available + if w.crushignore != nil { + if err == nil && w.crushignore.MatchesPath(relPath) { + return true + } + } + return false } diff --git a/internal/fsext/ignore_test.go b/internal/fsext/ignore_test.go new file mode 100644 index 00000000..668e8383 --- /dev/null +++ b/internal/fsext/ignore_test.go @@ -0,0 +1,44 @@ +package fsext + +import ( + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCrushIgnore(t *testing.T) { + // Create a temporary directory for testing + tempDir := t.TempDir() + + // Change to temp directory + oldWd, _ := os.Getwd() + err := os.Chdir(tempDir) + require.NoError(t, err) + defer os.Chdir(oldWd) + + // Create test files + require.NoError(t, os.WriteFile("test1.txt", []byte("test"), 0644)) + require.NoError(t, os.WriteFile("test2.log", []byte("test"), 0644)) + require.NoError(t, os.WriteFile("test3.tmp", []byte("test"), 0644)) + + // Create a .crushignore file that ignores .log files + require.NoError(t, os.WriteFile(".crushignore", []byte("*.log\n"), 0644)) + + // Test DirectoryLister + t.Run("DirectoryLister respects .crushignore", func(t *testing.T) { + dl := NewDirectoryLister(tempDir) + + // Test that .log files are ignored + require.True(t, dl.gitignore == nil, "gitignore should be nil") + require.NotNil(t, dl.crushignore, "crushignore should not be nil") + }) + + // Test FastGlobWalker + t.Run("FastGlobWalker respects .crushignore", func(t *testing.T) { + walker := NewFastGlobWalker(tempDir) + + require.True(t, walker.gitignore == nil, "gitignore should be nil") + require.NotNil(t, walker.crushignore, "crushignore should not be nil") + }) +} \ No newline at end of file diff --git a/internal/fsext/ls.go b/internal/fsext/ls.go index 2c08fd1c..e800e921 100644 --- a/internal/fsext/ls.go +++ b/internal/fsext/ls.go @@ -68,6 +68,7 @@ var CommonIgnorePatterns = []string{ type DirectoryLister struct { gitignore *ignore.GitIgnore + crushignore *ignore.GitIgnore commonIgnore *ignore.GitIgnore rootPath string } @@ -85,6 +86,14 @@ func NewDirectoryLister(rootPath string) *DirectoryLister { } } + // Load crushignore if it exists + crushignorePath := filepath.Join(rootPath, ".crushignore") + if _, err := os.Stat(crushignorePath); err == nil { + if ci, err := ignore.CompileIgnoreFile(crushignorePath); err == nil { + dl.crushignore = ci + } + } + // Create common ignore patterns dl.commonIgnore = ignore.CompileIgnoreLines(CommonIgnorePatterns...) @@ -107,6 +116,11 @@ func (dl *DirectoryLister) shouldIgnore(path string, ignorePatterns []string) bo return true } + // Check crushignore patterns if available + if dl.crushignore != nil && dl.crushignore.MatchesPath(relPath) { + return true + } + base := filepath.Base(path) for _, pattern := range ignorePatterns {