diff --git a/news/408CCC8B-0506-40B2-B108-616C18016E59.trivial b/news/408CCC8B-0506-40B2-B108-616C18016E59.trivial new file mode 100644 index 000000000..e69de29bb diff --git a/src/pip/_internal/vcs/__init__.py b/src/pip/_internal/vcs/__init__.py index 08bd71fa8..704f1c3fa 100644 --- a/src/pip/_internal/vcs/__init__.py +++ b/src/pip/_internal/vcs/__init__.py @@ -213,7 +213,7 @@ class VersionControl(object): """ raise NotImplementedError - def get_url_rev(self): + def get_url_rev(self, url): """ Returns the correct repository URL and revision by parsing the given repository URL @@ -223,8 +223,8 @@ class VersionControl(object): "The format is +://, " "e.g. svn+http://myrepo/svn/MyApp#egg=MyApp" ) - assert '+' in self.url, error_message % self.url - url = self.url.split('+', 1)[1] + assert '+' in url, error_message % url + url = url.split('+', 1)[1] scheme, netloc, path, query, frag = urllib_parse.urlsplit(url) rev = None if '@' in path: @@ -239,12 +239,12 @@ class VersionControl(object): """ return url, [] - def get_url_rev_options(self): + def get_url_rev_options(self, url): """ - Return the URL and RevOptions object to use in obtain(), as a tuple - (url, rev_options). + Return the URL and RevOptions object to use in obtain() and in + some cases export(), as a tuple (url, rev_options). """ - url, rev = self.get_url_rev() + url, rev = self.get_url_rev(url) url, extra_args = self.get_url_rev_args(url) rev_options = self.make_rev_options(rev, extra_args=extra_args) @@ -318,7 +318,7 @@ class VersionControl(object): Args: dest: the repository directory in which to install or update. """ - url, rev_options = self.get_url_rev_options() + url, rev_options = self.get_url_rev_options(self.url) if not os.path.exists(dest): self.fetch_new(dest, url, rev_options) diff --git a/src/pip/_internal/vcs/bazaar.py b/src/pip/_internal/vcs/bazaar.py index 80c14903f..93b76165a 100644 --- a/src/pip/_internal/vcs/bazaar.py +++ b/src/pip/_internal/vcs/bazaar.py @@ -66,9 +66,9 @@ class Bazaar(VersionControl): cmd_args = ['pull', '-q'] + rev_options.to_args() self.run_command(cmd_args, cwd=dest) - def get_url_rev(self): + def get_url_rev(self, url): # hotfix the URL scheme after removing bzr+ from bzr+ssh:// readd it - url, rev = super(Bazaar, self).get_url_rev() + url, rev = super(Bazaar, self).get_url_rev(url) if url.startswith('ssh://'): url = 'bzr+' + url return url, rev diff --git a/src/pip/_internal/vcs/git.py b/src/pip/_internal/vcs/git.py index 6bda129a8..9ee2e012f 100644 --- a/src/pip/_internal/vcs/git.py +++ b/src/pip/_internal/vcs/git.py @@ -265,20 +265,20 @@ class Git(VersionControl): req += '&subdirectory=' + subdirectory return req - def get_url_rev(self): + def get_url_rev(self, url): """ Prefixes stub URLs like 'user@hostname:user/repo.git' with 'ssh://'. That's required because although they use SSH they sometimes don't work with a ssh:// scheme (e.g. GitHub). But we need a scheme for parsing. Hence we remove it again afterwards and return it as a stub. """ - if '://' not in self.url: - assert 'file:' not in self.url - self.url = self.url.replace('git+', 'git+ssh://') - url, rev = super(Git, self).get_url_rev() + if '://' not in url: + assert 'file:' not in url + url = url.replace('git+', 'git+ssh://') + url, rev = super(Git, self).get_url_rev(url) url = url.replace('ssh://', '') else: - url, rev = super(Git, self).get_url_rev() + url, rev = super(Git, self).get_url_rev(url) return url, rev diff --git a/src/pip/_internal/vcs/subversion.py b/src/pip/_internal/vcs/subversion.py index f42aa2f43..70787750b 100644 --- a/src/pip/_internal/vcs/subversion.py +++ b/src/pip/_internal/vcs/subversion.py @@ -61,7 +61,7 @@ class Subversion(VersionControl): def export(self, location): """Export the svn repository at the url to the destination location""" - url, rev_options = self.get_url_rev_options() + url, rev_options = self.get_url_rev_options(self.url) logger.info('Exporting svn repository %s to %s', url, location) with indent_log(): @@ -132,9 +132,9 @@ class Subversion(VersionControl): revision = max(revision, localrev) return revision - def get_url_rev(self): + def get_url_rev(self, url): # hotfix the URL scheme after removing svn+ from svn+ssh:// readd it - url, rev = super(Subversion, self).get_url_rev() + url, rev = super(Subversion, self).get_url_rev(url) if url.startswith('ssh://'): url = 'svn+' + url return url, rev diff --git a/tests/unit/test_vcs.py b/tests/unit/test_vcs.py index 46e0d66ef..c9bb882a9 100644 --- a/tests/unit/test_vcs.py +++ b/tests/unit/test_vcs.py @@ -129,7 +129,23 @@ def test_translate_egg_surname(): assert vc.translate_egg_surname("foo/1.2.3") == "foo_1.2.3" -def test_bazaar_simple_urls(): +def test_git__get_url_rev__idempotent(): + """ + Check that Git.get_url_rev() is idempotent for what the code calls + "stub URLs" (i.e. URLs that don't contain "://"). + + Also check that it doesn't change self.url. + """ + url = 'git+git@git.example.com:MyProject#egg=MyProject' + vcs = Git(url) + result1 = vcs.get_url_rev(url) + assert vcs.url == url + result2 = vcs.get_url_rev(url) + assert result1 == ('git@git.example.com:MyProject', None) + assert result2 == ('git@git.example.com:MyProject', None) + + +def test_bazaar__get_url_rev(): """ Test bzr url support. @@ -154,22 +170,22 @@ def test_bazaar_simple_urls(): url='bzr+lp:MyLaunchpadProject#egg=MyLaunchpadProject' ) - assert http_bzr_repo.get_url_rev() == ( + assert http_bzr_repo.get_url_rev(http_bzr_repo.url) == ( 'http://bzr.myproject.org/MyProject/trunk/', None, ) - assert https_bzr_repo.get_url_rev() == ( + assert https_bzr_repo.get_url_rev(https_bzr_repo.url) == ( 'https://bzr.myproject.org/MyProject/trunk/', None, ) - assert ssh_bzr_repo.get_url_rev() == ( + assert ssh_bzr_repo.get_url_rev(ssh_bzr_repo.url) == ( 'bzr+ssh://bzr.myproject.org/MyProject/trunk/', None, ) - assert ftp_bzr_repo.get_url_rev() == ( + assert ftp_bzr_repo.get_url_rev(ftp_bzr_repo.url) == ( 'ftp://bzr.myproject.org/MyProject/trunk/', None, ) - assert sftp_bzr_repo.get_url_rev() == ( + assert sftp_bzr_repo.get_url_rev(sftp_bzr_repo.url) == ( 'sftp://bzr.myproject.org/MyProject/trunk/', None, ) - assert launchpad_bzr_repo.get_url_rev() == ( + assert launchpad_bzr_repo.get_url_rev(launchpad_bzr_repo.url) == ( 'lp:MyLaunchpadProject', None, )