Merge lp:~jelmer/brz/move-mergeable into lp:brz

Proposed by Jelmer Vernooij on 2018-11-13
Status: Merged
Approved by: Jelmer Vernooij on 2019-05-29
Approved revision: 7150
Merge reported by: The Breezy Bot
Merged at revision: not available
Proposed branch: lp:~jelmer/brz/move-mergeable
Merge into: lp:brz
Diff against target: 475 lines (+207/-148)
8 files modified
breezy/builtins.py (+5/-5)
breezy/bundle/__init__.py (+0/-72)
breezy/bundle/commands.py (+1/-1)
breezy/mergeable.py (+107/-0)
breezy/tests/__init__.py (+1/-0)
breezy/tests/test_bundle.py (+0/-68)
breezy/tests/test_mergeable.py (+91/-0)
breezy/tests/test_read_bundle.py (+2/-2)
To merge this branch: bzr merge lp:~jelmer/brz/move-mergeable
Reviewer Review Type Date Requested Status
Martin Packman 2018-11-13 Approve on 2019-05-26
Review via email: mp+358676@code.launchpad.net

Commit message

Split mergeable bits out of breezy.bundle.

Description of the change

Split mergeable bits out of breezy.bundle.

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

Thanks!

review: Approve
lp:~jelmer/brz/move-mergeable updated on 2019-05-29
7150. By Jelmer Vernooij on 2019-05-29

Merge trunk.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'breezy/builtins.py'
2--- breezy/builtins.py 2019-05-28 21:53:23 +0000
3+++ breezy/builtins.py 2019-05-29 03:29:58 +0000
4@@ -33,7 +33,6 @@
5 from breezy import (
6 branch as _mod_branch,
7 bugtracker,
8- bundle,
9 cache_utf8,
10 controldir,
11 directory_service,
12@@ -46,6 +45,7 @@
13 lazy_regex,
14 log,
15 merge as _mod_merge,
16+ mergeable as _mod_mergeable,
17 merge_directive,
18 osutils,
19 reconfigure,
20@@ -1210,8 +1210,8 @@
21 possible_transports = []
22 if location is not None:
23 try:
24- mergeable = bundle.read_mergeable_from_url(location,
25- possible_transports=possible_transports)
26+ mergeable = _mod_mergeable.read_mergeable_from_url(
27+ location, possible_transports=possible_transports)
28 except errors.NotABundle:
29 mergeable = None
30
31@@ -4438,8 +4438,8 @@
32 self.add_cleanup(tree.lock_write().unlock)
33 if location is not None:
34 try:
35- mergeable = bundle.read_mergeable_from_url(location,
36- possible_transports=possible_transports)
37+ mergeable = _mod_mergeable.read_mergeable_from_url(
38+ location, possible_transports=possible_transports)
39 except errors.NotABundle:
40 mergeable = None
41 else:
42
43=== modified file 'breezy/bundle/__init__.py'
44--- breezy/bundle/__init__.py 2018-11-11 04:08:32 +0000
45+++ breezy/bundle/__init__.py 2019-05-29 03:29:58 +0000
46@@ -15,75 +15,3 @@
47 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
48
49 from __future__ import absolute_import
50-
51-
52-from ..lazy_import import lazy_import
53-lazy_import(globals(), """
54-from breezy import (
55- errors,
56- transport as _mod_transport,
57- urlutils,
58- )
59-from breezy.bundle import serializer as _serializer
60-from breezy.merge_directive import MergeDirective
61-from breezy.i18n import gettext
62-""")
63-from ..sixish import (
64- BytesIO,
65- )
66-from ..trace import note
67-
68-
69-def read_mergeable_from_url(url, _do_directive=True, possible_transports=None):
70- """Read mergable object from a given URL.
71-
72- :return: An object supporting get_target_revision. Raises NotABundle if
73- the target is not a mergeable type.
74- """
75- child_transport = _mod_transport.get_transport(url,
76- possible_transports=possible_transports)
77- transport = child_transport.clone('..')
78- filename = transport.relpath(child_transport.base)
79- mergeable, transport = read_mergeable_from_transport(transport, filename,
80- _do_directive)
81- return mergeable
82-
83-
84-def read_mergeable_from_transport(transport, filename, _do_directive=True):
85- def get_bundle(transport):
86- return BytesIO(transport.get_bytes(filename)), transport
87-
88- def redirected_transport(transport, exception, redirection_notice):
89- note(redirection_notice)
90- url, filename = urlutils.split(exception.target,
91- exclude_trailing_slash=False)
92- if not filename:
93- raise errors.NotABundle(gettext('A directory cannot be a bundle'))
94- return _mod_transport.get_transport_from_url(url)
95-
96- try:
97- bytef, transport = _mod_transport.do_catching_redirections(
98- get_bundle, transport, redirected_transport)
99- except errors.TooManyRedirections:
100- raise errors.NotABundle(transport.clone(filename).base)
101- except (errors.ConnectionReset, errors.ConnectionError) as e:
102- raise
103- except (errors.TransportError, errors.PathError) as e:
104- raise errors.NotABundle(str(e))
105- except (IOError,) as e:
106- # jam 20060707
107- # Abstraction leakage, SFTPTransport.get('directory')
108- # doesn't always fail at get() time. Sometimes it fails
109- # during read. And that raises a generic IOError with
110- # just the string 'Failure'
111- # StubSFTPServer does fail during get() (because of prefetch)
112- # so it has an opportunity to translate the error.
113- raise errors.NotABundle(str(e))
114-
115- if _do_directive:
116- try:
117- return MergeDirective.from_lines(bytef), transport
118- except errors.NotAMergeDirective:
119- bytef.seek(0)
120-
121- return _serializer.read_bundle(bytef), transport
122
123=== modified file 'breezy/bundle/commands.py'
124--- breezy/bundle/commands.py 2018-11-11 04:08:32 +0000
125+++ breezy/bundle/commands.py 2019-05-29 03:29:58 +0000
126@@ -53,7 +53,7 @@
127
128 def run(self, location, verbose=False):
129 from breezy.bundle.serializer import read_bundle
130- from breezy.bundle import read_mergeable_from_url
131+ from breezy.mergeable import read_mergeable_from_url
132 from breezy import osutils
133 term_encoding = osutils.get_terminal_encoding()
134 bundle_info = read_mergeable_from_url(location)
135
136=== added file 'breezy/mergeable.py'
137--- breezy/mergeable.py 1970-01-01 00:00:00 +0000
138+++ breezy/mergeable.py 2019-05-29 03:29:58 +0000
139@@ -0,0 +1,107 @@
140+# Copyright (C) 2005-2010 Canonical Ltd
141+#
142+# This program is free software; you can redistribute it and/or modify
143+# it under the terms of the GNU General Public License as published by
144+# the Free Software Foundation; either version 2 of the License, or
145+# (at your option) any later version.
146+#
147+# This program is distributed in the hope that it will be useful,
148+# but WITHOUT ANY WARRANTY; without even the implied warranty of
149+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
150+# GNU General Public License for more details.
151+#
152+# You should have received a copy of the GNU General Public License
153+# along with this program; if not, write to the Free Software
154+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
155+
156+from __future__ import absolute_import
157+
158+from .lazy_import import lazy_import
159+lazy_import(globals(), """
160+from breezy import (
161+ errors,
162+ transport as _mod_transport,
163+ urlutils,
164+ )
165+from breezy.bundle import serializer as _serializer
166+from breezy.merge_directive import MergeDirective
167+from breezy.i18n import gettext
168+""")
169+
170+from .sixish import (
171+ BytesIO,
172+ )
173+from .trace import note
174+
175+
176+class Mergeable(object):
177+ """A mergeable object."""
178+
179+ def install_revisions(self, repository):
180+ """Install the data from this mergeable into the specified repository.
181+
182+ :param repository: Repository
183+ """
184+ raise NotImplementedError(self.install_revisions)
185+
186+ def get_merge_request(self, repository):
187+ """Extract merge request data.
188+
189+ :return: tuple with (base_revision_id, target_revision_id, verified)
190+ """
191+ raise NotImplementedError(self.get_merge_request)
192+
193+
194+def read_mergeable_from_url(url, _do_directive=True, possible_transports=None):
195+ """Read mergable object from a given URL.
196+
197+ :return: An object supporting get_target_revision. Raises NotABundle if
198+ the target is not a mergeable type.
199+ """
200+ child_transport = _mod_transport.get_transport(
201+ url, possible_transports=possible_transports)
202+ transport = child_transport.clone('..')
203+ filename = transport.relpath(child_transport.base)
204+ mergeable, transport = read_mergeable_from_transport(transport, filename,
205+ _do_directive)
206+ return mergeable
207+
208+
209+def read_mergeable_from_transport(transport, filename, _do_directive=True):
210+ def get_bundle(transport):
211+ return BytesIO(transport.get_bytes(filename)), transport
212+
213+ def redirected_transport(transport, exception, redirection_notice):
214+ note(redirection_notice)
215+ url, filename = urlutils.split(exception.target,
216+ exclude_trailing_slash=False)
217+ if not filename:
218+ raise errors.NotABundle(gettext('A directory cannot be a bundle'))
219+ return _mod_transport.get_transport_from_url(url)
220+
221+ try:
222+ bytef, transport = _mod_transport.do_catching_redirections(
223+ get_bundle, transport, redirected_transport)
224+ except errors.TooManyRedirections:
225+ raise errors.NotABundle(transport.clone(filename).base)
226+ except (errors.ConnectionReset, errors.ConnectionError) as e:
227+ raise
228+ except (errors.TransportError, errors.PathError) as e:
229+ raise errors.NotABundle(str(e))
230+ except (IOError,) as e:
231+ # jam 20060707
232+ # Abstraction leakage, SFTPTransport.get('directory')
233+ # doesn't always fail at get() time. Sometimes it fails
234+ # during read. And that raises a generic IOError with
235+ # just the string 'Failure'
236+ # StubSFTPServer does fail during get() (because of prefetch)
237+ # so it has an opportunity to translate the error.
238+ raise errors.NotABundle(str(e))
239+
240+ if _do_directive:
241+ try:
242+ return MergeDirective.from_lines(bytef), transport
243+ except errors.NotAMergeDirective:
244+ bytef.seek(0)
245+
246+ return _serializer.read_bundle(bytef), transport
247
248=== modified file 'breezy/tests/__init__.py'
249--- breezy/tests/__init__.py 2019-03-12 05:18:19 +0000
250+++ breezy/tests/__init__.py 2019-05-29 03:29:58 +0000
251@@ -4141,6 +4141,7 @@
252 'breezy.tests.test_memorytree',
253 'breezy.tests.test_merge',
254 'breezy.tests.test_merge3',
255+ 'breezy.tests.test_mergeable',
256 'breezy.tests.test_merge_core',
257 'breezy.tests.test_merge_directive',
258 'breezy.tests.test_mergetools',
259
260=== modified file 'breezy/tests/test_bundle.py'
261--- breezy/tests/test_bundle.py 2019-02-09 02:59:15 +0000
262+++ breezy/tests/test_bundle.py 2019-05-29 03:29:58 +0000
263@@ -17,10 +17,6 @@
264 import bz2
265 from io import BytesIO
266 import os
267-try:
268- import socketserver
269-except ImportError:
270- import SocketServer as socketserver
271 import sys
272
273 from .. import (
274@@ -36,10 +32,8 @@
275 bzrdir,
276 inventory,
277 )
278-from ..bundle import read_mergeable_from_url
279 from ..bundle.apply_bundle import install_bundle, merge_bundle
280 from ..bundle.bundle_data import BundleTree
281-from ..directory_service import directories
282 from ..bundle.serializer import write_bundle, read_bundle, v09, v4
283 from ..bundle.serializer.v08 import BundleSerializerV08
284 from ..bundle.serializer.v09 import BundleSerializerV09
285@@ -48,8 +42,6 @@
286 from . import (
287 features,
288 test_commit,
289- test_read_bundle,
290- test_server,
291 )
292 from ..transform import TreeTransform
293
294@@ -1836,63 +1828,3 @@
295 self.assertEqual((None, {b'foo': b'bar', b'storage_kind': b'header'},
296 'info', None, None), record)
297 self.assertRaises(errors.BadBundle, next, record_iter)
298-
299-
300-class TestReadMergeableFromUrl(tests.TestCaseWithTransport):
301-
302- def test_read_mergeable_skips_local(self):
303- """A local bundle named like the URL should not be read.
304- """
305- out, wt = test_read_bundle.create_bundle_file(self)
306-
307- class FooService(object):
308- """A directory service that always returns source"""
309-
310- def look_up(self, name, url, purpose=None):
311- return 'source'
312- directories.register('foo:', FooService, 'Testing directory service')
313- self.addCleanup(directories.remove, 'foo:')
314- self.build_tree_contents([('./foo:bar', out.getvalue())])
315- self.assertRaises(errors.NotABundle, read_mergeable_from_url,
316- 'foo:bar')
317-
318- def test_infinite_redirects_are_not_a_bundle(self):
319- """If a URL causes TooManyRedirections then NotABundle is raised.
320- """
321- from .blackbox.test_push import RedirectingMemoryServer
322- server = RedirectingMemoryServer()
323- self.start_server(server)
324- url = server.get_url() + 'infinite-loop'
325- self.assertRaises(errors.NotABundle, read_mergeable_from_url, url)
326-
327- def test_smart_server_connection_reset(self):
328- """If a smart server connection fails during the attempt to read a
329- bundle, then the ConnectionReset error should be propagated.
330- """
331- # Instantiate a server that will provoke a ConnectionReset
332- sock_server = DisconnectingServer()
333- self.start_server(sock_server)
334- # We don't really care what the url is since the server will close the
335- # connection without interpreting it
336- url = sock_server.get_url()
337- self.assertRaises(errors.ConnectionReset, read_mergeable_from_url, url)
338-
339-
340-class DisconnectingHandler(socketserver.BaseRequestHandler):
341- """A request handler that immediately closes any connection made to it."""
342-
343- def handle(self):
344- self.request.close()
345-
346-
347-class DisconnectingServer(test_server.TestingTCPServerInAThread):
348-
349- def __init__(self):
350- super(DisconnectingServer, self).__init__(
351- ('127.0.0.1', 0),
352- test_server.TestingTCPServer,
353- DisconnectingHandler)
354-
355- def get_url(self):
356- """Return the url of the server"""
357- return "bzr://%s:%d/" % self.server.server_address
358
359=== added file 'breezy/tests/test_mergeable.py'
360--- breezy/tests/test_mergeable.py 1970-01-01 00:00:00 +0000
361+++ breezy/tests/test_mergeable.py 2019-05-29 03:29:58 +0000
362@@ -0,0 +1,91 @@
363+# Copyright (C) 2005-2013, 2016 Canonical Ltd
364+#
365+# This program is free software; you can redistribute it and/or modify
366+# it under the terms of the GNU General Public License as published by
367+# the Free Software Foundation; either version 2 of the License, or
368+# (at your option) any later version.
369+#
370+# This program is distributed in the hope that it will be useful,
371+# but WITHOUT ANY WARRANTY; without even the implied warranty of
372+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
373+# GNU General Public License for more details.
374+#
375+# You should have received a copy of the GNU General Public License
376+# along with this program; if not, write to the Free Software
377+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
378+
379+try:
380+ import socketserver
381+except ImportError:
382+ import SocketServer as socketserver
383+
384+from ..mergeable import read_mergeable_from_url
385+from ..directory_service import directories
386+from .. import (
387+ errors,
388+ tests,
389+ )
390+from . import (
391+ test_read_bundle,
392+ test_server,
393+ )
394+
395+
396+class TestReadMergeableFromUrl(tests.TestCaseWithTransport):
397+
398+ def test_read_mergeable_skips_local(self):
399+ """A local bundle named like the URL should not be read.
400+ """
401+ out, wt = test_read_bundle.create_bundle_file(self)
402+
403+ class FooService(object):
404+ """A directory service that always returns source"""
405+
406+ def look_up(self, name, url):
407+ return 'source'
408+ directories.register('foo:', FooService, 'Testing directory service')
409+ self.addCleanup(directories.remove, 'foo:')
410+ self.build_tree_contents([('./foo:bar', out.getvalue())])
411+ self.assertRaises(errors.NotABundle, read_mergeable_from_url,
412+ 'foo:bar')
413+
414+ def test_infinite_redirects_are_not_a_bundle(self):
415+ """If a URL causes TooManyRedirections then NotABundle is raised.
416+ """
417+ from .blackbox.test_push import RedirectingMemoryServer
418+ server = RedirectingMemoryServer()
419+ self.start_server(server)
420+ url = server.get_url() + 'infinite-loop'
421+ self.assertRaises(errors.NotABundle, read_mergeable_from_url, url)
422+
423+ def test_smart_server_connection_reset(self):
424+ """If a smart server connection fails during the attempt to read a
425+ bundle, then the ConnectionReset error should be propagated.
426+ """
427+ # Instantiate a server that will provoke a ConnectionReset
428+ sock_server = DisconnectingServer()
429+ self.start_server(sock_server)
430+ # We don't really care what the url is since the server will close the
431+ # connection without interpreting it
432+ url = sock_server.get_url()
433+ self.assertRaises(errors.ConnectionReset, read_mergeable_from_url, url)
434+
435+
436+class DisconnectingHandler(socketserver.BaseRequestHandler):
437+ """A request handler that immediately closes any connection made to it."""
438+
439+ def handle(self):
440+ self.request.close()
441+
442+
443+class DisconnectingServer(test_server.TestingTCPServerInAThread):
444+
445+ def __init__(self):
446+ super(DisconnectingServer, self).__init__(
447+ ('127.0.0.1', 0),
448+ test_server.TestingTCPServer,
449+ DisconnectingHandler)
450+
451+ def get_url(self):
452+ """Return the url of the server"""
453+ return "bzr://%s:%d/" % self.server.server_address
454
455=== modified file 'breezy/tests/test_read_bundle.py'
456--- breezy/tests/test_read_bundle.py 2018-11-12 01:41:38 +0000
457+++ breezy/tests/test_read_bundle.py 2019-05-29 03:29:58 +0000
458@@ -16,7 +16,7 @@
459
460 """Test read_bundle works properly across various transports."""
461
462-import breezy.bundle
463+import breezy.mergeable
464 from ..bundle.serializer import write_bundle
465 import breezy.bzr.bzrdir
466 from .. import errors
467@@ -71,7 +71,7 @@
468 self.create_test_bundle()
469
470 def read_mergeable_from_url(self, url):
471- return breezy.bundle.read_mergeable_from_url(
472+ return breezy.mergeable.read_mergeable_from_url(
473 url, possible_transports=self.possible_transports)
474
475 def get_url(self, relpath=''):

Subscribers

People subscribed via source and target branches