From 14f2ba148794242ce27c2bc5dedb00c76c2115de Mon Sep 17 00:00:00 2001 From: Antonio Ossa Guerra Date: Mon, 17 Oct 2022 09:58:55 -0300 Subject: [PATCH 1/3] Fix to use root gitignore in every source entry 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 --- src/black/__init__.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/black/__init__.py b/src/black/__init__.py index 5293796aea1..2e43e800c40 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -30,6 +30,7 @@ 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__ @@ -625,6 +626,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) @@ -658,16 +664,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(), From f5c5372f9ee1f27c59f9a190ba312a5042846372 Mon Sep 17 00:00:00 2001 From: Antonio Ossa Guerra Date: Mon, 17 Oct 2022 10:11:19 -0300 Subject: [PATCH 2/3] Test root gitignore behavior on multiple sources The test creates a fake context and collects the files from two sources. Both sources are directories in the root path, where a gitignore file ignores a filename that is present in both subdirs. Before the fix introduced in the previous commit, this test was expected to fail: a file that should be ignores was still visible for Black. Now, the test is passed. Signed-off-by: Antonio Ossa Guerra --- .../gitignore_used_on_multiple_sources/.gitignore | 1 + .../data/gitignore_used_on_multiple_sources/dir1/a.py | 0 .../data/gitignore_used_on_multiple_sources/dir1/b.py | 0 .../data/gitignore_used_on_multiple_sources/dir2/a.py | 0 .../data/gitignore_used_on_multiple_sources/dir2/b.py | 0 tests/test_black.py | 11 +++++++++++ 6 files changed, 12 insertions(+) create mode 100644 tests/data/gitignore_used_on_multiple_sources/.gitignore create mode 100644 tests/data/gitignore_used_on_multiple_sources/dir1/a.py create mode 100644 tests/data/gitignore_used_on_multiple_sources/dir1/b.py create mode 100644 tests/data/gitignore_used_on_multiple_sources/dir2/a.py create mode 100644 tests/data/gitignore_used_on_multiple_sources/dir2/b.py 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 00000000000..2987e7bb646 --- /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 00000000000..e69de29bb2d 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 00000000000..e69de29bb2d 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 00000000000..e69de29bb2d 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 00000000000..e69de29bb2d diff --git a/tests/test_black.py b/tests/test_black.py index 5d0175d9d66..d66305becf0 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -1956,6 +1956,17 @@ def test_gitignore_used_as_default(self) -> None: 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 From 84756769d15886e338bcdf7b3d42239b55ef0cf7 Mon Sep 17 00:00:00 2001 From: Antonio Ossa Guerra Date: Mon, 17 Oct 2022 10:38:45 -0300 Subject: [PATCH 3/3] Update CHANGES.md Add entry about fixed bug: .gitignore being skipped when more than one source directory was given Signed-off-by: Antonio Ossa Guerra --- CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index ba9f4c06f28..b1e8f6c75b1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,9 @@ +- Fix incorrectly ignoring .gitignore presence when more than one source directory is + specified (#3336) + ### Packaging