Implement get_src_requirement() in the VersionControl base class.

This commit is contained in:
Chris Jerdonek 2019-01-12 23:39:35 -08:00
parent 729404d4c5
commit fdbfde03e1
6 changed files with 76 additions and 54 deletions

View File

@ -11,7 +11,8 @@ from pip._vendor.six.moves.urllib import parse as urllib_parse
from pip._internal.exceptions import BadCommand
from pip._internal.utils.misc import (
display_path, backup_dir, call_subprocess, rmtree, ask_path_exists,
ask_path_exists, backup_dir, call_subprocess, display_path,
make_vcs_requirement_url, rmtree,
)
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
@ -186,6 +187,28 @@ class VersionControl(object):
unset_environ = () # type: Tuple[str, ...]
default_arg_rev = None # type: Optional[str]
@classmethod
def should_add_vcs_url_prefix(cls, remote_url):
"""
Return whether the vcs prefix (e.g. "git+") should be added to a
repository's remote url when used in a requirement.
"""
return not remote_url.lower().startswith('{}:'.format(cls.name))
@classmethod
def get_subdirectory(cls, repo_dir):
"""
Return the path to setup.py, relative to the repo root.
"""
return None
@classmethod
def get_requirement_revision(cls, repo_dir):
"""
Return the revision string that should be used in a requirement.
"""
return cls.get_revision(repo_dir)
def __init__(self, url=None, *args, **kwargs):
self.url = url
super(VersionControl, self).__init__(*args, **kwargs)
@ -446,14 +469,31 @@ class VersionControl(object):
self.obtain(location)
@classmethod
def get_src_requirement(cls, location, project_name):
def get_src_requirement(cls, repo_dir, project_name):
"""
Return a string representing the requirement needed to
redownload the files currently present in location, something
like:
{repository_url}@{revision}#egg={project_name}-{version_identifier}
Return the requirement string to use to redownload the files
currently at the given repository directory.
Args:
project_name: the (unescaped) project name.
The return value has a form similar to the following:
{repository_url}@{revision}#egg={project_name}
"""
raise NotImplementedError
repo_url = cls.get_remote_url(repo_dir)
if repo_url is None:
return None
if cls.should_add_vcs_url_prefix(repo_url):
repo_url = '{}+{}'.format(cls.name, repo_url)
revision = cls.get_requirement_revision(repo_dir)
subdir = cls.get_subdirectory(repo_dir)
req = make_vcs_requirement_url(repo_url, revision, project_name,
subdir=subdir)
return req
@classmethod
def get_remote_url(cls, location):

View File

@ -9,6 +9,7 @@ from pip._internal.download import path_to_url
from pip._internal.utils.misc import (
display_path, make_vcs_requirement_url, rmtree,
)
from pip._internal.utils.temp_dir import TempDirectory
from pip._internal.vcs import VersionControl, vcs
logger = logging.getLogger(__name__)
@ -93,16 +94,6 @@ class Bazaar(VersionControl):
)
return revision.splitlines()[-1]
@classmethod
def get_src_requirement(cls, location, project_name):
repo = cls.get_remote_url(location)
if not repo:
return None
if not repo.lower().startswith('bzr:'):
repo = 'bzr+' + repo
current_rev = cls.get_revision(location)
return make_vcs_requirement_url(repo, current_rev, project_name)
def is_commit_id_equal(self, dest, name):
"""Always assume the versions don't match"""
return False

View File

@ -10,9 +10,7 @@ from pip._vendor.six.moves.urllib import request as urllib_request
from pip._internal.exceptions import BadCommand
from pip._internal.utils.compat import samefile
from pip._internal.utils.misc import (
display_path, make_vcs_requirement_url, redact_password_from_url,
)
from pip._internal.utils.misc import display_path, redact_password_from_url
from pip._internal.utils.temp_dir import TempDirectory
from pip._internal.vcs import RemoteNotFoundError, VersionControl, vcs
@ -286,8 +284,7 @@ class Git(VersionControl):
return current_rev.strip()
@classmethod
def _get_subdirectory(cls, location):
"""Return the relative path of setup.py to the git repo root."""
def get_subdirectory(cls, location):
# find the repo root
git_dir = cls.run_command(['rev-parse', '--git-dir'],
show_stdout=False, cwd=location).strip()
@ -313,18 +310,6 @@ class Git(VersionControl):
return None
return os.path.relpath(location, root_dir)
@classmethod
def get_src_requirement(cls, location, project_name):
repo = cls.get_remote_url(location)
if not repo.lower().startswith('git:'):
repo = 'git+' + repo
current_rev = cls.get_revision(location)
subdir = cls._get_subdirectory(location)
req = make_vcs_requirement_url(repo, current_rev, project_name,
subdir=subdir)
return req
def get_url_rev_and_auth(self, url):
"""
Prefixes stub URLs like 'user@hostname:user/repo.git' with 'ssh://'.

View File

@ -6,7 +6,7 @@ import os
from pip._vendor.six.moves import configparser
from pip._internal.download import path_to_url
from pip._internal.utils.misc import display_path, make_vcs_requirement_url
from pip._internal.utils.misc import display_path
from pip._internal.utils.temp_dir import TempDirectory
from pip._internal.vcs import VersionControl, vcs
@ -75,26 +75,25 @@ class Mercurial(VersionControl):
@classmethod
def get_revision(cls, location):
"""
Return the repository-local changeset revision number, as an integer.
"""
current_revision = cls.run_command(
['parents', '--template={rev}'],
show_stdout=False, cwd=location).strip()
return current_revision
@classmethod
def get_revision_hash(cls, location):
def get_requirement_revision(cls, location):
"""
Return the changeset identification hash, as a 40-character
hexadecimal string
"""
current_rev_hash = cls.run_command(
['parents', '--template={node}'],
show_stdout=False, cwd=location).strip()
return current_rev_hash
@classmethod
def get_src_requirement(cls, location, project_name):
repo = cls.get_remote_url(location)
if not repo.lower().startswith('hg:'):
repo = 'hg+' + repo
current_rev_hash = cls.get_revision_hash(location)
return make_vcs_requirement_url(repo, current_rev_hash, project_name)
def is_commit_id_equal(self, dest, name):
"""Always assume the versions don't match"""
return False

View File

@ -6,7 +6,7 @@ import re
from pip._internal.utils.logging import indent_log
from pip._internal.utils.misc import (
display_path, make_vcs_requirement_url, rmtree, split_auth_from_netloc,
display_path, rmtree, split_auth_from_netloc,
)
from pip._internal.vcs import VersionControl, vcs
@ -25,6 +25,10 @@ class Subversion(VersionControl):
repo_name = 'checkout'
schemes = ('svn', 'svn+ssh', 'svn+http', 'svn+https', 'svn+svn')
@classmethod
def should_add_vcs_url_prefix(cls, remote_url):
return True
def get_base_rev_args(self, rev):
return ['-r', rev]
@ -183,15 +187,6 @@ class Subversion(VersionControl):
return url, rev
@classmethod
def get_src_requirement(cls, location, project_name):
repo = cls.get_remote_url(location)
if repo is None:
return None
repo = 'svn+' + repo
rev = cls.get_revision(location)
return make_vcs_requirement_url(repo, rev, project_name)
def is_commit_id_equal(self, dest, name):
"""Always assume the versions don't match"""
return False

View File

@ -79,6 +79,18 @@ def test_looks_like_hash():
assert not looks_like_hash(39 * 'a')
@pytest.mark.parametrize('vcs_cls, remote_url, expected', [
# Git is one of the subclasses using the base class implementation.
(Git, 'git://example.com/MyProject', False),
(Git, 'http://example.com/MyProject', True),
# Subversion is the only subclass overriding the base class implementation.
(Subversion, 'svn://example.com/MyProject', True),
])
def test_should_add_vcs_url_prefix(vcs_cls, remote_url, expected):
actual = vcs_cls.should_add_vcs_url_prefix(remote_url)
assert actual == expected
@patch('pip._internal.vcs.git.Git.get_revision')
@patch('pip._internal.vcs.git.Git.get_remote_url')
@pytest.mark.network