-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make --exclude only apply to recursively found files #1591
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -586,6 +586,7 @@ def get_sources( | |
exclude_regexes = [exclude_regex] | ||
if force_exclude_regex is not None: | ||
exclude_regexes.append(force_exclude_regex) | ||
gitignore = get_gitignore(root) | ||
|
||
for s in src: | ||
p = Path(s) | ||
|
@@ -597,17 +598,27 @@ def get_sources( | |
include_regex, | ||
exclude_regexes, | ||
report, | ||
get_gitignore(root), | ||
gitignore, | ||
) | ||
) | ||
elif s == "-": | ||
sources.add(p) | ||
elif p.is_file(): | ||
sources.update( | ||
gen_python_files( | ||
[p], root, None, exclude_regexes, report, get_gitignore(root) | ||
) | ||
) | ||
# Hard-exclude any files that matches the `--force-exclude` regex. | ||
normalized_path = normalize_path_maybe_ignore(p, root, report) | ||
if normalized_path is None: | ||
continue | ||
|
||
normalized_path = "/" + normalized_path | ||
if force_exclude_regex: | ||
force_exclude_match = force_exclude_regex.search(normalized_path) | ||
else: | ||
force_exclude_match = None | ||
if force_exclude_match and force_exclude_match.group(0): | ||
report.path_ignored(p, "matches the --force-exclude regular expression") | ||
continue | ||
|
||
sources.add(p) | ||
else: | ||
err(f"invalid path: {s}") | ||
return sources | ||
|
@@ -5759,6 +5770,29 @@ def get_gitignore(root: Path) -> PathSpec: | |
return PathSpec.from_lines("gitwildmatch", lines) | ||
|
||
|
||
def normalize_path_maybe_ignore( | ||
path: Path, root: Path, report: "Report" | ||
) -> Optional[str]: | ||
"""Normalize `path`. May return `None` if `path` was ignored. | ||
|
||
`report` is where "path ignored" output goes. | ||
""" | ||
try: | ||
normalized_path = path.resolve().relative_to(root).as_posix() | ||
except OSError as e: | ||
report.path_ignored(path, f"cannot be read because {e}") | ||
return None | ||
|
||
except ValueError: | ||
if path.is_symlink(): | ||
report.path_ignored(path, f"is a symbolic link that points outside {root}") | ||
return None | ||
|
||
raise | ||
|
||
return normalized_path | ||
|
||
|
||
def gen_python_files( | ||
paths: Iterable[Path], | ||
root: Path, | ||
|
@@ -5767,44 +5801,34 @@ def gen_python_files( | |
report: "Report", | ||
gitignore: PathSpec, | ||
) -> Iterator[Path]: | ||
"""Generate all files under `path` whose paths are not excluded by the | ||
`exclude` regex, but are included by the `include` regex. | ||
"""Generate all files under `path` whose paths are not excluded by | ||
`exclude_regexes`, but are included by the `include` regex. | ||
|
||
Symbolic links pointing outside of the `root` directory are ignored. | ||
|
||
`report` is where output about exclusions goes. | ||
""" | ||
assert root.is_absolute(), f"INTERNAL ERROR: `root` must be absolute but is {root}" | ||
for child in paths: | ||
# Then ignore with `exclude` option. | ||
try: | ||
normalized_path = child.resolve().relative_to(root).as_posix() | ||
except OSError as e: | ||
report.path_ignored(child, f"cannot be read because {e}") | ||
normalized_path = normalize_path_maybe_ignore(child, root, report) | ||
if normalized_path is None: | ||
continue | ||
except ValueError: | ||
if child.is_symlink(): | ||
report.path_ignored( | ||
child, f"is a symbolic link that points outside {root}" | ||
) | ||
continue | ||
|
||
raise | ||
|
||
# First ignore files matching .gitignore | ||
if gitignore.match_file(normalized_path): | ||
report.path_ignored(child, "matches the .gitignore file content") | ||
continue | ||
|
||
# Then ignore with `exclude` and `--force-exclude` options. | ||
normalized_path = "/" + normalized_path | ||
if child.is_dir(): | ||
normalized_path += "/" | ||
|
||
is_excluded = False | ||
for exclude in exclude_regexes: | ||
for opt_name, exclude in zip(("--exclude", "--force-exclude"), exclude_regexes): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This makes me a bit uneasy because it assumes that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this is not my cleanest code ever as it's also using the behaviour of zip ignoring trailing unmatched values. I have already thought about moving the force exclude regex into its own argument but I decided not doing so as it would have made more sense when |
||
exclude_match = exclude.search(normalized_path) if exclude else None | ||
if exclude_match and exclude_match.group(0): | ||
report.path_ignored(child, "matches the --exclude regular expression") | ||
report.path_ignored(child, f"matches the {opt_name} regular expression") | ||
is_excluded = True | ||
break | ||
if is_excluded: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment makes more sense on line 613 below