diff --git a/news/10117.removal.rst b/news/10117.removal.rst new file mode 100644 index 00000000000..c0191a35358 --- /dev/null +++ b/news/10117.removal.rst @@ -0,0 +1,2 @@ +Git version parsing is now done with regular expression to prepare for the +pending upstream removal of non-PEP-440 version parsing logic. diff --git a/src/pip/_internal/vcs/git.py b/src/pip/_internal/vcs/git.py index b860e350a2d..269bf6a65b3 100644 --- a/src/pip/_internal/vcs/git.py +++ b/src/pip/_internal/vcs/git.py @@ -6,9 +6,6 @@ import urllib.request from typing import List, Optional, Tuple -from pip._vendor.packaging.version import _BaseVersion -from pip._vendor.packaging.version import parse as parse_version - from pip._internal.exceptions import BadCommand, InstallationError from pip._internal.utils.misc import HiddenText, display_path, hide_url from pip._internal.utils.subprocess import make_command @@ -29,6 +26,14 @@ logger = logging.getLogger(__name__) +GIT_VERSION_REGEX = re.compile( + r"^git version " # Prefix. + r"(\d+)" # Major. + r"\.(\d+)" # Dot, minor. + r"(?:\.(\d+))?" # Optional dot, patch. + r".*$" # Suffix, including any pre- and post-release segments we don't care about. +) + HASH_REGEX = re.compile('^[a-fA-F0-9]{40}$') # SCP (Secure copy protocol) shorthand. e.g. 'git@example.com:foo/bar.git' @@ -83,21 +88,14 @@ def is_immutable_rev_checkout(self, url, dest): ) return not is_tag_or_branch - def get_git_version(self): - # type: () -> _BaseVersion - VERSION_PFX = 'git version ' + def get_git_version(self) -> Tuple[int, ...]: version = self.run_command( ['version'], show_stdout=False, stdout_only=True ) - if version.startswith(VERSION_PFX): - version = version[len(VERSION_PFX):].split()[0] - else: - version = '' - # get first 3 positions of the git version because - # on windows it is x.y.z.windows.t, and this parses as - # LegacyVersion which always smaller than a Version. - version = '.'.join(version.split('.')[:3]) - return parse_version(version) + match = GIT_VERSION_REGEX.match(version) + if not match: + return () + return tuple(int(c) for c in match.groups()) @classmethod def get_current_branch(cls, location): @@ -301,7 +299,7 @@ def switch(self, dest, url, rev_options): def update(self, dest, url, rev_options): # type: (str, HiddenText, RevOptions) -> None # First fetch changes from the default remote - if self.get_git_version() >= parse_version('1.9.0'): + if self.get_git_version() >= (1, 9): # fetch tags in addition to everything else self.run_command(['fetch', '-q', '--tags'], cwd=dest) else: diff --git a/tests/unit/test_vcs.py b/tests/unit/test_vcs.py index 305c45fd857..403f3946673 100644 --- a/tests/unit/test_vcs.py +++ b/tests/unit/test_vcs.py @@ -4,7 +4,6 @@ from unittest.mock import patch import pytest -from pip._vendor.packaging.version import parse as parse_version from pip._internal.exceptions import BadCommand, InstallationError from pip._internal.utils.misc import hide_url, hide_value @@ -483,7 +482,7 @@ def test_subversion__get_url_rev_options(): def test_get_git_version(): git_version = Git().get_git_version() - assert git_version >= parse_version('1.0.0') + assert git_version >= (1, 0, 0) @pytest.mark.parametrize('use_interactive,is_atty,expected', [