1
1
Fork 0
mirror of https://github.com/pypa/pip synced 2023-12-13 21:30:23 +01:00

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.
This commit is contained in:
Tzu-ping Chung 2021-07-01 13:33:38 +08:00
parent bef589d8cb
commit 72e38ca3df
3 changed files with 17 additions and 18 deletions

2
news/10117.removal.rst Normal file
View file

@ -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.

View file

@ -6,9 +6,6 @@ import urllib.parse
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 @@ urlunsplit = urllib.parse.urlunsplit
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 @@ class Git(VersionControl):
)
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 @@ class Git(VersionControl):
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:

View file

@ -4,7 +4,6 @@ from unittest import TestCase
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', [