Skip to content

Commit 0449b5c

Browse files
committed
Re-implement Git version parsing with regex
After packaging drops LegacyVersion, version.parse() will no longer guarantee to be able to parse Git versions, so we need to invent our own parser. Since we really only care about the major and minor segments, the logic is pretty simple.
1 parent bef589d commit 0449b5c

File tree

2 files changed

+15
-18
lines changed

2 files changed

+15
-18
lines changed

src/pip/_internal/vcs/git.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66
import urllib.request
77
from typing import List, Optional, Tuple
88

9-
from pip._vendor.packaging.version import _BaseVersion
10-
from pip._vendor.packaging.version import parse as parse_version
11-
129
from pip._internal.exceptions import BadCommand, InstallationError
1310
from pip._internal.utils.misc import HiddenText, display_path, hide_url
1411
from pip._internal.utils.subprocess import make_command
@@ -29,6 +26,14 @@
2926
logger = logging.getLogger(__name__)
3027

3128

29+
GIT_VERSION_REGEX = re.compile(
30+
r"^git version " # Prefix.
31+
r"(\d+)" # Major.
32+
r"\.(\d+)" # Dot, minor.
33+
r"(?:\.(\d+))?" # Optional dot, patch.
34+
r".*$" # Suffix, including any pre- and post-release segments we don't care about.
35+
)
36+
3237
HASH_REGEX = re.compile('^[a-fA-F0-9]{40}$')
3338

3439
# SCP (Secure copy protocol) shorthand. e.g. '[email protected]:foo/bar.git'
@@ -83,21 +88,14 @@ def is_immutable_rev_checkout(self, url, dest):
8388
)
8489
return not is_tag_or_branch
8590

86-
def get_git_version(self):
87-
# type: () -> _BaseVersion
88-
VERSION_PFX = 'git version '
91+
def get_git_version(self) -> Tuple[int, ...]:
8992
version = self.run_command(
9093
['version'], show_stdout=False, stdout_only=True
9194
)
92-
if version.startswith(VERSION_PFX):
93-
version = version[len(VERSION_PFX):].split()[0]
94-
else:
95-
version = ''
96-
# get first 3 positions of the git version because
97-
# on windows it is x.y.z.windows.t, and this parses as
98-
# LegacyVersion which always smaller than a Version.
99-
version = '.'.join(version.split('.')[:3])
100-
return parse_version(version)
95+
match = GIT_VERSION_REGEX.match(version)
96+
if not match:
97+
return ()
98+
return tuple(int(c) for c in match.groups())
10199

102100
@classmethod
103101
def get_current_branch(cls, location):
@@ -301,7 +299,7 @@ def switch(self, dest, url, rev_options):
301299
def update(self, dest, url, rev_options):
302300
# type: (str, HiddenText, RevOptions) -> None
303301
# First fetch changes from the default remote
304-
if self.get_git_version() >= parse_version('1.9.0'):
302+
if self.get_git_version() >= (1, 9):
305303
# fetch tags in addition to everything else
306304
self.run_command(['fetch', '-q', '--tags'], cwd=dest)
307305
else:

tests/unit/test_vcs.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from unittest.mock import patch
55

66
import pytest
7-
from pip._vendor.packaging.version import parse as parse_version
87

98
from pip._internal.exceptions import BadCommand, InstallationError
109
from pip._internal.utils.misc import hide_url, hide_value
@@ -483,7 +482,7 @@ def test_subversion__get_url_rev_options():
483482

484483
def test_get_git_version():
485484
git_version = Git().get_git_version()
486-
assert git_version >= parse_version('1.0.0')
485+
assert git_version >= (1, 0, 0)
487486

488487

489488
@pytest.mark.parametrize('use_interactive,is_atty,expected', [

0 commit comments

Comments
 (0)