Skip to content

Commit

Permalink
sdist.exclude takes precedence over .gitignore
Browse files Browse the repository at this point in the history
Previously, sdist.exclude and the built-in EXCLUDE_LINES were prepended
to the list of .gitignore rules. However, a common pattern of using *
to exclude everything and then using !-rules to list what should be
included renders this feature useless.

This commit changes the behavior of each_unignored_file to sequentially
consider the following sets of independent rules:

1. Explicit inclusions
2. Explicit exclusions
3. Global exclusions from the .gitignore files
4. The built-in exclusions
5. Nested exclusions from .gitignore

Fixes #871
  • Loading branch information
alexreinking authored Aug 22, 2024
1 parent 26ca7ed commit 3f0bfb0
Showing 1 changed file with 15 additions and 5 deletions.
20 changes: 15 additions & 5 deletions src/scikit_build_core/build/_file_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,11 @@ def each_unignored_file(
"""
Runs through all non-ignored files. Must be run from the root directory.
"""
exclude_lines = EXCLUDE_LINES + list(exclude)

global_exclude_lines = []
for gi in [Path(".git/info/exclude"), Path(".gitignore")]:
ignore_errs = [FileNotFoundError, NotADirectoryError]
with contextlib.suppress(*ignore_errs), gi.open(encoding="utf-8") as f:
exclude_lines += f.readlines()
global_exclude_lines += f.readlines()

nested_excludes = {
p.parent: pathspec.GitIgnoreSpec.from_lines(
Expand All @@ -51,7 +50,10 @@ def each_unignored_file(
if p != Path(".gitignore")
}

exclude_spec = pathspec.GitIgnoreSpec.from_lines(exclude_lines)
user_exclude_spec = pathspec.GitIgnoreSpec.from_lines(list(exclude))
global_exclude_spec = pathspec.GitIgnoreSpec.from_lines(global_exclude_lines)
builtin_exclude_spec = pathspec.GitIgnoreSpec.from_lines(EXCLUDE_LINES)

include_spec = pathspec.GitIgnoreSpec.from_lines(include)

for dirstr, _, filenames in os.walk(str(starting_path), followlinks=True):
Expand All @@ -63,8 +65,16 @@ def each_unignored_file(
yield p
continue

# Always exclude something excluded
if user_exclude_spec.match_file(p):
continue

# Ignore from global ignore
if exclude_spec.match_file(p):
if global_exclude_spec.match_file(p):
continue

# Ignore built-in patterns
if builtin_exclude_spec.match_file(p):
continue

# Check relative ignores (Python 3.9's is_relative_to workaround)
Expand Down

0 comments on commit 3f0bfb0

Please sign in to comment.