Skip to content

Commit 7fbcfa2

Browse files
authored
Merge pull request #140 from ivanov/non-git-repos
Allow running on plain (non-git) directories
2 parents 32e38f3 + a056dad commit 7fbcfa2

File tree

5 files changed

+108
-14
lines changed

5 files changed

+108
-14
lines changed

CHANGES.rst

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Added
4646
- Darker now allows itself to modify files when called with ``pre-commit -o HEAD``, but
4747
also emits a warning about this being an experimental feature
4848
- Mention Black's possible new line range formatting support in README
49+
- Darker can now be used in a plain directory tree in addition to Git repositories
4950

5051
Fixed
5152
-----

src/darker/__main__.py

+10-5
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
RevisionRange,
2828
get_missing_at_revision,
2929
git_get_content_at_revision,
30-
git_get_modified_files,
30+
git_get_modified_python_files,
31+
git_is_repository,
3132
)
3233
from darker.help import ISORT_INSTRUCTION
3334
from darker.highlighting import colorize
@@ -369,10 +370,14 @@ def main(argv: List[str] = None) -> int:
369370
black_exclude = set()
370371
else:
371372
# In other modes, only process files which have been modified.
372-
# These are relative to `root`:
373-
changed_files_to_process = git_get_modified_files(
374-
files_to_process, revrange, root
375-
)
373+
if git_is_repository(root):
374+
changed_files_to_process = git_get_modified_python_files(
375+
files_to_process, revrange, root
376+
)
377+
else:
378+
changed_files_to_process = {
379+
path.relative_to(root) for path in files_to_process
380+
}
376381
black_exclude = {
377382
f for f in changed_files_to_process if root / f not in files_to_blacken
378383
}

src/darker/git.py

+17-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,21 @@
3232
PRE_COMMIT_FROM_TO_REFS = ":PRE-COMMIT:"
3333

3434

35+
def git_is_repository(path: Path) -> bool:
36+
"""Return ``True`` if ``path`` is inside a Git working tree"""
37+
try:
38+
lines = _git_check_output_lines(
39+
["rev-parse", "--is-inside-work-tree"], path, exit_on_error=False
40+
)
41+
return lines[:1] == ["true"]
42+
except CalledProcessError as exc_info:
43+
if exc_info.returncode != 128 or not exc_info.stderr.startswith(
44+
"fatal: not a git repository"
45+
):
46+
raise
47+
return False
48+
49+
3550
def git_get_mtime_at_commit(path: Path, revision: str, cwd: Path) -> str:
3651
"""Return the committer date of the given file at the given revision
3752
@@ -267,10 +282,10 @@ def _git_ls_files_others(relative_paths: Set[Path], cwd: Path) -> Set[Path]:
267282
return {Path(line) for line in lines}
268283

269284

270-
def git_get_modified_files(
285+
def git_get_modified_python_files(
271286
paths: Iterable[Path], revrange: RevisionRange, cwd: Path
272287
) -> Set[Path]:
273-
"""Ask Git for modified and untracked files
288+
"""Ask Git for modified and untracked ``*.py`` files
274289
275290
- ``git diff --name-only --relative <rev> -- <path(s)>``
276291
- ``git ls-files --others --exclude-standard -- <path(s)>``

src/darker/tests/test_git.py

+27-6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,25 @@
1818
from darker.utils import GIT_DATEFORMAT, TextDocument
1919

2020

21+
def test_tmp_path_sanity(tmp_path):
22+
"""Make sure Pytest temporary directories aren't inside a Git repository"""
23+
try:
24+
result = git._git_check_output_lines(
25+
["rev-parse", "--absolute-git-dir"], tmp_path, exit_on_error=False
26+
)
27+
except CalledProcessError as exc_info:
28+
if exc_info.returncode != 128 or not exc_info.stderr.startswith(
29+
"fatal: not a git repository"
30+
):
31+
raise
32+
else:
33+
output = "\n".join(result)
34+
raise AssertionError(
35+
f"Temporary directory {tmp_path} for tests is not clean."
36+
f" There is a Git directory in {output}"
37+
)
38+
39+
2140
@pytest.mark.parametrize(
2241
"revision_range, expect",
2342
[
@@ -508,8 +527,8 @@ def test_git_ls_files_others(git_repo):
508527
modify_paths={},
509528
paths=[],
510529
)
511-
def test_git_get_modified_files(git_repo, modify_paths, paths, expect):
512-
"""Tests for `darker.git.git_get_modified_files()`"""
530+
def test_git_get_modified_python_files(git_repo, modify_paths, paths, expect):
531+
"""Tests for `darker.git.git_get_modified_python_files()`"""
513532
root = Path(git_repo.root)
514533
git_repo.add(
515534
{
@@ -530,7 +549,9 @@ def test_git_get_modified_files(git_repo, modify_paths, paths, expect):
530549
absolute_path.write_bytes(content.encode("ascii"))
531550
revrange = git.RevisionRange("HEAD", ":WORKTREE:")
532551

533-
result = git.git_get_modified_files({root / p for p in paths}, revrange, cwd=root)
552+
result = git.git_get_modified_python_files(
553+
{root / p for p in paths}, revrange, cwd=root
554+
)
534555

535556
assert result == {Path(p) for p in expect}
536557

@@ -677,11 +698,11 @@ def branched_repo(tmp_path_factory):
677698
expect={"mod_both.py", "mod_same.py", "mod_branch.py"},
678699
),
679700
)
680-
def test_git_get_modified_files_revision_range(
701+
def test_git_get_modified_python_files_revision_range(
681702
_description, branched_repo, revrange, expect
682703
):
683-
"""Test for :func:`darker.git.git_get_modified_files` with a revision range"""
684-
result = git.git_get_modified_files(
704+
"""Test for :func:`darker.git.git_get_modified_python_files` with revision range"""
705+
result = git.git_get_modified_python_files(
685706
[Path(branched_repo.root)],
686707
git.RevisionRange.parse_with_common_ancestor(revrange, branched_repo.root),
687708
Path(branched_repo.root),

src/darker/tests/test_main.py

+53-1
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
from pathlib import Path
99
from textwrap import dedent
1010
from types import SimpleNamespace
11-
from unittest.mock import patch
11+
from unittest.mock import call, patch
1212

1313
import pytest
1414
from black import find_project_root
1515

1616
import darker.__main__
1717
import darker.import_sorting
18+
import darker.linting
1819
from darker.exceptions import MissingPackageError
1920
from darker.git import WORKTREE, RevisionRange
2021
from darker.tests.helpers import isort_present
@@ -562,6 +563,57 @@ def test_main(
562563
assert retval == expect_retval
563564

564565

566+
def test_main_in_plain_directory(tmp_path, capsys):
567+
"""Darker works also in a plain directory tree"""
568+
subdir_a = tmp_path / "subdir_a"
569+
subdir_c = tmp_path / "subdir_b/subdir_c"
570+
subdir_a.mkdir()
571+
subdir_c.mkdir(parents=True)
572+
(subdir_a / "non-python file.txt").write_text("not reformatted\n")
573+
(subdir_a / "python file.py").write_text("import sys, os\nprint('ok')")
574+
(subdir_c / "another python file.py").write_text("a =5")
575+
with patch.object(darker.linting, "run_linter") as run_linter:
576+
577+
retval = darker.__main__.main(
578+
["--diff", "--check", "--isort", "--lint", "my-linter", str(tmp_path)]
579+
)
580+
581+
assert retval == 1
582+
assert run_linter.call_args_list == [
583+
call(
584+
"my-linter",
585+
tmp_path,
586+
{
587+
Path("subdir_a/python file.py"),
588+
Path("subdir_b/subdir_c/another python file.py"),
589+
},
590+
RevisionRange(rev1="HEAD", rev2=":WORKTREE:"),
591+
)
592+
]
593+
output = capsys.readouterr().out
594+
output = re.sub(
595+
r"\d{4}-\d\d-\d\d \d\d:\d\d:\d\d\.\d\d\d\d\d\d", "<timestamp>", output
596+
)
597+
assert output == dedent(
598+
"""\
599+
--- subdir_a/python file.py <timestamp> +0000
600+
+++ subdir_a/python file.py <timestamp> +0000
601+
@@ -1,2 +1,4 @@
602+
-import sys, os
603+
-print('ok')
604+
+import os
605+
+import sys
606+
+
607+
+print("ok")
608+
--- subdir_b/subdir_c/another python file.py <timestamp> +0000
609+
+++ subdir_b/subdir_c/another python file.py <timestamp> +0000
610+
@@ -1 +1 @@
611+
-a =5
612+
+a = 5
613+
"""
614+
)
615+
616+
565617
@pytest.mark.parametrize(
566618
"encoding, text", [(b"utf-8", b"touch\xc3\xa9"), (b"iso-8859-1", b"touch\xe9")]
567619
)

0 commit comments

Comments
 (0)