Skip to content

Commit

Permalink
Invalidate all cached version_info on refresh
Browse files Browse the repository at this point in the history
  • Loading branch information
EliahKagan committed Feb 22, 2024
1 parent 4b291f3 commit f130c66
Showing 1 changed file with 22 additions and 3 deletions.
25 changes: 22 additions & 3 deletions git/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,12 +306,18 @@ class Git:
"cat_file_all",
"cat_file_header",
"_version_info",
"_version_info_token",
"_git_options",
"_persistent_git_options",
"_environment",
)

_excluded_ = ("cat_file_all", "cat_file_header", "_version_info")
_excluded_ = (
"cat_file_all",
"cat_file_header",
"_version_info",
"_version_info_token",
)

re_unsafe_protocol = re.compile(r"(.+)::.+")

Expand Down Expand Up @@ -358,6 +364,8 @@ def __setstate__(self, d: Dict[str, Any]) -> None:
the top level ``__init__``.
"""

_refresh_token = object() # Since None would match an initial _version_info_token.

@classmethod
def refresh(cls, path: Union[None, PathLike] = None) -> bool:
"""This gets called by the refresh function (see the top level __init__)."""
Expand All @@ -370,7 +378,9 @@ def refresh(cls, path: Union[None, PathLike] = None) -> bool:

# Keep track of the old and new git executable path.
old_git = cls.GIT_PYTHON_GIT_EXECUTABLE
old_refresh_token = cls._refresh_token
cls.GIT_PYTHON_GIT_EXECUTABLE = new_git
cls._refresh_token = object()

# Test if the new git executable path is valid. A GitCommandNotFound error is
# spawned by us. A PermissionError is spawned if the git executable cannot be
Expand Down Expand Up @@ -399,6 +409,7 @@ def refresh(cls, path: Union[None, PathLike] = None) -> bool:

# Revert to whatever the old_git was.
cls.GIT_PYTHON_GIT_EXECUTABLE = old_git
cls._refresh_token = old_refresh_token

if old_git is None:
# On the first refresh (when GIT_PYTHON_GIT_EXECUTABLE is None) we only
Expand Down Expand Up @@ -782,8 +793,11 @@ def __init__(self, working_dir: Union[None, PathLike] = None):
# Extra environment variables to pass to git commands
self._environment: Dict[str, str] = {}

# Cached command slots
# Cached version slots
self._version_info: Union[Tuple[int, int, int, int], None] = None
self._version_info_token: object = None

# Cached command slots
self.cat_file_header: Union[None, TBD] = None
self.cat_file_all: Union[None, TBD] = None

Expand Down Expand Up @@ -824,7 +838,11 @@ def version_info(self) -> Tuple[int, int, int, int]:
This value is generated on demand and is cached.
"""
if self._version_info is None:
refresh_token = self._refresh_token # Copy it, in case of a concurrent refresh.

# Ask git for its version if we haven't done so since the last refresh.
# (Refreshing is global, but version information caching is per-instance.)
if self._version_info_token is not refresh_token:
# We only use the first 4 numbers, as everything else could be strings in fact (on Windows).
process_version = self._call_process("version") # Should be as default *args and **kwargs used.
version_numbers = process_version.split(" ")[2]
Expand All @@ -833,6 +851,7 @@ def version_info(self) -> Tuple[int, int, int, int]:
Tuple[int, int, int, int],
tuple(int(n) for n in version_numbers.split(".")[:4] if n.isdigit()),
)
self._version_info_token = refresh_token

return self._version_info

Expand Down

0 comments on commit f130c66

Please sign in to comment.