Simplify check for symlinks that resolve outside root (#4221) · psf/black@a201003 (original) (raw)
3 files changed
lines changed
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -50,9 +50,9 @@ | ||
50 | 50 | gen_python_files, |
51 | 51 | get_gitignore, |
52 | 52 | get_root_relative_path, |
53 | -normalize_path_maybe_ignore, | |
54 | 53 | parse_pyproject_toml, |
55 | 54 | path_is_excluded, |
55 | +resolves_outside_root_or_cannot_stat, | |
56 | 56 | wrap_stream_for_windows, |
57 | 57 | ) |
58 | 58 | from black.handle_ipynb_magics import ( |
@@ -763,12 +763,9 @@ def get_sources( | ||
763 | 763 | ) |
764 | 764 | continue |
765 | 765 | |
766 | -normalized_path: Optional[str] = normalize_path_maybe_ignore( | |
767 | -path, root, report | |
768 | - ) | |
769 | -if normalized_path is None: | |
766 | +if resolves_outside_root_or_cannot_stat(path, root, report): | |
770 | 767 | if verbose: |
771 | -out(f'Skipping invalid source: "{normalized_path}"', fg="red") | |
768 | +out(f'Skipping invalid source: "{path}"', fg="red") | |
772 | 769 | continue |
773 | 770 | |
774 | 771 | if is_stdin: |
@@ -780,7 +777,7 @@ def get_sources( | ||
780 | 777 | continue |
781 | 778 | |
782 | 779 | if verbose: |
783 | -out(f'Found input source: "{normalized_path}"', fg="blue") | |
780 | +out(f'Found input source: "{path}"', fg="blue") | |
784 | 781 | sources.add(path) |
785 | 782 | elif path.is_dir(): |
786 | 783 | path = root / (path.resolve().relative_to(root)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -254,26 +254,24 @@ def get_gitignore(root: Path) -> PathSpec: | ||
254 | 254 | raise |
255 | 255 | |
256 | 256 | |
257 | -def normalize_path_maybe_ignore( | |
257 | +def resolves_outside_root_or_cannot_stat( | |
258 | 258 | path: Path, |
259 | 259 | root: Path, |
260 | 260 | report: Optional[Report] = None, |
261 | -) -> Optional[str]: | |
262 | -"""Normalize `path`. May return `None` if `path` was ignored. | |
263 | - | |
264 | - `report` is where "path ignored" output goes. | |
261 | +) -> bool: | |
262 | +""" | |
263 | + Returns whether the path is a symbolic link that points outside the | |
264 | + root directory. Also returns True if we failed to resolve the path. | |
265 | 265 | """ |
266 | 266 | try: |
267 | -abspath = path if path.is_absolute() else Path.cwd() / path | |
268 | -normalized_path = abspath.resolve() | |
269 | -root_relative_path = get_root_relative_path(normalized_path, root, report) | |
270 | - | |
267 | +if sys.version_info < (3, 8, 6): | |
268 | + path = path.absolute() # https://bugs.python.org/issue33660 | |
269 | +resolved_path = path.resolve() | |
270 | + return get_root_relative_path(resolved_path, root, report) is None | |
271 | 271 | except OSError as e: |
272 | 272 | if report: |
273 | 273 | report.path_ignored(path, f"cannot be read because {e}") |
274 | -return None | |
275 | - | |
276 | -return root_relative_path | |
274 | +return True | |
277 | 275 | |
278 | 276 | |
279 | 277 | def get_root_relative_path( |
@@ -369,8 +367,7 @@ def gen_python_files( | ||
369 | 367 | report.path_ignored(child, "matches the --force-exclude regular expression") |
370 | 368 | continue |
371 | 369 | |
372 | -normalized_path = normalize_path_maybe_ignore(child, root, report) | |
373 | -if normalized_path is None: | |
370 | +if resolves_outside_root_or_cannot_stat(child, root, report): | |
374 | 371 | continue |
375 | 372 | |
376 | 373 | if child.is_dir(): |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1760,12 +1760,15 @@ def test_bpo_33660_workaround(self) -> None: | ||
1760 | 1760 | return |
1761 | 1761 | |
1762 | 1762 | # https://bugs.python.org/issue33660 |
1763 | +# Can be removed when we drop support for Python 3.8.5 | |
1763 | 1764 | root = Path("/") |
1764 | 1765 | with change_directory(root): |
1765 | 1766 | path = Path("workspace") / "project" |
1766 | 1767 | report = black.Report(verbose=True) |
1767 | -normalized_path = black.normalize_path_maybe_ignore(path, root, report) | |
1768 | -self.assertEqual(normalized_path, "workspace/project") | |
1768 | +resolves_outside = black.resolves_outside_root_or_cannot_stat( | |
1769 | +path, root, report | |
1770 | + ) | |
1771 | +self.assertIs(resolves_outside, False) | |
1769 | 1772 | |
1770 | 1773 | def test_normalize_path_ignore_windows_junctions_outside_of_root(self) -> None: |
1771 | 1774 | if system() != "Windows": |
@@ -1778,13 +1781,13 @@ def test_normalize_path_ignore_windows_junctions_outside_of_root(self) -> None: | ||
1778 | 1781 | os.system(f"mklink /J {junction_dir} {junction_target_outside_of_root}") |
1779 | 1782 | |
1780 | 1783 | report = black.Report(verbose=True) |
1781 | -normalized_path = black.normalize_path_maybe_ignore( | |
1784 | +resolves_outside = black.resolves_outside_root_or_cannot_stat( | |
1782 | 1785 | junction_dir, root, report |
1783 | 1786 | ) |
1784 | 1787 | # Manually delete for Python < 3.8 |
1785 | 1788 | os.system(f"rmdir {junction_dir}") |
1786 | 1789 | |
1787 | -self.assertEqual(normalized_path, None) | |
1790 | +self.assertIs(resolves_outside, True) | |
1788 | 1791 | |
1789 | 1792 | def test_newline_comment_interaction(self) -> None: |
1790 | 1793 | source = "class A:\\\r\n# type: ignore\n pass\n" |