Skip to content

Commit c7fad20

Browse files
committed
Fix Windows env var upcasing regression
This uses a simple hand-rolled context manager to patch the NoDefaultCurrentDirectoryInExePath variable, instead of unittest.mock.patch.dict. The latter set unrelated environment variables to the original (same) values via os.environ, and as a result, their names were all converted to upper-case on Windows. Because only environment variables that are actually set through os.environ have their names upcased, the only variable whose name should be upcased now is NoDefaultCurrentDirectoryInExePath, which should be fine (it has a single established use/meaning in Windows, where it's treated case-insensitively as environment variables in Windows *usually* are).
1 parent 7296e5c commit c7fad20

File tree

2 files changed

+19
-6
lines changed

2 files changed

+19
-6
lines changed

git/cmd.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import subprocess
1515
import threading
1616
from textwrap import dedent
17-
import unittest.mock
1817

1918
from git.compat import (
2019
defenc,
@@ -24,7 +23,7 @@
2423
is_win,
2524
)
2625
from git.exc import CommandError
27-
from git.util import is_cygwin_git, cygpath, expand_path, remove_password_if_present
26+
from git.util import is_cygwin_git, cygpath, expand_path, remove_password_if_present, patch_env
2827

2928
from .exc import GitCommandError, GitCommandNotFound, UnsafeOptionError, UnsafeProtocolError
3029
from .util import (
@@ -965,10 +964,10 @@ def execute(
965964
'"kill_after_timeout" feature is not supported on Windows.',
966965
)
967966
# Only search PATH, not CWD. This must be in the *caller* environment. The "1" can be any value.
968-
patch_caller_env = unittest.mock.patch.dict(os.environ, {"NoDefaultCurrentDirectoryInExePath": "1"})
967+
maybe_patch_caller_env = patch_env("NoDefaultCurrentDirectoryInExePath", "1")
969968
else:
970969
cmd_not_found_exception = FileNotFoundError # NOQA # exists, flake8 unknown @UndefinedVariable
971-
patch_caller_env = contextlib.nullcontext()
970+
maybe_patch_caller_env = contextlib.nullcontext()
972971
# end handle
973972

974973
stdout_sink = PIPE if with_stdout else getattr(subprocess, "DEVNULL", None) or open(os.devnull, "wb")
@@ -984,7 +983,7 @@ def execute(
984983
istream_ok,
985984
)
986985
try:
987-
with patch_caller_env:
986+
with maybe_patch_caller_env:
988987
proc = Popen(
989988
command,
990989
env=env,

git/util.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,20 @@ def cwd(new_dir: PathLike) -> Generator[PathLike, None, None]:
158158
os.chdir(old_dir)
159159

160160

161+
@contextlib.contextmanager
162+
def patch_env(name: str, value: str) -> Generator[None, None, None]:
163+
"""Context manager to temporarily patch an environment variable."""
164+
old_value = os.getenv(name)
165+
os.environ[name] = value
166+
try:
167+
yield
168+
finally:
169+
if old_value is None:
170+
del os.environ[name]
171+
else:
172+
os.environ[name] = old_value
173+
174+
161175
def rmtree(path: PathLike) -> None:
162176
"""Remove the given recursively.
163177
@@ -935,7 +949,7 @@ def _obtain_lock_or_raise(self) -> None:
935949
)
936950

937951
try:
938-
with open(lock_file, mode='w'):
952+
with open(lock_file, mode="w"):
939953
pass
940954
except OSError as e:
941955
raise IOError(str(e)) from e

0 commit comments

Comments
 (0)