Skip to content

Commit 9a7cec1

Browse files
authored
Merge pull request #1812 from EliahKagan/refresh-cmdline
Report actual attempted Git command when Git.refresh fails
2 parents 307f198 + 9b7e15f commit 9a7cec1

File tree

3 files changed

+58
-32
lines changed

3 files changed

+58
-32
lines changed

Diff for: git/cmd.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -478,12 +478,12 @@ def refresh(cls, path: Union[None, PathLike] = None) -> bool:
478478
# We get here if this was the initial refresh and the refresh mode was
479479
# not error. Go ahead and set the GIT_PYTHON_GIT_EXECUTABLE such that we
480480
# discern the difference between the first refresh at import time
481-
# and subsequent calls to refresh().
481+
# and subsequent calls to git.refresh or this refresh method.
482482
cls.GIT_PYTHON_GIT_EXECUTABLE = cls.git_exec_name
483483
else:
484484
# After the first refresh (when GIT_PYTHON_GIT_EXECUTABLE is no longer
485485
# None) we raise an exception.
486-
raise GitCommandNotFound("git", err)
486+
raise GitCommandNotFound(new_git, err)
487487

488488
return has_git
489489

Diff for: git/remote.py

+11-22
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,24 @@
55

66
"""Module implementing a remote object allowing easy access to git remotes."""
77

8+
import contextlib
89
import logging
910
import re
1011

11-
from git.cmd import handle_process_output, Git
12+
from git.cmd import Git, handle_process_output
1213
from git.compat import defenc, force_text
14+
from git.config import GitConfigParser, SectionConstraint, cp
1315
from git.exc import GitCommandError
16+
from git.refs import Head, Reference, RemoteReference, SymbolicReference, TagReference
1417
from git.util import (
15-
LazyMixin,
16-
IterableObj,
18+
CallableRemoteProgress,
1719
IterableList,
20+
IterableObj,
21+
LazyMixin,
1822
RemoteProgress,
19-
CallableRemoteProgress,
20-
)
21-
from git.util import (
2223
join_path,
2324
)
2425

25-
from git.config import (
26-
GitConfigParser,
27-
SectionConstraint,
28-
cp,
29-
)
30-
from git.refs import Head, Reference, RemoteReference, SymbolicReference, TagReference
31-
3226
# typing-------------------------------------------------------
3327

3428
from typing import (
@@ -345,18 +339,13 @@ class FetchInfo(IterableObj):
345339
@classmethod
346340
def refresh(cls) -> Literal[True]:
347341
"""This gets called by the refresh function (see the top level __init__)."""
348-
# clear the old values in _flag_map
349-
try:
342+
# Clear the old values in _flag_map.
343+
with contextlib.suppress(KeyError):
350344
del cls._flag_map["t"]
351-
except KeyError:
352-
pass
353-
354-
try:
345+
with contextlib.suppress(KeyError):
355346
del cls._flag_map["-"]
356-
except KeyError:
357-
pass
358347

359-
# set the value given the git version
348+
# Set the value given the git version.
360349
if Git().version_info[:2] >= (2, 10):
361350
cls._flag_map["t"] = cls.TAG_UPDATE
362351
else:

Diff for: test/test_git.py

+45-8
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ def _patch_out_env(name):
4444
os.environ[name] = old_value
4545

4646

47+
@contextlib.contextmanager
48+
def _rollback_refresh():
49+
try:
50+
yield Git.GIT_PYTHON_GIT_EXECUTABLE # Provide the old value for convenience.
51+
finally:
52+
refresh()
53+
54+
4755
@ddt.ddt
4856
class TestGit(TestBase):
4957
@classmethod
@@ -306,14 +314,43 @@ def test_cmd_override(self):
306314
):
307315
self.assertRaises(GitCommandNotFound, self.git.version)
308316

309-
def test_refresh(self):
310-
# Test a bad git path refresh.
311-
self.assertRaises(GitCommandNotFound, refresh, "yada")
312-
313-
# Test a good path refresh.
314-
which_cmd = "where" if os.name == "nt" else "command -v"
315-
path = os.popen("{0} git".format(which_cmd)).read().strip().split("\n")[0]
316-
refresh(path)
317+
def test_refresh_bad_absolute_git_path(self):
318+
"""Bad absolute path arg is reported and not set."""
319+
absolute_path = str(Path("yada").absolute())
320+
expected_pattern = rf"\n[ \t]*cmdline: {re.escape(absolute_path)}\Z"
321+
322+
with _rollback_refresh() as old_git_executable:
323+
with self.assertRaisesRegex(GitCommandNotFound, expected_pattern):
324+
refresh(absolute_path)
325+
self.assertEqual(self.git.GIT_PYTHON_GIT_EXECUTABLE, old_git_executable)
326+
327+
def test_refresh_bad_relative_git_path(self):
328+
"""Bad relative path arg is resolved to absolute path and reported, not set."""
329+
absolute_path = str(Path("yada").absolute())
330+
expected_pattern = rf"\n[ \t]*cmdline: {re.escape(absolute_path)}\Z"
331+
332+
with _rollback_refresh() as old_git_executable:
333+
with self.assertRaisesRegex(GitCommandNotFound, expected_pattern):
334+
refresh("yada")
335+
self.assertEqual(self.git.GIT_PYTHON_GIT_EXECUTABLE, old_git_executable)
336+
337+
def test_refresh_good_absolute_git_path(self):
338+
"""Good absolute path arg is set."""
339+
absolute_path = shutil.which("git")
340+
341+
with _rollback_refresh():
342+
refresh(absolute_path)
343+
self.assertEqual(self.git.GIT_PYTHON_GIT_EXECUTABLE, absolute_path)
344+
345+
def test_refresh_good_relative_git_path(self):
346+
"""Good relative path arg is resolved to absolute path and set."""
347+
absolute_path = shutil.which("git")
348+
dirname, basename = osp.split(absolute_path)
349+
350+
with cwd(dirname):
351+
with _rollback_refresh():
352+
refresh(basename)
353+
self.assertEqual(self.git.GIT_PYTHON_GIT_EXECUTABLE, absolute_path)
317354

318355
def test_options_are_passed_to_git(self):
319356
# This works because any command after git --version is ignored.

0 commit comments

Comments
 (0)