From: Antonio Ossa-Guerra Date: Sat, 5 Nov 2022 05:09:59 +0000 (-0300) Subject: Apply .gitignore correctly in every source entry (#3336) X-Git-Url: https://git.madduck.net/etc/vim.git/commitdiff_plain/0e9d29ab73d608a79028e22a713ee717b5dcca96?ds=inline;pf=etc Apply .gitignore correctly in every source entry (#3336) When passing multiple src directories, the root gitignore was only applied to the first processed source. The reason is that, in the first source, exclude is `None`, but then the value gets overridden by `re_compile_maybe_verbose(DEFAULT_EXCLUDES)`, so in the next iteration where the source is a directory, the condition is not met and sets the value of `gitignore` to `None`. To fix this problem, we store a boolean indicating if `exclude` is `None` and set the value of `exclude` to its default value if that's the case. This makes sure that the flow enters the correct condition on following iterations and also keeps the original value if the condition is not met. Also, the value of `gitignore` is initialized as `None` and overriden if necessary. The value of `root_gitignore` is always calculated to avoid using additional variables (at the small cost of additional computations). Signed-off-by: Antonio Ossa Guerra --- diff --git a/CHANGES.md b/CHANGES.md index 1dcd7f0..a1071a8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -22,6 +22,9 @@ +- Fix incorrectly ignoring .gitignore presence when more than one source directory is + specified (#3336) + ### Packaging diff --git a/src/black/__init__.py b/src/black/__init__.py index 9459227..6c8d346 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -30,6 +30,7 @@ from typing import ( import click from click.core import ParameterSource from mypy_extensions import mypyc_attr +from pathspec import PathSpec from pathspec.patterns.gitwildmatch import GitWildMatchPatternError from _black_version import version as __version__ @@ -627,6 +628,11 @@ def get_sources( sources: Set[Path] = set() root = ctx.obj["root"] + exclude_is_None = exclude is None + exclude = re_compile_maybe_verbose(DEFAULT_EXCLUDES) if exclude is None else exclude + gitignore = None # type: Optional[PathSpec] + root_gitignore = get_gitignore(root) + for s in src: if s == "-" and stdin_filename: p = Path(stdin_filename) @@ -660,16 +666,14 @@ def get_sources( sources.add(p) elif p.is_dir(): - if exclude is None: - exclude = re_compile_maybe_verbose(DEFAULT_EXCLUDES) - gitignore = get_gitignore(root) + if exclude_is_None: p_gitignore = get_gitignore(p) # No need to use p's gitignore if it is identical to root's gitignore # (i.e. root and p point to the same directory). - if gitignore != p_gitignore: - gitignore += p_gitignore - else: - gitignore = None + if root_gitignore == p_gitignore: + gitignore = root_gitignore + else: + gitignore = root_gitignore + p_gitignore sources.update( gen_python_files( p.iterdir(), diff --git a/tests/data/gitignore_used_on_multiple_sources/.gitignore b/tests/data/gitignore_used_on_multiple_sources/.gitignore new file mode 100644 index 0000000..2987e7b --- /dev/null +++ b/tests/data/gitignore_used_on_multiple_sources/.gitignore @@ -0,0 +1 @@ +a.py diff --git a/tests/data/gitignore_used_on_multiple_sources/dir1/a.py b/tests/data/gitignore_used_on_multiple_sources/dir1/a.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/data/gitignore_used_on_multiple_sources/dir1/b.py b/tests/data/gitignore_used_on_multiple_sources/dir1/b.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/data/gitignore_used_on_multiple_sources/dir2/a.py b/tests/data/gitignore_used_on_multiple_sources/dir2/a.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/data/gitignore_used_on_multiple_sources/dir2/b.py b/tests/data/gitignore_used_on_multiple_sources/dir2/b.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_black.py b/tests/test_black.py index 9256698..784eb0d 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -1998,6 +1998,17 @@ class TestFileCollection: ctx.obj["root"] = base assert_collected_sources(src, expected, ctx=ctx, extend_exclude=r"/exclude/") + def test_gitignore_used_on_multiple_sources(self) -> None: + root = Path(DATA_DIR / "gitignore_used_on_multiple_sources") + expected = [ + root / "dir1" / "b.py", + root / "dir2" / "b.py", + ] + ctx = FakeContext() + ctx.obj["root"] = root + src = [root / "dir1", root / "dir2"] + assert_collected_sources(src, expected, ctx=ctx) + @patch("black.find_project_root", lambda *args: (THIS_DIR.resolve(), None)) def test_exclude_for_issue_1572(self) -> None: # Exclude shouldn't touch files that were explicitly given to Black through the