Repository: pypa/pip

Issue:
pip install -e svn+ssh do not take care of the user specified in the URL
* Pip version: 10.0.1
* Python version: 2.7
* Operating system: Ubuntu 16.04, Centos 7.4

### Description:

`pip install -e svn+ssh://myuser@myhost/mypath#egg=mydestdir`

Does a 

`svn checkout --username myuser svn+ssh://myhost/mypath`

The problem is that --username option is not used by SVN with svn+ssh URLs (SVN 1.9.3/Ubuntu 16.04)

Only this works :

`svn checkout svn+ssh://myuser@myhost/mypath`

Suggestion : 

On svn+ssh URLs : do not extract user and password from URL given to pip and give the URL "as is" to the svn command

Workaround : 

use '%40' instead of '@' when specifying svn+ssh URLs having a user specified

### What I've run:

see https://stackoverflow.com/questions/50179270/pip-install-e-svnssh-do-not-take-the-user/
pip install -e svn+ssh do not take care of the user specified in the URL
* Pip version: 10.0.1
* Python version: 2.7
* Operating system: Ubuntu 16.04, Centos 7.4

### Description:

`pip install -e svn+ssh://myuser@myhost/mypath#egg=mydestdir`

Does a 

`svn checkout --username myuser svn+ssh://myhost/mypath`

The problem is that --username option is not used by SVN with svn+ssh URLs (SVN 1.9.3/Ubuntu 16.04)

Only this works :

`svn checkout svn+ssh://myuser@myhost/mypath`

Suggestion : 

On svn+ssh URLs : do not extract user and password from URL given to pip and give the URL "as is" to the svn command

Workaround : 

use '%40' instead of '@' when specifying svn+ssh URLs having a user specified

### What I've run:

see https://stackoverflow.com/questions/50179270/pip-install-e-svnssh-do-not-take-the-user/


Discussion:
Hey @elapouya!

I see that you have a commit on your fork with what seems to be a fix for this issue. Could you make a PR for it?

Hi !

I already made the Pull Request #5377

2018-05-10 14:26 GMT+02:00 Pradyun Gedam <notifications@github.com>:

> Hey @elapouya <https://github.com/elapouya>!
>
> I see that you have a commit on your fork with what seems to be a fix for
> this issue. Could you make a PR for it?
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <https://github.com/pypa/pip/issues/5375#issuecomment-388038669>, or mute
> the thread
> <https://github.com/notifications/unsubscribe-auth/AA2N7ESQLw82pbheth0jMzobsNCVGcqnks5txDIAgaJpZM4T0gMF>
> .
>

Oh. I missed that. Thanks. I've added a reference to this from there. :)
Hey @elapouya!

I see that you have a commit on your fork with what seems to be a fix for this issue. Could you make a PR for it?

Hi !

I already made the Pull Request #5377

2018-05-10 14:26 GMT+02:00 Pradyun Gedam <notifications@github.com>:

> Hey @elapouya <https://github.com/elapouya>!
>
> I see that you have a commit on your fork with what seems to be a fix for
> this issue. Could you make a PR for it?
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <https://github.com/pypa/pip/issues/5375#issuecomment-388038669>, or mute
> the thread
> <https://github.com/notifications/unsubscribe-auth/AA2N7ESQLw82pbheth0jMzobsNCVGcqnks5txDIAgaJpZM4T0gMF>
> .
>

Oh. I missed that. Thanks. I've added a reference to this from there. :)

Resolving patch:
diff --git a/src/pip/_internal/vcs/__init__.py b/src/pip/_internal/vcs/__init__.py
--- a/src/pip/_internal/vcs/__init__.py
+++ b/src/pip/_internal/vcs/__init__.py
@@ -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
@@ -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)
diff --git a/src/pip/_internal/vcs/subversion.py b/src/pip/_internal/vcs/subversion.py
--- a/src/pip/_internal/vcs/subversion.py
+++ b/src/pip/_internal/vcs/subversion.py
@@ -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):


Test patch:
diff --git a/tests/unit/test_vcs.py b/tests/unit/test_vcs.py
--- a/tests/unit/test_vcs.py
+++ b/tests/unit/test_vcs.py
@@ -124,33 +124,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:pass@example.com', ('user:pass@example.com', (None, None))),
+    (('user:pass@example.com', 'https'),
+     ('user:pass@example.com', (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.
-    ('user@example.com', ('example.com', ('user', None))),
-    # Test with username and password.
-    ('user:pass@example.com', ('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.
+    (('user@example.com', 'https'), ('example.com', ('user', None))),
+    # Test https with username and password.
+    (('user:pass@example.com', 'https'), ('example.com', ('user', 'pass'))),
+    # Test ssh with username and password.
+    (('user:pass@example.com', 'ssh'),
+     ('user:pass@example.com', (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
 
 
@@ -247,6 +253,28 @@ def test_bazaar__get_url_rev_and_auth():
     )
 
 
+@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:pass@svn.example.com/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://user@svn.example.com/MyProject#egg=MyProject',
+     ('svn+ssh://user@svn.example.com/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', [