Skip to content

Commit 2b3609a

Browse files
authored
Merge pull request #5664 from cjerdonek/issue-5375-svn-ssh-auth
Fix #5375: add editable install support for svn+ssh URLs with a username
2 parents 2ce7b28 + e1d60f8 commit 2b3609a

File tree

5 files changed

+62
-17
lines changed

5 files changed

+62
-17
lines changed

docs/reference/pip_install.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,12 @@ Subversion
426426

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

429+
Here are some of the supported forms::
430+
431+
[-e] svn+https://svn.example.com/MyProject#egg=MyProject
432+
[-e] svn+ssh://svn.example.com/MyProject#egg=MyProject
433+
[-e] svn+ssh://[email protected]/MyProject#egg=MyProject
434+
429435
You can also give specific revisions to an SVN URL, like so::
430436

431437
[-e] svn+svn://svn.example.com/svn/MyProject#egg=MyProject

news/5375.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Support passing ``svn+ssh`` URLs with a username to ``pip install -e``.

src/pip/_internal/vcs/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,11 +207,15 @@ def export(self, location):
207207
"""
208208
raise NotImplementedError
209209

210-
def get_netloc_and_auth(self, netloc):
210+
def get_netloc_and_auth(self, netloc, scheme):
211211
"""
212212
Parse the repository URL's netloc, and return the new netloc to use
213213
along with auth information.
214214
215+
Args:
216+
netloc: the original repository URL netloc.
217+
scheme: the repository URL's scheme without the vcs prefix.
218+
215219
This is mainly for the Subversion class to override, so that auth
216220
information can be provided via the --username and --password options
217221
instead of through the URL. For other subclasses like Git without
@@ -237,7 +241,7 @@ def get_url_rev_and_auth(self, url):
237241
)
238242
# Remove the vcs prefix.
239243
scheme = scheme.split('+', 1)[1]
240-
netloc, user_pass = self.get_netloc_and_auth(netloc)
244+
netloc, user_pass = self.get_netloc_and_auth(netloc, scheme)
241245
rev = None
242246
if '@' in path:
243247
path, rev = path.rsplit('@', 1)

src/pip/_internal/vcs/subversion.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,17 @@ def get_revision(self, location):
102102
revision = max(revision, localrev)
103103
return revision
104104

105-
def get_netloc_and_auth(self, netloc):
105+
def get_netloc_and_auth(self, netloc, scheme):
106106
"""
107107
This override allows the auth information to be passed to svn via the
108108
--username and --password options instead of via the URL.
109109
"""
110+
if scheme == 'ssh':
111+
# The --username and --password options can't be used for
112+
# svn+ssh URLs, so keep the auth information in the URL.
113+
return super(Subversion, self).get_netloc_and_auth(
114+
netloc, scheme)
115+
110116
return split_auth_from_netloc(netloc)
111117

112118
def get_url_rev_and_auth(self, url):

tests/unit/test_vcs.py

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -169,33 +169,39 @@ def test_git_is_commit_id_equal(git, rev_name, result):
169169

170170
# The non-SVN backends all use the same get_netloc_and_auth(), so only test
171171
# Git as a representative.
172-
@pytest.mark.parametrize('netloc, expected', [
172+
@pytest.mark.parametrize('args, expected', [
173173
# Test a basic case.
174-
('example.com', ('example.com', (None, None))),
174+
(('example.com', 'https'), ('example.com', (None, None))),
175175
# Test with username and password.
176-
('user:[email protected]', ('user:[email protected]', (None, None))),
176+
(('user:[email protected]', 'https'),
177+
('user:[email protected]', (None, None))),
177178
])
178-
def test_git__get_netloc_and_auth(netloc, expected):
179+
def test_git__get_netloc_and_auth(args, expected):
179180
"""
180181
Test VersionControl.get_netloc_and_auth().
181182
"""
182-
actual = Git().get_netloc_and_auth(netloc)
183+
netloc, scheme = args
184+
actual = Git().get_netloc_and_auth(netloc, scheme)
183185
assert actual == expected
184186

185187

186-
@pytest.mark.parametrize('netloc, expected', [
187-
# Test a basic case.
188-
('example.com', ('example.com', (None, None))),
189-
# Test with username and no password.
190-
('[email protected]', ('example.com', ('user', None))),
191-
# Test with username and password.
192-
('user:[email protected]', ('example.com', ('user', 'pass'))),
188+
@pytest.mark.parametrize('args, expected', [
189+
# Test https.
190+
(('example.com', 'https'), ('example.com', (None, None))),
191+
# Test https with username and no password.
192+
(('[email protected]', 'https'), ('example.com', ('user', None))),
193+
# Test https with username and password.
194+
(('user:[email protected]', 'https'), ('example.com', ('user', 'pass'))),
195+
# Test ssh with username and password.
196+
(('user:[email protected]', 'ssh'),
197+
('user:[email protected]', (None, None))),
193198
])
194-
def test_subversion__get_netloc_and_auth(netloc, expected):
199+
def test_subversion__get_netloc_and_auth(args, expected):
195200
"""
196201
Test Subversion.get_netloc_and_auth().
197202
"""
198-
actual = Subversion().get_netloc_and_auth(netloc)
203+
netloc, scheme = args
204+
actual = Subversion().get_netloc_and_auth(netloc, scheme)
199205
assert actual == expected
200206

201207

@@ -276,6 +282,28 @@ def test_bazaar__get_url_rev_and_auth(url, expected):
276282
assert actual == (expected, None, (None, None))
277283

278284

285+
@pytest.mark.parametrize('url, expected', [
286+
# Test an https URL.
287+
('svn+https://svn.example.com/MyProject#egg=MyProject',
288+
('https://svn.example.com/MyProject', None, (None, None))),
289+
# Test an https URL with a username and password.
290+
('svn+https://user:[email protected]/MyProject#egg=MyProject',
291+
('https://svn.example.com/MyProject', None, ('user', 'pass'))),
292+
# Test an ssh URL.
293+
('svn+ssh://svn.example.com/MyProject#egg=MyProject',
294+
('svn+ssh://svn.example.com/MyProject', None, (None, None))),
295+
# Test an ssh URL with a username.
296+
('svn+ssh://[email protected]/MyProject#egg=MyProject',
297+
('svn+ssh://[email protected]/MyProject', None, (None, None))),
298+
])
299+
def test_subversion__get_url_rev_and_auth(url, expected):
300+
"""
301+
Test Subversion.get_url_rev_and_auth().
302+
"""
303+
actual = Subversion().get_url_rev_and_auth(url)
304+
assert actual == expected
305+
306+
279307
# The non-SVN backends all use the same make_rev_args(), so only test
280308
# Git as a representative.
281309
@pytest.mark.parametrize('username, password, expected', [

0 commit comments

Comments
 (0)