mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-15 12:14:52 +00:00
Gitignore: fix handling of anchored ignores
Previously anchored ignores would be erroneosly ingored everywhere
This commit is contained in:
1 parent
40b9a246f0
commit
0c5a98236f
2 files changed
+135
-3
No files matched your search
@@ -225,7 +225,13 @@ class GitignoreParser:
|
||||
# Add the directory prefix but also allow matching in subdirectories
|
||||
adjusted_pattern = os.path.join(rel_dir, "**", line)
|
||||
else:
|
||||
adjusted_pattern = line
|
||||
if is_anchored:
|
||||
# Anchored patterns in root should only match at root level
|
||||
# Add leading slash back to indicate root-only matching
|
||||
adjusted_pattern = "/" + line
|
||||
else:
|
||||
# Non-anchored patterns can match anywhere
|
||||
adjusted_pattern = line
|
||||
|
||||
# Re-add negation if needed
|
||||
if is_negation:
|
||||
@@ -251,9 +257,14 @@ class GitignoreParser:
|
||||
else:
|
||||
rel_path = path
|
||||
|
||||
abs_path = os.path.join(self.repo_root, rel_path)
|
||||
|
||||
# Normalize path separators
|
||||
rel_path = rel_path.replace(os.sep, "/")
|
||||
|
||||
if os.path.exists(abs_path) and os.path.isdir(abs_path) and not rel_path.endswith("/"):
|
||||
rel_path = rel_path + "/"
|
||||
|
||||
# Check against each ignore spec
|
||||
for spec in self.ignore_specs:
|
||||
if spec.matches(rel_path):
|
||||
|
||||
@@ -133,7 +133,7 @@ build/
|
||||
|
||||
assert "*.log" in patterns
|
||||
assert "build/" in patterns
|
||||
assert "temp.txt" in patterns
|
||||
assert "/temp.txt" in patterns
|
||||
|
||||
def test_parse_patterns_subdirectory(self):
|
||||
"""Test parsing gitignore patterns in subdirectory."""
|
||||
@@ -227,6 +227,127 @@ data.json
|
||||
assert parser.should_ignore("src/subdir/data.json")
|
||||
assert parser.should_ignore("src/subdir/deep/data.json")
|
||||
|
||||
def test_root_anchored_patterns(self):
|
||||
"""Test anchored patterns in root .gitignore only match root-level files."""
|
||||
# Create new test structure for root anchored patterns
|
||||
test_dir = self.repo_path / "test_root_anchored"
|
||||
test_dir.mkdir()
|
||||
(test_dir / "src").mkdir()
|
||||
(test_dir / "docs").mkdir()
|
||||
(test_dir / "src" / "nested").mkdir()
|
||||
|
||||
# Create root .gitignore with anchored patterns
|
||||
gitignore = test_dir / ".gitignore"
|
||||
gitignore.write_text(
|
||||
"""/config.json
|
||||
/temp.log
|
||||
/build
|
||||
*.pyc
|
||||
"""
|
||||
)
|
||||
|
||||
# Create test files at root level
|
||||
(test_dir / "config.json").touch()
|
||||
(test_dir / "temp.log").touch()
|
||||
(test_dir / "build").mkdir()
|
||||
(test_dir / "file.pyc").touch()
|
||||
|
||||
# Create same-named files in subdirectories
|
||||
(test_dir / "src" / "config.json").touch()
|
||||
(test_dir / "src" / "temp.log").touch()
|
||||
(test_dir / "src" / "build").mkdir()
|
||||
(test_dir / "src" / "file.pyc").touch()
|
||||
(test_dir / "docs" / "config.json").touch()
|
||||
(test_dir / "docs" / "temp.log").touch()
|
||||
(test_dir / "src" / "nested" / "config.json").touch()
|
||||
(test_dir / "src" / "nested" / "temp.log").touch()
|
||||
(test_dir / "src" / "nested" / "build").mkdir()
|
||||
|
||||
parser = GitignoreParser(str(test_dir))
|
||||
|
||||
# Anchored patterns should only match root-level files
|
||||
assert parser.should_ignore("config.json")
|
||||
assert not parser.should_ignore("src/config.json")
|
||||
assert not parser.should_ignore("docs/config.json")
|
||||
assert not parser.should_ignore("src/nested/config.json")
|
||||
|
||||
assert parser.should_ignore("temp.log")
|
||||
assert not parser.should_ignore("src/temp.log")
|
||||
assert not parser.should_ignore("docs/temp.log")
|
||||
assert not parser.should_ignore("src/nested/temp.log")
|
||||
|
||||
assert parser.should_ignore("build")
|
||||
assert not parser.should_ignore("src/build")
|
||||
assert not parser.should_ignore("src/nested/build")
|
||||
|
||||
# Non-anchored patterns should match everywhere
|
||||
assert parser.should_ignore("file.pyc")
|
||||
assert parser.should_ignore("src/file.pyc")
|
||||
|
||||
def test_mixed_anchored_and_non_anchored_root_patterns(self):
|
||||
"""Test mix of anchored and non-anchored patterns in root .gitignore."""
|
||||
test_dir = self.repo_path / "test_mixed_patterns"
|
||||
test_dir.mkdir()
|
||||
(test_dir / "app").mkdir()
|
||||
(test_dir / "tests").mkdir()
|
||||
(test_dir / "app" / "modules").mkdir()
|
||||
|
||||
# Create root .gitignore with mixed patterns
|
||||
gitignore = test_dir / ".gitignore"
|
||||
gitignore.write_text(
|
||||
"""/secrets.env
|
||||
/dist/
|
||||
node_modules/
|
||||
*.tmp
|
||||
/app/local.config
|
||||
debug.log
|
||||
"""
|
||||
)
|
||||
|
||||
# Create test files and directories
|
||||
(test_dir / "secrets.env").touch()
|
||||
(test_dir / "dist").mkdir()
|
||||
(test_dir / "node_modules").mkdir()
|
||||
(test_dir / "file.tmp").touch()
|
||||
(test_dir / "app" / "local.config").touch()
|
||||
(test_dir / "debug.log").touch()
|
||||
|
||||
# Create same files in subdirectories
|
||||
(test_dir / "app" / "secrets.env").touch()
|
||||
(test_dir / "app" / "dist").mkdir()
|
||||
(test_dir / "app" / "node_modules").mkdir()
|
||||
(test_dir / "app" / "file.tmp").touch()
|
||||
(test_dir / "app" / "debug.log").touch()
|
||||
(test_dir / "tests" / "secrets.env").touch()
|
||||
(test_dir / "tests" / "node_modules").mkdir()
|
||||
(test_dir / "tests" / "debug.log").touch()
|
||||
(test_dir / "app" / "modules" / "local.config").touch()
|
||||
|
||||
parser = GitignoreParser(str(test_dir))
|
||||
|
||||
# Anchored patterns should only match at root
|
||||
assert parser.should_ignore("secrets.env")
|
||||
assert not parser.should_ignore("app/secrets.env")
|
||||
assert not parser.should_ignore("tests/secrets.env")
|
||||
|
||||
assert parser.should_ignore("dist")
|
||||
assert not parser.should_ignore("app/dist")
|
||||
|
||||
assert parser.should_ignore("app/local.config")
|
||||
assert not parser.should_ignore("app/modules/local.config")
|
||||
|
||||
# Non-anchored patterns should match everywhere
|
||||
assert parser.should_ignore("node_modules")
|
||||
assert parser.should_ignore("app/node_modules")
|
||||
assert parser.should_ignore("tests/node_modules")
|
||||
|
||||
assert parser.should_ignore("file.tmp")
|
||||
assert parser.should_ignore("app/file.tmp")
|
||||
|
||||
assert parser.should_ignore("debug.log")
|
||||
assert parser.should_ignore("app/debug.log")
|
||||
assert parser.should_ignore("tests/debug.log")
|
||||
|
||||
def test_negation_patterns(self):
|
||||
"""Test negation patterns are parsed correctly."""
|
||||
test_dir = self.repo_path / "test_negation"
|
||||
@@ -248,7 +369,7 @@ data.json
|
||||
|
||||
assert "*.log" in patterns
|
||||
assert "!important.log" in patterns
|
||||
assert "!src/keep.log" in patterns
|
||||
assert "!/src/keep.log" in patterns
|
||||
|
||||
def test_comments_and_empty_lines(self):
|
||||
"""Test that comments and empty lines are ignored."""
|
||||
|
||||
Reference in new issue
Block a user