Merge lp:~jelmer/brz/rcp-url into lp:brz

Proposed by Jelmer Vernooij on 2019-02-05
Status: Merged
Approved by: Jelmer Vernooij on 2019-03-03
Approved revision: 7269
Merge reported by: The Breezy Bot
Merged at revision: not available
Proposed branch: lp:~jelmer/brz/rcp-url
Merge into: lp:brz
Diff against target: 189 lines (+79/-12)
6 files modified
breezy/directory_service.py (+2/-2)
breezy/location.py (+33/-2)
breezy/tests/test_location.py (+26/-0)
breezy/tests/test_transport.py (+7/-5)
breezy/transport/remote.py (+7/-3)
doc/en/release-notes/brz-3.0.txt (+4/-0)
To merge this branch: bzr merge lp:~jelmer/brz/rcp-url
Reviewer Review Type Date Requested Status
Martin Packman 2019-02-05 Approve on 2019-02-14
Review via email: mp+362712@code.launchpad.net

Commit message

Add support for rcp-style location string for SSH operations.

Description of the change

Add support for rcp-style location stringfor SSH operations.

For the moment, these are converted to ssh:// URLs. Breezy prints an error when
opening these, suggesting the user use either bzr+ssh or git+ssh. This is not
ideal, but better than giving a more confusing error.

Unfortunately this requires some heuristics, since it may be hard to tell apart
real "URLs" and RCP style location strings. E.g. "http:foo".

To post a comment you must log in.
Martin Packman (gz) wrote :

Thanks, seem couple of comments inline.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'breezy/directory_service.py'
2--- breezy/directory_service.py 2019-02-09 03:23:20 +0000
3+++ breezy/directory_service.py 2019-03-03 20:13:19 +0000
4@@ -185,8 +185,8 @@
5
6 def look_up(self, name, url, purpose=None):
7 dir = _mod_controldir.ControlDir.open_containing('.')[0]
8- return urlutils.join_segment_parameters(dir.user_url,
9- {"branch": urlutils.escape(name)})
10+ return urlutils.join_segment_parameters(
11+ dir.user_url, {"branch": urlutils.escape(name)})
12
13
14 directories.register('co:', ColocatedDirectory,
15
16=== modified file 'breezy/location.py'
17--- breezy/location.py 2019-02-09 03:23:20 +0000
18+++ breezy/location.py 2019-03-03 20:13:19 +0000
19@@ -19,6 +19,8 @@
20
21 from __future__ import absolute_import
22
23+import re
24+
25 from . import (
26 urlutils,
27 )
28@@ -44,6 +46,28 @@
29 hooks = LocationHooks()
30
31
32+def rcp_location_to_url(location, scheme='ssh'):
33+ """Convert a rcp-style location to a URL.
34+
35+ :param location: Location to convert, e.g. "foo:bar"
36+ :param schenme: URL scheme to return, defaults to "ssh"
37+ :return: A URL, e.g. "ssh://foo/bar"
38+ :raises ValueError: if this is not a RCP-style URL
39+ """
40+ m = re.match('^(?P<user>[^@:/]+@)?(?P<host>[^/:]+):(?P<path>.*)$', location)
41+ if not m:
42+ raise ValueError("Not a RCP URL")
43+ if m.group('path').startswith('//'):
44+ raise ValueError("Not a RCP URL: already looks like a URL")
45+ quoted_user = urlutils.quote(m.group('user')[:-1]) if m.group('user') else None
46+ url = urlutils.URL(
47+ scheme=scheme, quoted_user=quoted_user,
48+ port=None, quoted_password=None,
49+ quoted_host=urlutils.quote(m.group('host')),
50+ quoted_path=urlutils.quote(m.group('path')))
51+ return str(url)
52+
53+
54 def location_to_url(location, purpose=None):
55 """Determine a fully qualified URL from a location string.
56
57@@ -65,8 +89,8 @@
58 location = location.encode('ascii')
59 except UnicodeError:
60 if urlutils.is_url(location):
61- raise urlutils.InvalidURL(path=location,
62- extra='URLs must be properly escaped')
63+ raise urlutils.InvalidURL(
64+ path=location, extra='URLs must be properly escaped')
65 location = urlutils.local_path_to_url(location)
66 else:
67 if PY3:
68@@ -75,6 +99,13 @@
69 if location.startswith("file:") and not location.startswith("file://"):
70 return urlutils.join(urlutils.local_path_to_url("."), location[5:])
71
72+ try:
73+ url = rcp_location_to_url(location, scheme="ssh")
74+ except ValueError:
75+ pass
76+ else:
77+ return url
78+
79 if not urlutils.is_url(location):
80 return urlutils.local_path_to_url(location)
81
82
83=== modified file 'breezy/tests/test_location.py'
84--- breezy/tests/test_location.py 2019-02-09 02:59:15 +0000
85+++ breezy/tests/test_location.py 2019-03-03 20:13:19 +0000
86@@ -25,6 +25,7 @@
87 from ..location import (
88 hooks as location_hooks,
89 location_to_url,
90+ rcp_location_to_url,
91 )
92
93
94@@ -75,6 +76,11 @@
95 def test_absolute_file_url(self):
96 self.assertEqual("file:///bar", location_to_url("file:/bar"))
97
98+ def test_rcp_url(self):
99+ self.assertEqual(
100+ "ssh://example.com/srv/git/bar",
101+ location_to_url("example.com:/srv/git/bar"))
102+
103 def test_rewrite_hook(self):
104 self.assertEqual(
105 'http://foo.example.com/blah', location_to_url('http://foo.example.com/blah'))
106@@ -84,3 +90,23 @@
107 location_hooks.install_named_hook('rewrite_url', rewrite_url, 'test')
108 self.assertEqual(
109 'http://bar.example.com/bar', location_to_url('http://foo.example.com/foo'))
110+
111+
112+class RCPLocationTests(tests.TestCase):
113+
114+ def test_without_user(self):
115+ self.assertEqual(
116+ "git+ssh://example.com/srv/git/bar",
117+ rcp_location_to_url("example.com:/srv/git/bar", scheme='git+ssh'))
118+ self.assertEqual(
119+ "ssh://example.com/srv/git/bar",
120+ rcp_location_to_url("example.com:/srv/git/bar"))
121+
122+ def test_with_user(self):
123+ self.assertEqual(
124+ "git+ssh://foo@example.com/srv/git/bar",
125+ rcp_location_to_url("foo@example.com:/srv/git/bar", scheme='git+ssh'))
126+
127+ def test_invalid(self):
128+ self.assertRaises(ValueError, rcp_location_to_url, "http://srv/git/bar")
129+ self.assertRaises(ValueError, rcp_location_to_url, "git/bar")
130
131=== modified file 'breezy/tests/test_transport.py'
132--- breezy/tests/test_transport.py 2018-11-23 23:51:34 +0000
133+++ breezy/tests/test_transport.py 2019-03-03 20:13:19 +0000
134@@ -119,11 +119,13 @@
135 try:
136 transport.get_transport_from_url('ssh://fooserver/foo')
137 except errors.UnsupportedProtocol as e:
138- self.assertEqual('Unsupported protocol'
139- ' for url "ssh://fooserver/foo":'
140- ' bzr supports bzr+ssh to operate over ssh,'
141- ' use "bzr+ssh://fooserver/foo".',
142- str(e))
143+ self.assertEqual(
144+ 'Unsupported protocol'
145+ ' for url "ssh://fooserver/foo":'
146+ ' Use bzr+ssh for Bazaar operations over SSH, '
147+ 'e.g. "bzr+ssh://fooserver/foo". Use git+ssh '
148+ 'for Git operations over SSH, e.g. "git+ssh://fooserver/foo".',
149+ str(e))
150 else:
151 self.fail('Did not raise UnsupportedProtocol')
152
153
154=== modified file 'breezy/transport/remote.py'
155--- breezy/transport/remote.py 2018-11-11 04:08:32 +0000
156+++ breezy/transport/remote.py 2019-03-03 20:13:19 +0000
157@@ -602,11 +602,15 @@
158
159
160 class HintingSSHTransport(transport.Transport):
161- """Simple transport that handles ssh:// and points out bzr+ssh://."""
162+ """Simple transport that handles ssh:// and points out bzr+ssh:// and git+ssh://."""
163+
164+ # TODO(jelmer): Implement support for detecting whether the repository at the
165+ # other end is a git or bzr repository.
166
167 def __init__(self, url):
168- raise errors.UnsupportedProtocol(url,
169- 'bzr supports bzr+ssh to operate over ssh, use "bzr+%s".' % url)
170+ raise errors.UnsupportedProtocol(
171+ url, 'Use bzr+ssh for Bazaar operations over SSH, e.g. "bzr+%s". '
172+ 'Use git+ssh for Git operations over SSH, e.g. "git+%s".' % (url, url))
173
174
175 def get_test_permutations():
176
177=== modified file 'doc/en/release-notes/brz-3.0.txt'
178--- doc/en/release-notes/brz-3.0.txt 2019-02-14 06:21:45 +0000
179+++ doc/en/release-notes/brz-3.0.txt 2019-03-03 20:13:19 +0000
180@@ -137,6 +137,10 @@
181 * Plugins can now be registered using the 'entrypoints' mechanism in
182 setuptools. (Jelmer Vernooń≥, #1802647)
183
184+ * The Breezy UI now handles RCP-style URLs and suggests the
185+ user specify either ``git+ssh`` or ``bzr+ssh``.
186+ (Jelmer Vernooń≥)
187+
188 Improvements
189 ************
190

Subscribers

People subscribed via source and target branches