Skip to content

Commit

Permalink
Merge pull request #5664 from cjerdonek/issue-5375-svn-ssh-auth
Browse files Browse the repository at this point in the history
Fix #5375: add editable install support for svn+ssh URLs with a username
  • Loading branch information
pradyunsg authored Aug 22, 2018
2 parents 2ce7b28 + e1d60f8 commit 2b3609a
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 17 deletions.
6 changes: 6 additions & 0 deletions docs/reference/pip_install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,12 @@ Subversion

pip supports the URL schemes ``svn``, ``svn+svn``, ``svn+http``, ``svn+https``, ``svn+ssh``.

Here are some of the supported forms::

[-e] svn+https://svn.example.com/MyProject#egg=MyProject
[-e] svn+ssh://svn.example.com/MyProject#egg=MyProject
[-e] svn+ssh://[email protected]/MyProject#egg=MyProject

You can also give specific revisions to an SVN URL, like so::

[-e] svn+svn://svn.example.com/svn/MyProject#egg=MyProject
Expand Down
1 change: 1 addition & 0 deletions news/5375.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support passing ``svn+ssh`` URLs with a username to ``pip install -e``.
8 changes: 6 additions & 2 deletions src/pip/_internal/vcs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,15 @@ def export(self, location):
"""
raise NotImplementedError

def get_netloc_and_auth(self, netloc):
def get_netloc_and_auth(self, netloc, scheme):
"""
Parse the repository URL's netloc, and return the new netloc to use
along with auth information.
Args:
netloc: the original repository URL netloc.
scheme: the repository URL's scheme without the vcs prefix.
This is mainly for the Subversion class to override, so that auth
information can be provided via the --username and --password options
instead of through the URL. For other subclasses like Git without
Expand All @@ -237,7 +241,7 @@ def get_url_rev_and_auth(self, url):
)
# Remove the vcs prefix.
scheme = scheme.split('+', 1)[1]
netloc, user_pass = self.get_netloc_and_auth(netloc)
netloc, user_pass = self.get_netloc_and_auth(netloc, scheme)
rev = None
if '@' in path:
path, rev = path.rsplit('@', 1)
Expand Down
8 changes: 7 additions & 1 deletion src/pip/_internal/vcs/subversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,17 @@ def get_revision(self, location):
revision = max(revision, localrev)
return revision

def get_netloc_and_auth(self, netloc):
def get_netloc_and_auth(self, netloc, scheme):
"""
This override allows the auth information to be passed to svn via the
--username and --password options instead of via the URL.
"""
if scheme == 'ssh':
# The --username and --password options can't be used for
# svn+ssh URLs, so keep the auth information in the URL.
return super(Subversion, self).get_netloc_and_auth(
netloc, scheme)

return split_auth_from_netloc(netloc)

def get_url_rev_and_auth(self, url):
Expand Down
56 changes: 42 additions & 14 deletions tests/unit/test_vcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,33 +169,39 @@ def test_git_is_commit_id_equal(git, rev_name, result):

# The non-SVN backends all use the same get_netloc_and_auth(), so only test
# Git as a representative.
@pytest.mark.parametrize('netloc, expected', [
@pytest.mark.parametrize('args, expected', [
# Test a basic case.
('example.com', ('example.com', (None, None))),
(('example.com', 'https'), ('example.com', (None, None))),
# Test with username and password.
('user:[email protected]', ('user:[email protected]', (None, None))),
(('user:[email protected]', 'https'),
('user:[email protected]', (None, None))),
])
def test_git__get_netloc_and_auth(netloc, expected):
def test_git__get_netloc_and_auth(args, expected):
"""
Test VersionControl.get_netloc_and_auth().
"""
actual = Git().get_netloc_and_auth(netloc)
netloc, scheme = args
actual = Git().get_netloc_and_auth(netloc, scheme)
assert actual == expected


@pytest.mark.parametrize('netloc, expected', [
# Test a basic case.
('example.com', ('example.com', (None, None))),
# Test with username and no password.
('[email protected]', ('example.com', ('user', None))),
# Test with username and password.
('user:[email protected]', ('example.com', ('user', 'pass'))),
@pytest.mark.parametrize('args, expected', [
# Test https.
(('example.com', 'https'), ('example.com', (None, None))),
# Test https with username and no password.
(('[email protected]', 'https'), ('example.com', ('user', None))),
# Test https with username and password.
(('user:[email protected]', 'https'), ('example.com', ('user', 'pass'))),
# Test ssh with username and password.
(('user:[email protected]', 'ssh'),
('user:[email protected]', (None, None))),
])
def test_subversion__get_netloc_and_auth(netloc, expected):
def test_subversion__get_netloc_and_auth(args, expected):
"""
Test Subversion.get_netloc_and_auth().
"""
actual = Subversion().get_netloc_and_auth(netloc)
netloc, scheme = args
actual = Subversion().get_netloc_and_auth(netloc, scheme)
assert actual == expected


Expand Down Expand Up @@ -276,6 +282,28 @@ def test_bazaar__get_url_rev_and_auth(url, expected):
assert actual == (expected, None, (None, None))


@pytest.mark.parametrize('url, expected', [
# Test an https URL.
('svn+https://svn.example.com/MyProject#egg=MyProject',
('https://svn.example.com/MyProject', None, (None, None))),
# Test an https URL with a username and password.
('svn+https://user:[email protected]/MyProject#egg=MyProject',
('https://svn.example.com/MyProject', None, ('user', 'pass'))),
# Test an ssh URL.
('svn+ssh://svn.example.com/MyProject#egg=MyProject',
('svn+ssh://svn.example.com/MyProject', None, (None, None))),
# Test an ssh URL with a username.
('svn+ssh://[email protected]/MyProject#egg=MyProject',
('svn+ssh://[email protected]/MyProject', None, (None, None))),
])
def test_subversion__get_url_rev_and_auth(url, expected):
"""
Test Subversion.get_url_rev_and_auth().
"""
actual = Subversion().get_url_rev_and_auth(url)
assert actual == expected


# The non-SVN backends all use the same make_rev_args(), so only test
# Git as a representative.
@pytest.mark.parametrize('username, password, expected', [
Expand Down

0 comments on commit 2b3609a

Please sign in to comment.