Merge lp:~jelmer/brz/move-mergeable into lp:brz
- move-mergeable
- Merge into trunk
Proposed by
Jelmer Vernooij
Status: | Merged |
---|---|
Approved by: | Jelmer Vernooij |
Approved revision: | no longer in the source branch. |
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Packman | Approve | ||
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.
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Merging failed
https:/
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Merging failed
https:/
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Merging failed
https:/
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=''): |
Thanks!