Merge lp:~jelmer/bzr/2a-supports-colo into lp:bzr/2.5
- 2a-supports-colo
- Merge into 2.5
Proposed by
Jelmer Vernooij
Status: | Merged |
---|---|
Approved by: | Vincent Ladeuil |
Approved revision: | no longer in the source branch. |
Merged at revision: | 6465 |
Proposed branch: | lp:~jelmer/bzr/2a-supports-colo |
Merge into: | lp:bzr/2.5 |
Diff against target: |
1135 lines (+321/-205) 14 files modified
bzrlib/builtins.py (+43/-19) bzrlib/bzrdir.py (+100/-142) bzrlib/remote.py (+24/-8) bzrlib/switch.py (+18/-10) bzrlib/tests/blackbox/test_branch.py (+3/-2) bzrlib/tests/blackbox/test_info.py (+90/-0) bzrlib/tests/per_branch/test_branch.py (+7/-1) bzrlib/tests/per_bzrdir/test_bzrdir.py (+2/-3) bzrlib/tests/per_controldir_colo/__init__.py (+22/-0) bzrlib/tests/per_controldir_colo/test_unsupported.py (+2/-1) bzrlib/tests/test_bzrdir.py (+2/-2) bzrlib/tests/test_remote.py (+0/-12) bzrlib/transport/__init__.py (+5/-5) doc/en/release-notes/bzr-2.5.txt (+3/-0) |
To merge this branch: | bzr merge lp:~jelmer/bzr/2a-supports-colo |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Vincent Ladeuil | Approve | ||
Review via email: mp+89738@code.launchpad.net |
Commit message
Merge colocated branch support back into the 2a format.
Description of the change
Merge colocated branch support back into the 2a format.
This also updates the upgrader for development-
To post a comment you must log in.
Revision history for this message
Gordon Tyler (doxxx) wrote : | # |
Revision history for this message
Jelmer Vernooij (jelmer) wrote : | # |
Am 23/01/12 18:14, schrieb Gordon Tyler:
> What are the upgrade implications for users of the current 2a? When they install the new version of bzr that has the new 2a-with-colo, what happens to their existing 2a branches/repos?
Nothing. :-) Older versions of bzr won't be able to see the colocated
branches (obviously), but they will be able to access the active branch.
Newer versions of bzr will be able to create colocated branches and
change the active branch.
Cheers,
Jelmer
Revision history for this message
Vincent Ladeuil (vila) : | # |
review:
Approve
Revision history for this message
Jelmer Vernooij (jelmer) wrote : | # |
sent to pqm by email
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bzrlib/builtins.py' |
2 | --- bzrlib/builtins.py 2012-01-25 17:41:05 +0000 |
3 | +++ bzrlib/builtins.py 2012-01-28 02:10:28 +0000 |
4 | @@ -83,10 +83,11 @@ |
5 | ) |
6 | |
7 | |
8 | -def _get_branch_location(control_dir): |
9 | +def _get_branch_location(control_dir, possible_transports=None): |
10 | """Return location of branch for this control dir.""" |
11 | try: |
12 | - this_branch = control_dir.open_branch() |
13 | + this_branch = control_dir.open_branch( |
14 | + possible_transports=possible_transports) |
15 | # This may be a heavy checkout, where we want the master branch |
16 | master_location = this_branch.get_bound_location() |
17 | if master_location is not None: |
18 | @@ -101,7 +102,34 @@ |
19 | return control_dir.root_transport.base |
20 | |
21 | |
22 | -def lookup_new_sibling_branch(control_dir, location): |
23 | +def _is_colocated(control_dir, possible_transports=None): |
24 | + """Check if the branch in control_dir is colocated. |
25 | + |
26 | + :param control_dir: Control directory |
27 | + :return: Boolean indicating whether |
28 | + """ |
29 | + # This path is meant to be relative to the existing branch |
30 | + this_url = _get_branch_location(control_dir, |
31 | + possible_transports=possible_transports) |
32 | + # Perhaps the target control dir supports colocated branches? |
33 | + try: |
34 | + root = controldir.ControlDir.open(this_url, |
35 | + possible_transports=possible_transports) |
36 | + except errors.NotBranchError: |
37 | + return (False, this_url) |
38 | + else: |
39 | + try: |
40 | + wt = control_dir.open_workingtree() |
41 | + except (errors.NoWorkingTree, errors.NotLocalUrl): |
42 | + return (False, this_url) |
43 | + else: |
44 | + return ( |
45 | + root._format.colocated_branches and |
46 | + control_dir.control_url == root.control_url, |
47 | + this_url) |
48 | + |
49 | + |
50 | +def lookup_new_sibling_branch(control_dir, location, possible_transports=None): |
51 | """Lookup the location for a new sibling branch. |
52 | |
53 | :param control_dir: Control directory relative to which to look up |
54 | @@ -111,16 +139,7 @@ |
55 | """ |
56 | location = directory_service.directories.dereference(location) |
57 | if '/' not in location and '\\' not in location: |
58 | - # This path is meant to be relative to the existing branch |
59 | - this_url = _get_branch_location(control_dir) |
60 | - # Perhaps the target control dir supports colocated branches? |
61 | - try: |
62 | - root = controldir.ControlDir.open(this_url, |
63 | - possible_transports=[control_dir.user_transport]) |
64 | - except errors.NotBranchError: |
65 | - colocated = False |
66 | - else: |
67 | - colocated = root._format.colocated_branches |
68 | + (colocated, this_url) = _is_colocated(control_dir, possible_transports) |
69 | |
70 | if colocated: |
71 | return urlutils.join_segment_parameters(this_url, |
72 | @@ -130,7 +149,7 @@ |
73 | return location |
74 | |
75 | |
76 | -def lookup_sibling_branch(control_dir, location): |
77 | +def lookup_sibling_branch(control_dir, location, possible_transports=None): |
78 | """Lookup sibling branch. |
79 | |
80 | :param control_dir: Control directory relative to which to lookup the |
81 | @@ -140,7 +159,8 @@ |
82 | """ |
83 | try: |
84 | # Perhaps it's a colocated branch? |
85 | - return control_dir.open_branch(location) |
86 | + return control_dir.open_branch(location, |
87 | + possible_transports=possible_transports) |
88 | except (errors.NotBranchError, errors.NoColocatedBranchSupport): |
89 | try: |
90 | return Branch.open(location) |
91 | @@ -6201,14 +6221,17 @@ |
92 | from bzrlib import switch |
93 | tree_location = directory |
94 | revision = _get_one_revision('switch', revision) |
95 | - control_dir = controldir.ControlDir.open_containing(tree_location)[0] |
96 | + possible_transports = [] |
97 | + control_dir = controldir.ControlDir.open_containing(tree_location, |
98 | + possible_transports=possible_transports)[0] |
99 | if to_location is None: |
100 | if revision is None: |
101 | raise errors.BzrCommandError(gettext('You must supply either a' |
102 | ' revision or a location')) |
103 | to_location = tree_location |
104 | try: |
105 | - branch = control_dir.open_branch() |
106 | + branch = control_dir.open_branch( |
107 | + possible_transports=possible_transports) |
108 | had_explicit_nick = branch.get_config().has_explicit_nickname() |
109 | except errors.NotBranchError: |
110 | branch = None |
111 | @@ -6217,9 +6240,10 @@ |
112 | if branch is None: |
113 | raise errors.BzrCommandError( |
114 | gettext('cannot create branch without source branch')) |
115 | - to_location = lookup_new_sibling_branch(control_dir, to_location) |
116 | + to_location = lookup_new_sibling_branch(control_dir, to_location, |
117 | + possible_transports=possible_transports) |
118 | to_branch = branch.bzrdir.sprout(to_location, |
119 | - possible_transports=[branch.bzrdir.root_transport], |
120 | + possible_transports=possible_transports, |
121 | source_branch=branch).open_branch() |
122 | else: |
123 | to_branch = lookup_sibling_branch(control_dir, to_location) |
124 | |
125 | === modified file 'bzrlib/bzrdir.py' |
126 | --- bzrlib/bzrdir.py 2012-01-27 20:46:27 +0000 |
127 | +++ bzrlib/bzrdir.py 2012-01-28 02:10:28 +0000 |
128 | @@ -810,10 +810,51 @@ |
129 | present within a BzrDir. |
130 | """ |
131 | |
132 | + def _get_branch_path(self, name): |
133 | + """Obtain the branch path to use. |
134 | + |
135 | + This uses the API specified branch name first, and then falls back to |
136 | + the branch name specified in the URL. If neither of those is specified, |
137 | + it uses the default branch. |
138 | + |
139 | + :param name: Optional branch name to use |
140 | + :return: Relative path to branch |
141 | + """ |
142 | + if name == "": |
143 | + return 'branch' |
144 | + return urlutils.join('branches', name.encode("utf-8")) |
145 | + |
146 | + def _read_branch_list(self): |
147 | + """Read the branch list. |
148 | + |
149 | + :return: List of utf-8 encoded branch names. |
150 | + """ |
151 | + try: |
152 | + f = self.control_transport.get('branch-list') |
153 | + except errors.NoSuchFile: |
154 | + return [] |
155 | + |
156 | + ret = [] |
157 | + try: |
158 | + for name in f: |
159 | + ret.append(name.rstrip("\n")) |
160 | + finally: |
161 | + f.close() |
162 | + return ret |
163 | + |
164 | + def _write_branch_list(self, branches): |
165 | + """Write out the branch list. |
166 | + |
167 | + :param branches: List of utf-8 branch names to write |
168 | + """ |
169 | + self.transport.put_bytes('branch-list', |
170 | + "".join([name+"\n" for name in branches])) |
171 | + |
172 | def __init__(self, _transport, _format): |
173 | super(BzrDirMeta1, self).__init__(_transport, _format) |
174 | - self.control_files = lockable_files.LockableFiles(self.control_transport, |
175 | - self._format._lock_file_name, self._format._lock_class) |
176 | + self.control_files = lockable_files.LockableFiles( |
177 | + self.control_transport, self._format._lock_file_name, |
178 | + self._format._lock_class) |
179 | |
180 | def can_convert_format(self): |
181 | """See BzrDir.can_convert_format().""" |
182 | @@ -832,9 +873,19 @@ |
183 | """See BzrDir.create_branch.""" |
184 | if name is None: |
185 | name = self._get_selected_branch() |
186 | + path = self._get_branch_path(name) |
187 | if name != "": |
188 | - raise errors.NoColocatedBranchSupport(self) |
189 | - self.transport.delete_tree('branch') |
190 | + self.control_files.lock_write() |
191 | + try: |
192 | + branches = self._read_branch_list() |
193 | + try: |
194 | + branches.remove(name.encode("utf-8")) |
195 | + except ValueError: |
196 | + raise errors.NotBranchError(name) |
197 | + self._write_branch_list(branches) |
198 | + finally: |
199 | + self.control_files.unlock() |
200 | + self.transport.delete_tree(path) |
201 | |
202 | def create_repository(self, shared=False): |
203 | """See BzrDir.create_repository.""" |
204 | @@ -896,21 +947,41 @@ |
205 | """See BzrDir.get_branch_transport().""" |
206 | if name is None: |
207 | name = self._get_selected_branch() |
208 | - if name != "": |
209 | - raise errors.NoColocatedBranchSupport(self) |
210 | + path = self._get_branch_path(name) |
211 | # XXX: this shouldn't implicitly create the directory if it's just |
212 | # promising to get a transport -- mbp 20090727 |
213 | if branch_format is None: |
214 | - return self.transport.clone('branch') |
215 | + return self.transport.clone(path) |
216 | try: |
217 | branch_format.get_format_string() |
218 | except NotImplementedError: |
219 | raise errors.IncompatibleFormat(branch_format, self._format) |
220 | + if name != "": |
221 | + branches = self._read_branch_list() |
222 | + utf8_name = name.encode("utf-8") |
223 | + if not utf8_name in branches: |
224 | + self.control_files.lock_write() |
225 | + try: |
226 | + branches = self._read_branch_list() |
227 | + dirname = urlutils.dirname(utf8_name) |
228 | + if dirname != "" and dirname in branches: |
229 | + raise errors.ParentBranchExists(name) |
230 | + child_branches = [ |
231 | + b.startswith(utf8_name+"/") for b in branches] |
232 | + if any(child_branches): |
233 | + raise errors.AlreadyBranchError(name) |
234 | + branches.append(utf8_name) |
235 | + self._write_branch_list(branches) |
236 | + finally: |
237 | + self.control_files.unlock() |
238 | + branch_transport = self.transport.clone(path) |
239 | + mode = self._get_mkdir_mode() |
240 | + branch_transport.create_prefix(mode=mode) |
241 | try: |
242 | - self.transport.mkdir('branch', mode=self._get_mkdir_mode()) |
243 | + self.transport.mkdir(path, mode=mode) |
244 | except errors.FileExists: |
245 | pass |
246 | - return self.transport.clone('branch') |
247 | + return self.transport.clone(path) |
248 | |
249 | def get_repository_transport(self, repository_format): |
250 | """See BzrDir.get_repository_transport().""" |
251 | @@ -940,6 +1011,19 @@ |
252 | pass |
253 | return self.transport.clone('checkout') |
254 | |
255 | + def get_branches(self): |
256 | + """See ControlDir.get_branches.""" |
257 | + ret = {} |
258 | + try: |
259 | + ret[""] = self.open_branch(name="") |
260 | + except (errors.NotBranchError, errors.NoRepositoryPresent): |
261 | + pass |
262 | + |
263 | + for name in self._read_branch_list(): |
264 | + ret[name] = self.open_branch(name=name.decode('utf-8')) |
265 | + |
266 | + return ret |
267 | + |
268 | def has_workingtree(self): |
269 | """Tell if this bzrdir contains a working tree. |
270 | |
271 | @@ -1013,124 +1097,6 @@ |
272 | return config.TransportConfig(self.transport, 'control.conf') |
273 | |
274 | |
275 | -class BzrDirMeta1Colo(BzrDirMeta1): |
276 | - """BzrDirMeta1 with support for colocated branches. |
277 | - |
278 | - This format is experimental, and will eventually be merged back into |
279 | - BzrDirMeta1. |
280 | - """ |
281 | - |
282 | - def _get_branch_path(self, name): |
283 | - """Obtain the branch path to use. |
284 | - |
285 | - This uses the API specified branch name first, and then falls back to |
286 | - the branch name specified in the URL. If neither of those is specified, |
287 | - it uses the default branch. |
288 | - |
289 | - :param name: Optional branch name to use |
290 | - :return: Relative path to branch |
291 | - """ |
292 | - if name == "": |
293 | - return 'branch' |
294 | - return urlutils.join('branches', name.encode("utf-8")) |
295 | - |
296 | - def _read_branch_list(self): |
297 | - """Read the branch list. |
298 | - |
299 | - :return: List of utf-8 encoded branch names. |
300 | - """ |
301 | - try: |
302 | - f = self.control_transport.get('branch-list') |
303 | - except errors.NoSuchFile: |
304 | - return [] |
305 | - |
306 | - ret = [] |
307 | - try: |
308 | - for name in f: |
309 | - ret.append(name.rstrip("\n")) |
310 | - finally: |
311 | - f.close() |
312 | - return ret |
313 | - |
314 | - def _write_branch_list(self, branches): |
315 | - """Write out the branch list. |
316 | - |
317 | - :param branches: List of utf-8 branch names to write |
318 | - """ |
319 | - self.transport.put_bytes('branch-list', |
320 | - "".join([name+"\n" for name in branches])) |
321 | - |
322 | - def destroy_branch(self, name=None): |
323 | - """See BzrDir.create_branch.""" |
324 | - if name is None: |
325 | - name = self._get_selected_branch() |
326 | - path = self._get_branch_path(name) |
327 | - if name != "": |
328 | - self.control_files.lock_write() |
329 | - try: |
330 | - branches = self._read_branch_list() |
331 | - try: |
332 | - branches.remove(name.encode("utf-8")) |
333 | - except ValueError: |
334 | - raise errors.NotBranchError(name) |
335 | - self._write_branch_list(branches) |
336 | - finally: |
337 | - self.control_files.unlock() |
338 | - self.transport.delete_tree(path) |
339 | - |
340 | - def get_branches(self): |
341 | - """See ControlDir.get_branches.""" |
342 | - ret = {} |
343 | - try: |
344 | - ret[""] = self.open_branch(name="") |
345 | - except (errors.NotBranchError, errors.NoRepositoryPresent): |
346 | - pass |
347 | - |
348 | - for name in self._read_branch_list(): |
349 | - ret[name] = self.open_branch(name=name.decode('utf-8')) |
350 | - |
351 | - return ret |
352 | - |
353 | - def get_branch_transport(self, branch_format, name=None): |
354 | - """See BzrDir.get_branch_transport().""" |
355 | - if name is None: |
356 | - name = self._get_selected_branch() |
357 | - path = self._get_branch_path(name) |
358 | - # XXX: this shouldn't implicitly create the directory if it's just |
359 | - # promising to get a transport -- mbp 20090727 |
360 | - if branch_format is None: |
361 | - return self.transport.clone(path) |
362 | - try: |
363 | - branch_format.get_format_string() |
364 | - except NotImplementedError: |
365 | - raise errors.IncompatibleFormat(branch_format, self._format) |
366 | - if name != "": |
367 | - branches = self._read_branch_list() |
368 | - utf8_name = name.encode("utf-8") |
369 | - if not utf8_name in branches: |
370 | - self.control_files.lock_write() |
371 | - try: |
372 | - branches = self._read_branch_list() |
373 | - dirname = urlutils.dirname(utf8_name) |
374 | - if dirname != "" and dirname in branches: |
375 | - raise errors.ParentBranchExists(name) |
376 | - child_branches = [ |
377 | - b.startswith(utf8_name+"/") for b in branches] |
378 | - if any(child_branches): |
379 | - raise errors.AlreadyBranchError(name) |
380 | - branches.append(utf8_name) |
381 | - self._write_branch_list(branches) |
382 | - finally: |
383 | - self.control_files.unlock() |
384 | - branch_transport = self.transport.clone(path) |
385 | - branch_transport.create_prefix() |
386 | - try: |
387 | - self.transport.mkdir('.', mode=self._get_mkdir_mode()) |
388 | - except errors.FileExists: |
389 | - pass |
390 | - return branch_transport |
391 | - |
392 | - |
393 | class BzrFormat(object): |
394 | """Base class for all formats of things living in metadirs. |
395 | |
396 | @@ -1579,7 +1545,7 @@ |
397 | |
398 | fixed_components = False |
399 | |
400 | - colocated_branches = False |
401 | + colocated_branches = True |
402 | |
403 | def __init__(self): |
404 | BzrDirFormat.__init__(self) |
405 | @@ -1712,7 +1678,7 @@ |
406 | return ConvertMetaToColo(format) |
407 | if (type(self) is BzrDirMetaFormat1Colo and |
408 | type(format) is BzrDirMetaFormat1): |
409 | - return ConvertMetaRemoveColo(format) |
410 | + return ConvertMetaToColo(format) |
411 | if not isinstance(self, format.__class__): |
412 | # converting away from metadir is not implemented |
413 | raise NotImplementedError(self.get_converter) |
414 | @@ -1814,7 +1780,7 @@ |
415 | # problems. |
416 | format = BzrDirMetaFormat1Colo() |
417 | self._supply_sub_formats_to(format) |
418 | - return BzrDirMeta1Colo(transport, format) |
419 | + return BzrDirMeta1(transport, format) |
420 | |
421 | |
422 | BzrProber.formats.register(BzrDirMetaFormat1Colo.get_format_string(), |
423 | @@ -1916,12 +1882,12 @@ |
424 | return BzrDir.open_from_transport(to_convert.root_transport) |
425 | |
426 | |
427 | -class ConvertMetaRemoveColo(controldir.Converter): |
428 | - """Remove colocated branch support from a bzrdir.""" |
429 | +class ConvertMetaToColo(controldir.Converter): |
430 | + """Convert a 'development-colo' bzrdir to a '2a' bzrdir.""" |
431 | |
432 | def __init__(self, target_format): |
433 | - """Create a converter.that downgrades a colocated branch metadir |
434 | - to a regular metadir. |
435 | + """Create a converter that converts a 'development-colo' metadir |
436 | + to a '2a' metadir. |
437 | |
438 | :param target_format: The final metadir format that is desired. |
439 | """ |
440 | @@ -1929,14 +1895,6 @@ |
441 | |
442 | def convert(self, to_convert, pb): |
443 | """See Converter.convert().""" |
444 | - to_convert.control_files.lock_write() |
445 | - try: |
446 | - branches = to_convert.list_branches() |
447 | - if len(branches) > 1: |
448 | - raise errors.BzrError("remove all but a single " |
449 | - "colocated branch when downgrading") |
450 | - finally: |
451 | - to_convert.control_files.unlock() |
452 | to_convert.transport.put_bytes('branch-format', |
453 | self.target_format.as_string()) |
454 | return BzrDir.open_from_transport(to_convert.root_transport) |
455 | |
456 | === modified file 'bzrlib/remote.py' |
457 | --- bzrlib/remote.py 2012-01-27 13:33:53 +0000 |
458 | +++ bzrlib/remote.py 2012-01-28 02:10:28 +0000 |
459 | @@ -59,7 +59,7 @@ |
460 | from bzrlib.repository import RepositoryWriteLockResult, _LazyListJoin |
461 | from bzrlib.serializer import format_registry as serializer_format_registry |
462 | from bzrlib.trace import mutter, note, warning, log_exception_quietly |
463 | -from bzrlib.versionedfile import ChunkedContentFactory, FulltextContentFactory |
464 | +from bzrlib.versionedfile import FulltextContentFactory |
465 | |
466 | |
467 | _DEFAULT_SEARCH_DEPTH = 100 |
468 | @@ -113,6 +113,8 @@ |
469 | |
470 | supports_workingtrees = False |
471 | |
472 | + colocated_branches = False |
473 | + |
474 | def __init__(self): |
475 | _mod_bzrdir.BzrDirMetaFormat1.__init__(self) |
476 | # XXX: It's a bit ugly that the network name is here, because we'd |
477 | @@ -627,6 +629,8 @@ |
478 | append_revisions_only=None): |
479 | if name is None: |
480 | name = self._get_selected_branch() |
481 | + if name != "": |
482 | + raise errors.NoColocatedBranchSupport(self) |
483 | # as per meta1 formats - just delegate to the format object which may |
484 | # be parameterised. |
485 | real_branch = self._format.get_branch_format().initialize(self, |
486 | @@ -651,9 +655,13 @@ |
487 | |
488 | def destroy_branch(self, name=None): |
489 | """See BzrDir.destroy_branch""" |
490 | + if name is None: |
491 | + name = self._get_selected_branch() |
492 | + if name != "": |
493 | + raise errors.NoColocatedBranchSupport(self) |
494 | path = self._path_for_remote_call(self._client) |
495 | try: |
496 | - if name is not None: |
497 | + if name != "": |
498 | args = (name, ) |
499 | else: |
500 | args = () |
501 | @@ -699,13 +707,18 @@ |
502 | |
503 | def set_branch_reference(self, target_branch, name=None): |
504 | """See BzrDir.set_branch_reference().""" |
505 | + if name is None: |
506 | + name = self._get_selected_branch() |
507 | + if name != "": |
508 | + raise errors.NoColocatedBranchSupport(self) |
509 | self._ensure_real() |
510 | return self._real_bzrdir.set_branch_reference(target_branch, name=name) |
511 | |
512 | def get_branch_reference(self, name=None): |
513 | """See BzrDir.get_branch_reference().""" |
514 | - if name is not None: |
515 | - # XXX JRV20100304: Support opening colocated branches |
516 | + if name is None: |
517 | + name = self._get_selected_branch() |
518 | + if name != "": |
519 | raise errors.NoColocatedBranchSupport(self) |
520 | response = self._get_branch_reference() |
521 | if response[0] == 'ref': |
522 | @@ -765,6 +778,10 @@ |
523 | |
524 | def open_branch(self, name=None, unsupported=False, |
525 | ignore_fallbacks=False, possible_transports=None): |
526 | + if name is None: |
527 | + name = self._get_selected_branch() |
528 | + if name != "": |
529 | + raise errors.NoColocatedBranchSupport(self) |
530 | if unsupported: |
531 | raise NotImplementedError('unsupported flag support not implemented yet.') |
532 | if self._next_open_branch_result is not None: |
533 | @@ -773,8 +790,6 @@ |
534 | self._next_open_branch_result = None |
535 | return result |
536 | response = self._get_branch_reference() |
537 | - if name is None: |
538 | - name = self._get_selected_branch() |
539 | return self._open_branch(name, response[0], response[1], |
540 | possible_transports=possible_transports, |
541 | ignore_fallbacks=ignore_fallbacks) |
542 | @@ -3122,10 +3137,10 @@ |
543 | if isinstance(a_bzrdir, RemoteBzrDir): |
544 | a_bzrdir._ensure_real() |
545 | result = self._custom_format.initialize(a_bzrdir._real_bzrdir, |
546 | - name, append_revisions_only=append_revisions_only) |
547 | + name=name, append_revisions_only=append_revisions_only) |
548 | else: |
549 | # We assume the bzrdir is parameterised; it may not be. |
550 | - result = self._custom_format.initialize(a_bzrdir, name, |
551 | + result = self._custom_format.initialize(a_bzrdir, name=name, |
552 | append_revisions_only=append_revisions_only) |
553 | if (isinstance(a_bzrdir, RemoteBzrDir) and |
554 | not isinstance(result, RemoteBranch)): |
555 | @@ -3322,6 +3337,7 @@ |
556 | # will try to assign to self.tags, which is a property in this subclass. |
557 | # And the parent's __init__ doesn't do much anyway. |
558 | self.bzrdir = remote_bzrdir |
559 | + self.name = name |
560 | if _client is not None: |
561 | self._client = _client |
562 | else: |
563 | |
564 | === modified file 'bzrlib/switch.py' |
565 | --- bzrlib/switch.py 2012-01-18 19:14:21 +0000 |
566 | +++ bzrlib/switch.py 2012-01-28 02:10:28 +0000 |
567 | @@ -45,7 +45,11 @@ |
568 | source_repository = control_dir.open_branch().repository |
569 | except errors.NotBranchError: |
570 | source_repository = to_branch.repository |
571 | - _set_branch_location(control_dir, to_branch, force) |
572 | + to_branch.lock_read() |
573 | + try: |
574 | + _set_branch_location(control_dir, to_branch, force) |
575 | + finally: |
576 | + to_branch.unlock() |
577 | tree = control_dir.open_workingtree() |
578 | _update(tree, source_repository, quiet, revision_id) |
579 | _run_post_switch_hooks(control_dir, to_branch, force, revision_id) |
580 | @@ -109,15 +113,19 @@ |
581 | else: |
582 | # If this is a standalone tree and the new branch |
583 | # is derived from this one, create a lightweight checkout. |
584 | - graph = b.repository.get_graph(to_branch.repository) |
585 | - if (b.bzrdir._format.colocated_branches and |
586 | - (force or graph.is_ancestor(b.last_revision(), |
587 | - to_branch.last_revision()))): |
588 | - b.bzrdir.destroy_branch() |
589 | - b.bzrdir.set_branch_reference(to_branch, name="") |
590 | - else: |
591 | - raise errors.BzrCommandError(gettext('Cannot switch a branch, ' |
592 | - 'only a checkout.')) |
593 | + b.lock_read() |
594 | + try: |
595 | + graph = b.repository.get_graph(to_branch.repository) |
596 | + if (b.bzrdir._format.colocated_branches and |
597 | + (force or graph.is_ancestor(b.last_revision(), |
598 | + to_branch.last_revision()))): |
599 | + b.bzrdir.destroy_branch() |
600 | + b.bzrdir.set_branch_reference(to_branch, name="") |
601 | + else: |
602 | + raise errors.BzrCommandError(gettext('Cannot switch a branch, ' |
603 | + 'only a checkout.')) |
604 | + finally: |
605 | + b.unlock() |
606 | |
607 | |
608 | def _any_local_commits(this_branch, possible_transports): |
609 | |
610 | === modified file 'bzrlib/tests/blackbox/test_branch.py' |
611 | --- bzrlib/tests/blackbox/test_branch.py 2012-01-25 17:41:05 +0000 |
612 | +++ bzrlib/tests/blackbox/test_branch.py 2012-01-28 02:10:28 +0000 |
613 | @@ -155,14 +155,15 @@ |
614 | # => new branch will be created, but switch fails and the current |
615 | # branch is unmodified |
616 | self.example_branch('a') |
617 | - self.make_branch_and_tree('current') |
618 | + tree = self.make_branch_and_tree('current') |
619 | + c1 = tree.commit('some diverged change') |
620 | self.run_bzr_error(['Cannot switch a branch, only a checkout'], |
621 | 'branch --switch ../a ../b', working_dir='current') |
622 | a = branch.Branch.open('a') |
623 | b = branch.Branch.open('b') |
624 | self.assertEqual(a.last_revision(), b.last_revision()) |
625 | work = branch.Branch.open('current') |
626 | - self.assertEqual(work.last_revision(), _mod_revision.NULL_REVISION) |
627 | + self.assertEqual(work.last_revision(), c1) |
628 | |
629 | def test_branch_into_empty_dir(self): |
630 | t = self.example_branch('source') |
631 | |
632 | === modified file 'bzrlib/tests/blackbox/test_info.py' |
633 | --- bzrlib/tests/blackbox/test_info.py 2012-01-19 16:51:39 +0000 |
634 | +++ bzrlib/tests/blackbox/test_info.py 2012-01-28 02:10:28 +0000 |
635 | @@ -99,6 +99,9 @@ |
636 | branch: Branch format 5 |
637 | repository: Knit repository format 1 |
638 | |
639 | +Control directory: |
640 | + 1 branches |
641 | + |
642 | In the working tree: |
643 | 0 unchanged |
644 | 0 modified |
645 | @@ -130,6 +133,9 @@ |
646 | branch: Branch format 5 |
647 | repository: Knit repository format 1 |
648 | |
649 | +Control directory: |
650 | + 1 branches |
651 | + |
652 | In the working tree: |
653 | 0 unchanged |
654 | 0 modified |
655 | @@ -184,6 +190,9 @@ |
656 | branch: Branch format 5 |
657 | repository: Knit repository format 1 |
658 | |
659 | +Control directory: |
660 | + 1 branches |
661 | + |
662 | In the working tree: |
663 | 1 unchanged |
664 | 0 modified |
665 | @@ -230,6 +239,9 @@ |
666 | branch: %s |
667 | repository: %s |
668 | |
669 | +Control directory: |
670 | + 1 branches |
671 | + |
672 | In the working tree: |
673 | 1 unchanged |
674 | 0 modified |
675 | @@ -273,6 +285,9 @@ |
676 | branch: Branch format 5 |
677 | repository: %s |
678 | |
679 | +Control directory: |
680 | + 1 branches |
681 | + |
682 | In the working tree: |
683 | 1 unchanged |
684 | 0 modified |
685 | @@ -316,6 +331,9 @@ |
686 | branch: Branch format 5 |
687 | repository: Knit repository format 1 |
688 | |
689 | +Control directory: |
690 | + 1 branches |
691 | + |
692 | In the working tree: |
693 | 1 unchanged |
694 | 0 modified |
695 | @@ -361,6 +379,9 @@ |
696 | branch: Branch format 5 |
697 | repository: Knit repository format 1 |
698 | |
699 | +Control directory: |
700 | + 1 branches |
701 | + |
702 | In the working tree: |
703 | 1 unchanged |
704 | 0 modified |
705 | @@ -400,6 +421,9 @@ |
706 | branch: Branch format 5 |
707 | repository: %s |
708 | |
709 | +Control directory: |
710 | + 1 branches |
711 | + |
712 | Branch is out of date: missing 1 revision. |
713 | |
714 | In the working tree: |
715 | @@ -439,6 +463,9 @@ |
716 | branch: Branch format 5 |
717 | repository: %s |
718 | |
719 | +Control directory: |
720 | + 1 branches |
721 | + |
722 | Branch is out of date: missing 1 revision. |
723 | |
724 | In the working tree: |
725 | @@ -478,6 +505,9 @@ |
726 | branch: Branch format 5 |
727 | repository: Knit repository format 1 |
728 | |
729 | +Control directory: |
730 | + 1 branches |
731 | + |
732 | Working tree is out of date: missing 1 revision. |
733 | |
734 | In the working tree: |
735 | @@ -517,6 +547,9 @@ |
736 | branch: %s |
737 | repository: %s |
738 | |
739 | +Control directory: |
740 | + 1 branches |
741 | + |
742 | Branch history: |
743 | 0 revisions |
744 | |
745 | @@ -545,6 +578,9 @@ |
746 | control: Meta directory format 1 |
747 | repository: %s |
748 | |
749 | +Control directory: |
750 | + 0 branches |
751 | + |
752 | Repository: |
753 | 0 revisions |
754 | """ % ('repo', format.repository_format.get_format_description(), |
755 | @@ -567,6 +603,9 @@ |
756 | branch: %s |
757 | repository: %s |
758 | |
759 | +Control directory: |
760 | + 1 branches |
761 | + |
762 | Branch history: |
763 | 0 revisions |
764 | |
765 | @@ -611,6 +650,9 @@ |
766 | branch: %s |
767 | repository: %s |
768 | |
769 | +Control directory: |
770 | + 1 branches |
771 | + |
772 | In the working tree: |
773 | 1 unchanged |
774 | 0 modified |
775 | @@ -649,6 +691,9 @@ |
776 | branch: %s |
777 | repository: %s |
778 | |
779 | +Control directory: |
780 | + 1 branches |
781 | + |
782 | Branch is out of date: missing 1 revision. |
783 | |
784 | In the working tree: |
785 | @@ -688,6 +733,9 @@ |
786 | branch: %s |
787 | repository: %s |
788 | |
789 | +Control directory: |
790 | + 1 branches |
791 | + |
792 | In the working tree: |
793 | 1 unchanged |
794 | 0 modified |
795 | @@ -730,6 +778,9 @@ |
796 | branch: %s |
797 | repository: %s |
798 | |
799 | +Control directory: |
800 | + 1 branches |
801 | + |
802 | Working tree is out of date: missing 1 revision. |
803 | |
804 | In the working tree: |
805 | @@ -769,6 +820,9 @@ |
806 | branch: %s |
807 | repository: %s |
808 | |
809 | +Control directory: |
810 | + 1 branches |
811 | + |
812 | Branch history: |
813 | 2 revisions |
814 | 0 days old |
815 | @@ -794,6 +848,9 @@ |
816 | control: Meta directory format 1 |
817 | repository: %s |
818 | |
819 | +Control directory: |
820 | + 0 branches |
821 | + |
822 | Repository: |
823 | 2 revisions |
824 | """ % (format.repository_format.get_format_description(), |
825 | @@ -817,6 +874,9 @@ |
826 | control: Meta directory format 1 |
827 | repository: %s |
828 | |
829 | +Control directory: |
830 | + 0 branches |
831 | + |
832 | Create working tree for new branches inside the repository. |
833 | |
834 | Repository: |
835 | @@ -845,6 +905,9 @@ |
836 | branch: %s |
837 | repository: %s |
838 | |
839 | +Control directory: |
840 | + 1 branches |
841 | + |
842 | In the working tree: |
843 | 0 unchanged |
844 | 0 modified |
845 | @@ -885,6 +948,9 @@ |
846 | branch: %s |
847 | repository: %s |
848 | |
849 | +Control directory: |
850 | + 1 branches |
851 | + |
852 | In the working tree: |
853 | 1 unchanged |
854 | 0 modified |
855 | @@ -926,6 +992,9 @@ |
856 | branch: %s |
857 | repository: %s |
858 | |
859 | +Control directory: |
860 | + 1 branches |
861 | + |
862 | In the working tree: |
863 | 0 unchanged |
864 | 0 modified |
865 | @@ -965,6 +1034,9 @@ |
866 | branch: %s |
867 | repository: %s |
868 | |
869 | +Control directory: |
870 | + 1 branches |
871 | + |
872 | In the working tree: |
873 | 1 unchanged |
874 | 0 modified |
875 | @@ -1000,6 +1072,9 @@ |
876 | control: Meta directory format 1 |
877 | repository: %s |
878 | |
879 | +Control directory: |
880 | + 0 branches |
881 | + |
882 | Create working tree for new branches inside the repository. |
883 | |
884 | Repository: |
885 | @@ -1026,6 +1101,9 @@ |
886 | control: Meta directory format 1 |
887 | repository: %s |
888 | |
889 | +Control directory: |
890 | + 0 branches |
891 | + |
892 | Create working tree for new branches inside the repository. |
893 | |
894 | Repository: |
895 | @@ -1051,6 +1129,9 @@ |
896 | branch: %s |
897 | repository: %s |
898 | |
899 | +Control directory: |
900 | + 1 branches |
901 | + |
902 | In the working tree: |
903 | 0 unchanged |
904 | 0 modified |
905 | @@ -1088,6 +1169,9 @@ |
906 | control: Meta directory format 1 |
907 | repository: %s |
908 | |
909 | +Control directory: |
910 | + 0 branches |
911 | + |
912 | Create working tree for new branches inside the repository. |
913 | |
914 | Repository: |
915 | @@ -1227,6 +1311,9 @@ |
916 | branch: %s |
917 | repository: %s |
918 | %s |
919 | +Control directory: |
920 | + 1 branches |
921 | + |
922 | In the working tree: |
923 | 0 unchanged |
924 | 0 modified |
925 | @@ -1403,6 +1490,9 @@ |
926 | branch: Branch format 7 |
927 | repository: Repository format 2a - rich roots, group compression and chk inventories |
928 | |
929 | +Control directory: |
930 | + 1 branches |
931 | + |
932 | In the working tree: |
933 | 0 unchanged |
934 | 0 modified |
935 | |
936 | === modified file 'bzrlib/tests/per_branch/test_branch.py' |
937 | --- bzrlib/tests/per_branch/test_branch.py 2012-01-04 17:12:42 +0000 |
938 | +++ bzrlib/tests/per_branch/test_branch.py 2012-01-28 02:10:28 +0000 |
939 | @@ -318,11 +318,17 @@ |
940 | repo = self.make_repository('.', shared=True) |
941 | except errors.IncompatibleFormat: |
942 | return |
943 | + if repo.bzrdir._format.colocated_branches: |
944 | + raise tests.TestNotApplicable( |
945 | + "control dir does not support colocated branches") |
946 | self.assertEquals(0, len(repo.bzrdir.list_branches())) |
947 | + if not self.bzrdir_format.colocated_branches: |
948 | + raise tests.TestNotApplicable("control dir format does not support " |
949 | + "colocated branches") |
950 | try: |
951 | child_branch1 = self.branch_format.initialize(repo.bzrdir, |
952 | name='branch1') |
953 | - except (errors.UninitializableFormat, errors.NoColocatedBranchSupport): |
954 | + except errors.UninitializableFormat: |
955 | # branch references are not default init'able and |
956 | # not all bzrdirs support colocated branches. |
957 | return |
958 | |
959 | === modified file 'bzrlib/tests/per_bzrdir/test_bzrdir.py' |
960 | --- bzrlib/tests/per_bzrdir/test_bzrdir.py 2012-01-27 14:36:00 +0000 |
961 | +++ bzrlib/tests/per_bzrdir/test_bzrdir.py 2012-01-28 02:10:28 +0000 |
962 | @@ -685,10 +685,9 @@ |
963 | |
964 | def test_get_branches(self): |
965 | repo = self.make_repository('branch-1') |
966 | - try: |
967 | - target_branch = repo.bzrdir.create_branch(name='foo') |
968 | - except errors.NoColocatedBranchSupport: |
969 | + if not repo.bzrdir._format.colocated_branches: |
970 | raise TestNotApplicable('Format does not support colocation') |
971 | + target_branch = repo.bzrdir.create_branch(name='foo') |
972 | repo.bzrdir.set_branch_reference(target_branch) |
973 | self.assertEqual(set(["", 'foo']), |
974 | set(repo.bzrdir.get_branches().keys())) |
975 | |
976 | === modified file 'bzrlib/tests/per_controldir_colo/__init__.py' |
977 | --- bzrlib/tests/per_controldir_colo/__init__.py 2010-08-21 16:06:24 +0000 |
978 | +++ bzrlib/tests/per_controldir_colo/__init__.py 2012-01-28 02:10:28 +0000 |
979 | @@ -27,17 +27,23 @@ |
980 | from bzrlib.tests import ( |
981 | default_transport, |
982 | multiply_tests, |
983 | + test_server, |
984 | ) |
985 | from bzrlib.tests.per_controldir import ( |
986 | TestCaseWithControlDir, |
987 | make_scenarios, |
988 | ) |
989 | +from bzrlib.transport import memory |
990 | |
991 | |
992 | def load_tests(standard_tests, module, loader): |
993 | colo_supported_formats = [] |
994 | colo_unsupported_formats = [] |
995 | + # This will always add scenarios using the smart server. |
996 | + from bzrlib.remote import RemoteBzrDirFormat |
997 | for format in ControlDirFormat.known_formats(): |
998 | + if isinstance(format, RemoteBzrDirFormat): |
999 | + continue |
1000 | if format.colocated_branches: |
1001 | colo_supported_formats.append(format) |
1002 | else: |
1003 | @@ -46,6 +52,22 @@ |
1004 | colo_supported_formats) |
1005 | unsupported_scenarios = make_scenarios(default_transport, None, None, |
1006 | colo_unsupported_formats) |
1007 | + # test the remote server behaviour when backed with a MemoryTransport |
1008 | + # Once for the current version |
1009 | + unsupported_scenarios.extend(make_scenarios( |
1010 | + memory.MemoryServer, |
1011 | + test_server.SmartTCPServer_for_testing, |
1012 | + test_server.ReadonlySmartTCPServer_for_testing, |
1013 | + [(RemoteBzrDirFormat())], |
1014 | + name_suffix='-default')) |
1015 | + # And once with < 1.6 - the 'v2' protocol. |
1016 | + unsupported_scenarios.extend(make_scenarios( |
1017 | + memory.MemoryServer, |
1018 | + test_server.SmartTCPServer_for_testing_v2_only, |
1019 | + test_server.ReadonlySmartTCPServer_for_testing_v2_only, |
1020 | + [(RemoteBzrDirFormat())], |
1021 | + name_suffix='-v2')) |
1022 | + |
1023 | result = loader.suiteClass() |
1024 | supported_tests = loader.loadTestsFromModuleNames([ |
1025 | 'bzrlib.tests.per_controldir_colo.test_supported']) |
1026 | |
1027 | === modified file 'bzrlib/tests/per_controldir_colo/test_unsupported.py' |
1028 | --- bzrlib/tests/per_controldir_colo/test_unsupported.py 2012-01-18 17:37:38 +0000 |
1029 | +++ bzrlib/tests/per_controldir_colo/test_unsupported.py 2012-01-28 02:10:28 +0000 |
1030 | @@ -40,9 +40,10 @@ |
1031 | raise tests.TestNotApplicable('Control dir format not supported') |
1032 | t = self.get_transport() |
1033 | try: |
1034 | - made_control = self.bzrdir_format.initialize(t.base) |
1035 | + made_control = self.make_bzrdir('.', format=self.bzrdir_format) |
1036 | except errors.UninitializableFormat: |
1037 | raise tests.TestNotApplicable('Control dir format not initializable') |
1038 | + self.assertEquals(made_control._format, self.bzrdir_format) |
1039 | made_repo = made_control.create_repository() |
1040 | return made_control |
1041 | |
1042 | |
1043 | === modified file 'bzrlib/tests/test_bzrdir.py' |
1044 | --- bzrlib/tests/test_bzrdir.py 2012-01-27 15:47:12 +0000 |
1045 | +++ bzrlib/tests/test_bzrdir.py 2012-01-28 02:10:28 +0000 |
1046 | @@ -1447,8 +1447,8 @@ |
1047 | tree.bzrdir.create_branch(name="another-colocated-branch") |
1048 | converter = tree.bzrdir._format.get_converter( |
1049 | bzrdir.BzrDirMetaFormat1()) |
1050 | - self.assertRaises(errors.BzrError, converter.convert, tree.bzrdir, |
1051 | - None) |
1052 | + result = converter.convert(tree.bzrdir, bzrdir.BzrDirMetaFormat1()) |
1053 | + self.assertIsInstance(result._format, bzrdir.BzrDirMetaFormat1) |
1054 | |
1055 | def test_nested(self): |
1056 | tree = self.make_branch_and_tree('.', format='development-colo') |
1057 | |
1058 | === modified file 'bzrlib/tests/test_remote.py' |
1059 | --- bzrlib/tests/test_remote.py 2012-01-06 22:06:36 +0000 |
1060 | +++ bzrlib/tests/test_remote.py 2012-01-28 02:10:28 +0000 |
1061 | @@ -589,18 +589,6 @@ |
1062 | a_bzrdir.destroy_branch() |
1063 | self.assertFinished(client) |
1064 | |
1065 | - def test_destroy_named(self): |
1066 | - transport = self.get_transport('quack') |
1067 | - referenced = self.make_branch('referenced') |
1068 | - client = FakeClient(transport.base) |
1069 | - client.add_expected_call( |
1070 | - 'BzrDir.destroy_branch', ('quack/', "foo"), |
1071 | - 'success', ('ok',)), |
1072 | - a_bzrdir = RemoteBzrDir(transport, RemoteBzrDirFormat(), |
1073 | - _client=client) |
1074 | - a_bzrdir.destroy_branch("foo") |
1075 | - self.assertFinished(client) |
1076 | - |
1077 | |
1078 | class TestBzrDirHasWorkingTree(TestRemote): |
1079 | |
1080 | |
1081 | === modified file 'bzrlib/transport/__init__.py' |
1082 | --- bzrlib/transport/__init__.py 2012-01-20 13:15:15 +0000 |
1083 | +++ bzrlib/transport/__init__.py 2012-01-28 02:10:28 +0000 |
1084 | @@ -364,7 +364,7 @@ |
1085 | """ |
1086 | raise NotImplementedError(self.clone) |
1087 | |
1088 | - def create_prefix(self): |
1089 | + def create_prefix(self, mode=None): |
1090 | """Create all the directories leading down to self.base.""" |
1091 | cur_transport = self |
1092 | needed = [cur_transport] |
1093 | @@ -376,7 +376,7 @@ |
1094 | "Failed to create path prefix for %s." |
1095 | % cur_transport.base) |
1096 | try: |
1097 | - new_transport.mkdir('.') |
1098 | + new_transport.mkdir('.', mode=mode) |
1099 | except errors.NoSuchFile: |
1100 | needed.append(new_transport) |
1101 | cur_transport = new_transport |
1102 | @@ -387,9 +387,9 @@ |
1103 | # Now we only need to create child directories |
1104 | while needed: |
1105 | cur_transport = needed.pop() |
1106 | - cur_transport.ensure_base() |
1107 | + cur_transport.ensure_base(mode=mode) |
1108 | |
1109 | - def ensure_base(self): |
1110 | + def ensure_base(self, mode=None): |
1111 | """Ensure that the directory this transport references exists. |
1112 | |
1113 | This will create a directory if it doesn't exist. |
1114 | @@ -399,7 +399,7 @@ |
1115 | # than permission". We attempt to create the directory, and just |
1116 | # suppress FileExists and PermissionDenied (for Windows) exceptions. |
1117 | try: |
1118 | - self.mkdir('.') |
1119 | + self.mkdir('.', mode=mode) |
1120 | except (errors.FileExists, errors.PermissionDenied): |
1121 | return False |
1122 | else: |
1123 | |
1124 | === modified file 'doc/en/release-notes/bzr-2.5.txt' |
1125 | --- doc/en/release-notes/bzr-2.5.txt 2012-01-27 21:40:55 +0000 |
1126 | +++ doc/en/release-notes/bzr-2.5.txt 2012-01-28 02:10:28 +0000 |
1127 | @@ -20,6 +20,9 @@ |
1128 | |
1129 | .. New commands, options, etc that users may wish to try out. |
1130 | |
1131 | +* Support for colocated branches is now available in the default |
1132 | + format ("2a"). (Jelmer Vernooij) |
1133 | + |
1134 | Improvements |
1135 | ************ |
1136 |
What are the upgrade implications for users of the current 2a? When they install the new version of bzr that has the new 2a-with-colo, what happens to their existing 2a branches/repos?