Skip to content

Commit

Permalink
Merge pull request #6122 from cjerdonek/make-get-src-requirement-clas…
Browse files Browse the repository at this point in the history
…s-method

Make VersionControl.get_src_requirement() a class method
  • Loading branch information
cjerdonek authored Jan 10, 2019
2 parents 4771470 + 6a882b6 commit 2a6d282
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 76 deletions.
2 changes: 1 addition & 1 deletion src/pip/_internal/operations/freeze.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def get_requirement_info(dist):
return (location, True, comments)

try:
req = vc_type().get_src_requirement(location, dist.project_name)
req = vc_type.get_src_requirement(location, dist.project_name)
except RemoteNotFoundError:
req = dist.as_requirement()
comments = [
Expand Down
21 changes: 13 additions & 8 deletions src/pip/_internal/vcs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,8 @@ def make_rev_options(self, rev=None, extra_args=None):
"""
return RevOptions(self, rev, extra_args=extra_args)

def _is_local_repository(self, repo):
@classmethod
def _is_local_repository(cls, repo):
# type: (str) -> bool
"""
posix absolute paths start with os.path.sep,
Expand Down Expand Up @@ -444,7 +445,8 @@ def unpack(self, location):
rmtree(location)
self.obtain(location)

def get_src_requirement(self, location, project_name):
@classmethod
def get_src_requirement(cls, location, project_name):
"""
Return a string representing the requirement needed to
redownload the files currently present in location, something
Expand All @@ -453,7 +455,8 @@ def get_src_requirement(self, location, project_name):
"""
raise NotImplementedError

def get_remote_url(self, location):
@classmethod
def get_remote_url(cls, location):
"""
Return the url used at location
Expand All @@ -462,14 +465,16 @@ def get_remote_url(self, location):
"""
raise NotImplementedError

def get_revision(self, location):
@classmethod
def get_revision(cls, location):
"""
Return the current commit id of the files at the given location.
"""
raise NotImplementedError

@classmethod
def run_command(
self,
cls,
cmd, # type: List[str]
show_stdout=True, # type: bool
cwd=None, # type: Optional[str]
Expand All @@ -485,14 +490,14 @@ def run_command(
This is simply a wrapper around call_subprocess that adds the VCS
command name, and checks that the VCS is available
"""
cmd = [self.name] + cmd
cmd = [cls.name] + cmd
try:
return call_subprocess(cmd, show_stdout, cwd,
on_returncode=on_returncode,
extra_ok_returncodes=extra_ok_returncodes,
command_desc=command_desc,
extra_environ=extra_environ,
unset_environ=self.unset_environ,
unset_environ=cls.unset_environ,
spinner=spinner)
except OSError as e:
# errno.ENOENT = no such file or directory
Expand All @@ -501,7 +506,7 @@ def run_command(
raise BadCommand(
'Cannot find command %r - do you have '
'%r installed and in your '
'PATH?' % (self.name, self.name))
'PATH?' % (cls.name, cls.name))
else:
raise # re-raise exception if a different error occurred

Expand Down
19 changes: 11 additions & 8 deletions src/pip/_internal/vcs/bazaar.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,32 +75,35 @@ def get_url_rev_and_auth(self, url):
url = 'bzr+' + url
return url, rev, user_pass

def get_remote_url(self, location):
urls = self.run_command(['info'], show_stdout=False, cwd=location)
@classmethod
def get_remote_url(cls, location):
urls = cls.run_command(['info'], show_stdout=False, cwd=location)
for line in urls.splitlines():
line = line.strip()
for x in ('checkout of branch: ',
'parent branch: '):
if line.startswith(x):
repo = line.split(x)[1]
if self._is_local_repository(repo):
if cls._is_local_repository(repo):
return path_to_url(repo)
return repo
return None

def get_revision(self, location):
revision = self.run_command(
@classmethod
def get_revision(cls, location):
revision = cls.run_command(
['revno'], show_stdout=False, cwd=location,
)
return revision.splitlines()[-1]

def get_src_requirement(self, location, project_name):
repo = self.get_remote_url(location)
@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 = self.get_revision(location)
current_rev = cls.get_revision(location)
return make_vcs_requirement_url(repo, current_rev, project_name)

def is_commit_id_equal(self, dest, name):
Expand Down
34 changes: 19 additions & 15 deletions src/pip/_internal/vcs/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ def update(self, dest, url, rev_options):
#: update submodules
self.update_submodules(dest)

def get_remote_url(self, location):
@classmethod
def get_remote_url(cls, location):
"""
Return URL of the first remote encountered.
Expand All @@ -258,7 +259,7 @@ def get_remote_url(self, location):
"""
# We need to pass 1 for extra_ok_returncodes since the command
# exits with return code 1 if there are no matching lines.
stdout = self.run_command(
stdout = cls.run_command(
['config', '--get-regexp', r'remote\..*\.url'],
extra_ok_returncodes=(1, ), show_stdout=False, cwd=location,
)
Expand All @@ -275,19 +276,21 @@ def get_remote_url(self, location):
url = found_remote.split(' ')[1]
return url.strip()

def get_revision(self, location, rev=None):
@classmethod
def get_revision(cls, location, rev=None):
if rev is None:
rev = 'HEAD'
current_rev = self.run_command(
current_rev = cls.run_command(
['rev-parse', rev], show_stdout=False, cwd=location,
)
return current_rev.strip()

def _get_subdirectory(self, location):
@classmethod
def _get_subdirectory(cls, location):
"""Return the relative path of setup.py to the git repo root."""
# find the repo root
git_dir = self.run_command(['rev-parse', '--git-dir'],
show_stdout=False, cwd=location).strip()
git_dir = cls.run_command(['rev-parse', '--git-dir'],
show_stdout=False, cwd=location).strip()
if not os.path.isabs(git_dir):
git_dir = os.path.join(location, git_dir)
root_dir = os.path.join(git_dir, '..')
Expand All @@ -310,12 +313,13 @@ def _get_subdirectory(self, location):
return None
return os.path.relpath(location, root_dir)

def get_src_requirement(self, location, project_name):
repo = self.get_remote_url(location)
@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 = self.get_revision(location)
subdir = self._get_subdirectory(location)
current_rev = cls.get_revision(location)
subdir = cls._get_subdirectory(location)
req = make_vcs_requirement_url(repo, current_rev, project_name,
subdir=subdir)

Expand Down Expand Up @@ -351,10 +355,10 @@ def controls_location(cls, location):
if super(Git, cls).controls_location(location):
return True
try:
r = cls().run_command(['rev-parse'],
cwd=location,
show_stdout=False,
on_returncode='ignore')
r = cls.run_command(['rev-parse'],
cwd=location,
show_stdout=False,
on_returncode='ignore')
return not r
except BadCommand:
logger.debug("could not determine if %s is under git control "
Expand Down
24 changes: 14 additions & 10 deletions src/pip/_internal/vcs/mercurial.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,31 +64,35 @@ def update(self, dest, url, rev_options):
cmd_args = ['update', '-q'] + rev_options.to_args()
self.run_command(cmd_args, cwd=dest)

def get_remote_url(self, location):
url = self.run_command(
@classmethod
def get_remote_url(cls, location):
url = cls.run_command(
['showconfig', 'paths.default'],
show_stdout=False, cwd=location).strip()
if self._is_local_repository(url):
if cls._is_local_repository(url):
url = path_to_url(url)
return url.strip()

def get_revision(self, location):
current_revision = self.run_command(
@classmethod
def get_revision(cls, location):
current_revision = cls.run_command(
['parents', '--template={rev}'],
show_stdout=False, cwd=location).strip()
return current_revision

def get_revision_hash(self, location):
current_rev_hash = self.run_command(
@classmethod
def get_revision_hash(cls, location):
current_rev_hash = cls.run_command(
['parents', '--template={node}'],
show_stdout=False, cwd=location).strip()
return current_rev_hash

def get_src_requirement(self, location, project_name):
repo = self.get_remote_url(location)
@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 = self.get_revision_hash(location)
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):
Expand Down
30 changes: 17 additions & 13 deletions src/pip/_internal/vcs/subversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,24 +60,25 @@ def update(self, dest, url, rev_options):
cmd_args = ['update'] + rev_options.to_args() + [dest]
self.run_command(cmd_args)

def get_revision(self, location):
@classmethod
def get_revision(cls, location):
"""
Return the maximum revision for all files under a given location
"""
# Note: taken from setuptools.command.egg_info
revision = 0

for base, dirs, files in os.walk(location):
if self.dirname not in dirs:
if cls.dirname not in dirs:
dirs[:] = []
continue # no sense walking uncontrolled subdirs
dirs.remove(self.dirname)
entries_fn = os.path.join(base, self.dirname, 'entries')
dirs.remove(cls.dirname)
entries_fn = os.path.join(base, cls.dirname, 'entries')
if not os.path.exists(entries_fn):
# FIXME: should we warn?
continue

dirurl, localrev = self._get_svn_url_rev(base)
dirurl, localrev = cls._get_svn_url_rev(base)

if base == location:
base = dirurl + '/' # save the root url
Expand Down Expand Up @@ -116,7 +117,8 @@ def make_rev_args(self, username, password):

return extra_args

def get_remote_url(self, location):
@classmethod
def get_remote_url(cls, location):
# In cases where the source is in a subdirectory, not alongside
# setup.py we have to look up in the location until we find a real
# setup.py
Expand All @@ -134,12 +136,13 @@ def get_remote_url(self, location):
)
return None

return self._get_svn_url_rev(location)[0]
return cls._get_svn_url_rev(location)[0]

def _get_svn_url_rev(self, location):
@classmethod
def _get_svn_url_rev(cls, location):
from pip._internal.exceptions import InstallationError

entries_path = os.path.join(location, self.dirname, 'entries')
entries_path = os.path.join(location, cls.dirname, 'entries')
if os.path.exists(entries_path):
with open(entries_path) as f:
data = f.read()
Expand All @@ -162,7 +165,7 @@ def _get_svn_url_rev(self, location):
else:
try:
# subversion >= 1.7
xml = self.run_command(
xml = cls.run_command(
['info', '--xml', location],
show_stdout=False,
)
Expand All @@ -180,12 +183,13 @@ def _get_svn_url_rev(self, location):

return url, rev

def get_src_requirement(self, location, project_name):
repo = self.get_remote_url(location)
@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 = self.get_revision(location)
rev = cls.get_revision(location)
return make_vcs_requirement_url(repo, rev, project_name)

def is_commit_id_equal(self, dest, name):
Expand Down
11 changes: 5 additions & 6 deletions tests/functional/test_vcs_git.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def test_git_dir_ignored(tmpdir):

env = {'GIT_DIR': 'foo'}
# If GIT_DIR is not ignored, then os.listdir() will return ['foo'].
Git().run_command(['init', repo_dir], cwd=repo_dir, extra_environ=env)
Git.run_command(['init', repo_dir], cwd=repo_dir, extra_environ=env)
assert os.listdir(repo_dir) == ['.git']


Expand All @@ -70,13 +70,12 @@ def test_git_work_tree_ignored(tmpdir):
repo_path.mkdir()
repo_dir = str(repo_path)

git = Git()
git.run_command(['init', repo_dir], cwd=repo_dir)
Git.run_command(['init', repo_dir], cwd=repo_dir)
# Choose a directory relative to the cwd that does not exist.
# If GIT_WORK_TREE is not ignored, then the command will error out
# with: "fatal: This operation must be run in a work tree".
env = {'GIT_WORK_TREE': 'foo'}
git.run_command(['status', repo_dir], extra_environ=env, cwd=repo_dir)
Git.run_command(['status', repo_dir], extra_environ=env, cwd=repo_dir)


def test_get_remote_url(script, tmpdir):
Expand All @@ -91,7 +90,7 @@ def test_get_remote_url(script, tmpdir):
repo_dir = str(tmpdir / 'repo')
script.run('git', 'clone', source_url, repo_dir, expect_stderr=True)

remote_url = Git().get_remote_url(repo_dir)
remote_url = Git.get_remote_url(repo_dir)
assert remote_url == source_url


Expand All @@ -106,7 +105,7 @@ def test_get_remote_url__no_remote(script, tmpdir):
script.run('git', 'init', cwd=repo_dir)

with pytest.raises(RemoteNotFoundError):
Git().get_remote_url(repo_dir)
Git.get_remote_url(repo_dir)


def test_get_current_branch(script):
Expand Down
Loading

0 comments on commit 2a6d282

Please sign in to comment.