Merge lp:~bzr/bzr/smooth-upgrades into lp:~bzr/bzr/trunk-old
- smooth-upgrades
- Merge into trunk-old
Status: | Merged |
---|---|
Merge reported by: | Vincent Ladeuil |
Merged at revision: | not available |
Proposed branch: | lp:~bzr/bzr/smooth-upgrades |
Merge into: | lp:~bzr/bzr/trunk-old |
Diff against target: |
561 lines (has conflicts)
Text conflict in NEWS |
To merge this branch: | bzr merge lp:~bzr/bzr/smooth-upgrades |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Pool | Needs Information | ||
Review via email: mp+8921@code.launchpad.net |
Commit message
Description of the change
Ian Clatworthy (ian-clatworthy) wrote : | # |
Aaron Bentley (abentley) wrote : | # |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
I think you should specify using=True to repo.find_branches. Branches
which aren't using the shared repository aren't really part of it even
if they're inside its directory, and may be in an incompatible format.
Aaron
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://
iEYEARECAAYFAkp
Ot8Ani+
=7UNy
-----END PGP SIGNATURE-----
Robert Collins (lifeless) wrote : | # |
On Fri, 2009-07-17 at 02:45 +0000, Ian Clatworthy wrote:
> Ian Clatworthy has proposed merging lp:~bzr/bzr/smooth-upgrades into lp:bzr.
>
> Requested reviews:
> bzr-core (bzr-core)
>
> This patch adds numerous enhancements to the upgrade command to make upgrading a lot smoother than it currently is. In particular, it now upgrades dependent branches when a shared repository is specified. Based on feedback provided on the mailing list a few months back, it now also supports several new options:
>
> * --dry-run for showing what will happen
>
> * --clean to remove the backup.dir directory on successful completion
I think these are useful
> * --pack to pack the repository on successful completion.
This isn't needed; bzr will autopack if packing helps.
> There's room to make things even nicer still but I think this patch is large enough as is. I'd also like to get these changes landed soon to encourage those of us running Bazaar's trunk to get as many branches as possible converted to 2a prior to the Bazaar 2.0 release.
-Rob
Martin Pool (mbp) wrote : | # |
=== modified file 'NEWS'
--- NEWS 2009-07-15 19:06:39 +0000
+++ NEWS 2009-07-17 02:29:14 +0000
@@ -19,6 +19,17 @@
* ``merge --interactive`` applies a user-selected portion of the merge. The UI
is similar to ``shelve``. (Aaron Bentley)
+* ``upgrade`` now upgrades dependent branches when a shared repository is
+ specified. It also supports several new options:
+
+ * --dry-run for showing what will happen
+
+ * --clean to remove the backup.dir directory on successful completion
+
+ * --pack to pack the repository on successful completion.
+
+ (Ian Clatworthy)
+
I'd put the options in double-backticks too.
You might also find some bug numbers corresponding to these...
Bug Fixes
*********
=== modified file 'bzrlib/
--- bzrlib/builtins.py 2009-07-15 07:32:26 +0000
+++ bzrlib/builtins.py 2009-07-17 02:29:14 +0000
@@ -3122,27 +3122,60 @@
class cmd_upgrade(
- """Upgrade branch storage to current format.
-
- The check command or bzr developers may sometimes advise you to run
- this command. When the default format has changed you may also be warned
- during other operations to upgrade.
+ """Upgrade a repository, branch or working tree to a newer format.
+
+ The check command or Bazaar developers may sometimes advise you to run
+ this command. When the default format has changed after a major new
+ release of Bazaar, you may also be warned during other operations
+ that you should upgrade.
This bit about 'the check command' almost sounds like a mis-copy from
cmd_reconcile. Do we ever specifically recommend an upgrade from check?
Also it might be better off to have the first full paragraph be a more
general explanation like this:
Upgrading to a newer format may improve performance or make
new features available, but it may limit interoperability with
older repositories or with older versions of Bazaar.
Strictly speaking you can also use upgrade to downgrade; it doesn't have
to be to a newer format.
+
+ If the location given is a shared repository, dependent branches
+ are also converted provided the repository converts successfully.
+ If the conversion of a branch fails, remaining branches are still tried.
+
+ A backup.bzr directory is created at the start of the conversion
+ process. By default, this is left there on completion. If the
+ conversion fails, delete the new .bzr directory and rename this
+ one back in its place. Use the --clean option to ask for the
+ backup.bzr directory to be removed on successful conversion.
+ Alternatively, you can delete it by hand if everything looks
+ good afterwards.
+
+ It is often a good idea to pack the repository after an upgrade.
+ Use the --pack option to request this or do it separately using
+ the pack command.
+
+ For more information on upgrades, see the Bazaar 2.0 Upgrade Guide.
"""
- _see_also = ['check']
+ _see_also = ['check', 'reconcile', 'pack']
Also current-formats etc?
takes_args = ['url?']
takes_options = [
- RegistryOption(
- help='Upgrade to a specific format. See "bzr help'
- ...
Martin Pool (mbp) wrote : | # |
I think this is now back in Ian's court.
Matthew Fuller (fullermd) wrote : | # |
See mp42746 for an updated version of this.
Vincent Ladeuil (vila) wrote : | # |
This could be considered merged now.
Preview Diff
1 | === modified file 'NEWS' |
2 | --- NEWS 2009-08-30 23:51:10 +0000 |
3 | +++ NEWS 2009-08-31 04:36:58 +0000 |
4 | @@ -9,6 +9,7 @@ |
5 | In Development |
6 | ############## |
7 | |
8 | +<<<<<<< TREE |
9 | Compatibility Breaks |
10 | ******************** |
11 | |
12 | @@ -90,6 +91,8 @@ |
13 | least six months or until the following stable release (we said |
14 | that previously, but that's worth repeating). |
15 | |
16 | +======= |
17 | +>>>>>>> MERGE-SOURCE |
18 | Compatibility Breaks |
19 | ******************** |
20 | |
21 | @@ -107,12 +110,25 @@ |
22 | New Features |
23 | ************ |
24 | |
25 | +<<<<<<< TREE |
26 | * ``bzr branch --switch`` can now switch the checkout in the current directory |
27 | to the newly created branch. (Lukáš Lalinský) |
28 | |
29 | +======= |
30 | +* ``upgrade`` now upgrades dependent branches when a shared repository is |
31 | + specified. It also supports several new options: |
32 | + |
33 | + * ``--dry-run`` for showing what will happen |
34 | + |
35 | + * ``--clean`` to remove the backup.dir directory on successful completion. |
36 | + |
37 | + (Ian Clatworthy) |
38 | + |
39 | +>>>>>>> MERGE-SOURCE |
40 | Bug Fixes |
41 | ********* |
42 | |
43 | +<<<<<<< TREE |
44 | * Further tweaks to handling of ``bzr add`` messages about ignored files. |
45 | (Jason Spashett, #76616) |
46 | |
47 | @@ -141,6 +157,11 @@ |
48 | fetching only a few hundred bytes at a time. |
49 | (Andrew Bennetts, #402657) |
50 | |
51 | +======= |
52 | +* Fix a test failure on karmic by making a locale test more robust. |
53 | + (Vincent Ladeuil, #413514) |
54 | + |
55 | +>>>>>>> MERGE-SOURCE |
56 | Improvements |
57 | ************ |
58 | |
59 | @@ -379,6 +400,7 @@ |
60 | if password authentication is even supported. This fixes a bug where |
61 | users would be prompted for a launchpad password, even though launchpad |
62 | only supports publickey authentication. (John Arbash Meinel, #375867) |
63 | +>>>>>>> MERGE-SOURCE |
64 | |
65 | * BranchBuilder now accepts timezone to avoid test failures in countries far |
66 | from GMT. (Vincent Ladeuil, #397716) |
67 | |
68 | === modified file 'bzrlib/builtins.py' |
69 | --- bzrlib/builtins.py 2009-08-28 05:00:33 +0000 |
70 | +++ bzrlib/builtins.py 2009-08-31 04:36:59 +0000 |
71 | @@ -3139,27 +3139,62 @@ |
72 | |
73 | |
74 | class cmd_upgrade(Command): |
75 | - """Upgrade branch storage to current format. |
76 | - |
77 | - The check command or bzr developers may sometimes advise you to run |
78 | - this command. When the default format has changed you may also be warned |
79 | - during other operations to upgrade. |
80 | + """Upgrade a repository, branch or working tree to a newer format. |
81 | + |
82 | + When the default format has changed after a major new release of |
83 | + Bazaar, you may be informed during certain operations that you |
84 | + should upgrade. Upgrading to a newer format may improve performance |
85 | + or make new features available. It may however limit interoperability |
86 | + with older repositories or with older versions of Bazaar. |
87 | + |
88 | + If you wish to upgrade to a particular format rather than the |
89 | + current default, that can be specified using the --format option. |
90 | + As a consequence, you can use the upgrade command this way to |
91 | + "downgrade" to an earlier format, though some conversions are |
92 | + a one way process (e.g. changing from the 1.x default to the |
93 | + 2.x default) so downgrading is not always possible. |
94 | + |
95 | + A backup.bzr directory is created at the start of the conversion |
96 | + process. By default, this is left there on completion. If the |
97 | + conversion fails, delete the new .bzr directory and rename this |
98 | + one back in its place. Use the --clean option to ask for the |
99 | + backup.bzr directory to be removed on successful conversion. |
100 | + Alternatively, you can delete it by hand if everything looks |
101 | + good afterwards. |
102 | + |
103 | + If the location given is a shared repository, dependent branches |
104 | + are also converted provided the repository converts successfully. |
105 | + If the conversion of a branch fails, remaining branches are still |
106 | + tried. |
107 | + |
108 | + For more information on upgrades, see the Bazaar 2.0 Upgrade Guide, |
109 | + http://doc.bazaar-vcs.org/latest/en/upgrade-guide/. |
110 | """ |
111 | |
112 | - _see_also = ['check'] |
113 | + _see_also = ['check', 'reconcile', 'formats'] |
114 | takes_args = ['url?'] |
115 | takes_options = [ |
116 | - RegistryOption('format', |
117 | - help='Upgrade to a specific format. See "bzr help' |
118 | - ' formats" for details.', |
119 | - lazy_registry=('bzrlib.bzrdir', 'format_registry'), |
120 | - converter=lambda name: bzrdir.format_registry.make_bzrdir(name), |
121 | - value_switches=True, title='Branch format'), |
122 | - ] |
123 | + RegistryOption('format', |
124 | + help='Upgrade to a specific format. See "bzr help' |
125 | + ' formats" for details.', |
126 | + lazy_registry=('bzrlib.bzrdir', 'format_registry'), |
127 | + converter=lambda name: bzrdir.format_registry.make_bzrdir(name), |
128 | + value_switches=True, title='Branch format'), |
129 | + Option('clean', |
130 | + help='Remove the backup.bzr directory if successful.'), |
131 | + Option('dry-run', |
132 | + help="Show what would be done, but don't actually do anything."), |
133 | + ] |
134 | |
135 | - def run(self, url='.', format=None): |
136 | + def run(self, url='.', format=None, clean=False, dry_run=False): |
137 | from bzrlib.upgrade import upgrade |
138 | - upgrade(url, format) |
139 | + exceptions = upgrade(url, format, clean_up=clean, dry_run=dry_run) |
140 | + if exceptions: |
141 | + if len(exceptions) == 1: |
142 | + # This provides backwards compatibility |
143 | + raise exceptions[0] |
144 | + else: |
145 | + return 3 |
146 | |
147 | |
148 | class cmd_whoami(Command): |
149 | |
150 | === modified file 'bzrlib/bzrdir.py' |
151 | --- bzrlib/bzrdir.py 2009-08-21 02:10:06 +0000 |
152 | +++ bzrlib/bzrdir.py 2009-08-31 04:36:59 +0000 |
153 | @@ -88,7 +88,7 @@ |
154 | |
155 | |
156 | class BzrDir(object): |
157 | - """A .bzr control diretory. |
158 | + """A .bzr control directory. |
159 | |
160 | BzrDir instances let you create or open any of the things that can be |
161 | found within .bzr - checkouts, branches and repositories. |
162 | @@ -1300,6 +1300,40 @@ |
163 | push_result.branch_push_result.target_branch |
164 | return push_result |
165 | |
166 | + def _get_object_and_label(self): |
167 | + """Return the primary object and type label for a control directory. |
168 | + |
169 | + :return: object, label where |
170 | + object is a Branch, Repository or WorkingTree and |
171 | + label is one of: |
172 | + branch - a branch |
173 | + repository - a repository |
174 | + tree - a lightweight checkout |
175 | + """ |
176 | + try: |
177 | + try: |
178 | + br = self.open_branch(unsupported=True, ignore_fallbacks=True) |
179 | + except TypeError: |
180 | + # RemoteRepository doesn't support the unsupported parameter |
181 | + br = self.open_branch(ignore_fallbacks=True) |
182 | + except errors.NotBranchError: |
183 | + pass |
184 | + else: |
185 | + return br, "branch" |
186 | + try: |
187 | + repo = self.open_repository() |
188 | + except errors.NoRepositoryPresent: |
189 | + pass |
190 | + else: |
191 | + return repo, "repository" |
192 | + try: |
193 | + wt = self.open_workingtree() |
194 | + except (errors.NoWorkingTree, errors.NotLocalUrl): |
195 | + pass |
196 | + else: |
197 | + return wt, "tree" |
198 | + raise AssertionError("unknown type of control directory %s", self) |
199 | + |
200 | |
201 | class BzrDirHooks(hooks.Hooks): |
202 | """Hooks for BzrDir operations.""" |
203 | |
204 | === modified file 'bzrlib/tests/blackbox/test_upgrade.py' |
205 | --- bzrlib/tests/blackbox/test_upgrade.py 2009-08-21 02:10:06 +0000 |
206 | +++ bzrlib/tests/blackbox/test_upgrade.py 2009-08-31 04:36:59 +0000 |
207 | @@ -154,6 +154,29 @@ |
208 | self.run_bzr('init-repository --format=metaweave repo') |
209 | self.run_bzr('upgrade --format=knit repo') |
210 | |
211 | + def _assert_option_legal(self, option_str): |
212 | + # Confirm that an option is legal. (Lower level tests are |
213 | + # expected to validate the actual functionality.) |
214 | + self.run_bzr('init --format=pack-0.92 branch-foo') |
215 | + self.run_bzr('upgrade --format=2a branch-foo %s' % (option_str,)) |
216 | + |
217 | + def _assert_branch_format(self, dir, format): |
218 | + branch = bzrdir.BzrDir.open_tree_or_branch(self.get_url(dir))[1] |
219 | + branch_format = branch._format |
220 | + meta_format = bzrdir.format_registry.make_bzrdir(format) |
221 | + expected_format = meta_format.get_branch_format() |
222 | + self.assertEqual(expected_format, branch_format) |
223 | + |
224 | + def test_upgrade_clean_supported(self): |
225 | + self._assert_option_legal('--clean') |
226 | + self._assert_branch_format('branch-foo', '2a') |
227 | + backup_bzr_dir = os.path.join("branch-foo", "backup.bzr") |
228 | + self.assertFalse(os.path.exists(backup_bzr_dir)) |
229 | + |
230 | + def test_upgrade_dry_run_supported(self): |
231 | + self._assert_option_legal('--dry-run') |
232 | + self._assert_branch_format('branch-foo', 'pack-0.92') |
233 | + |
234 | |
235 | class SFTPTests(TestCaseWithSFTPServer): |
236 | """Tests for upgrade over sftp.""" |
237 | |
238 | === modified file 'bzrlib/tests/test_foreign.py' |
239 | --- bzrlib/tests/test_foreign.py 2009-08-17 07:54:34 +0000 |
240 | +++ bzrlib/tests/test_foreign.py 2009-08-31 04:36:59 +0000 |
241 | @@ -249,7 +249,7 @@ |
242 | self._control_files = lockable_files.LockableFiles(self.transport, |
243 | "lock", lockable_files.TransportLock) |
244 | |
245 | - def open_branch(self, ignore_fallbacks=True): |
246 | + def open_branch(self, unsupported=False, ignore_fallbacks=True): |
247 | return self._format.get_branch_format().open(self, _found=True) |
248 | |
249 | def cloning_metadir(self, stacked=False): |
250 | |
251 | === modified file 'bzrlib/tests/test_upgrade.py' |
252 | --- bzrlib/tests/test_upgrade.py 2009-05-07 05:08:46 +0000 |
253 | +++ bzrlib/tests/test_upgrade.py 2009-08-31 04:36:59 +0000 |
254 | @@ -29,6 +29,7 @@ |
255 | from bzrlib import ( |
256 | branch as _mod_branch, |
257 | bzrdir, |
258 | + osutils, |
259 | progress, |
260 | repository, |
261 | workingtree, |
262 | @@ -38,7 +39,7 @@ |
263 | from bzrlib.branch import Branch |
264 | from bzrlib.tests import TestCaseWithTransport |
265 | from bzrlib.transport import get_transport |
266 | -from bzrlib.upgrade import upgrade |
267 | +from bzrlib.upgrade import upgrade, smart_upgrade |
268 | |
269 | |
270 | class TestUpgrade(TestCaseWithTransport): |
271 | @@ -428,3 +429,62 @@ |
272 | ), |
273 | ( './dir/', ), |
274 | ] |
275 | + |
276 | + |
277 | +class TestSmartUpgrade(TestCaseWithTransport): |
278 | + |
279 | + from_format = "pack-0.92" |
280 | + to_format = bzrdir.format_registry.make_bzrdir("2a") |
281 | + |
282 | + def make_standalone_branch(self): |
283 | + wt = self.make_branch_and_tree("branch1", format=self.from_format) |
284 | + return wt.bzrdir |
285 | + |
286 | + def test_upgrade_standalone_branch(self): |
287 | + control = self.make_standalone_branch() |
288 | + tried, worked, issues = smart_upgrade([control], format=self.to_format) |
289 | + self.assertEqual(1, len(tried)) |
290 | + self.assertEqual(1, len(worked)) |
291 | + self.assertEqual(0, len(issues)) |
292 | + self.failUnlessExists('branch1/backup.bzr') |
293 | + |
294 | + def test_upgrade_standalone_branch_cleanup(self): |
295 | + control = self.make_standalone_branch() |
296 | + tried, worked, issues = smart_upgrade([control], format=self.to_format, |
297 | + clean_up=True) |
298 | + self.assertEqual(1, len(tried)) |
299 | + self.assertEqual(1, len(worked)) |
300 | + self.assertEqual(0, len(issues)) |
301 | + self.failUnlessExists('branch1') |
302 | + self.failUnlessExists('branch1/.bzr') |
303 | + self.failIfExists('branch1/backup.bzr') |
304 | + |
305 | + def make_repo_with_branches(self): |
306 | + repo = self.make_repository('repo', shared=True, |
307 | + format=self.from_format) |
308 | + b1 = self.make_branch("repo/branch1", format=self.from_format) |
309 | + b2 = self.make_branch("repo/branch2", format=self.from_format) |
310 | + return repo.bzrdir |
311 | + |
312 | + def test_upgrade_repo_with_branches(self): |
313 | + control = self.make_repo_with_branches() |
314 | + tried, worked, issues = smart_upgrade([control], format=self.to_format) |
315 | + self.assertEqual(3, len(tried)) |
316 | + self.assertEqual(3, len(worked)) |
317 | + self.assertEqual(0, len(issues)) |
318 | + self.failUnlessExists('repo/backup.bzr') |
319 | + self.failUnlessExists('repo/branch1/backup.bzr') |
320 | + self.failUnlessExists('repo/branch2/backup.bzr') |
321 | + |
322 | + def test_upgrade_repo_with_branches_cleanup(self): |
323 | + control = self.make_repo_with_branches() |
324 | + tried, worked, issues = smart_upgrade([control], format=self.to_format, |
325 | + clean_up=True) |
326 | + self.assertEqual(3, len(tried)) |
327 | + self.assertEqual(3, len(worked)) |
328 | + self.assertEqual(0, len(issues)) |
329 | + self.failUnlessExists('repo') |
330 | + self.failUnlessExists('repo/.bzr') |
331 | + self.failIfExists('repo/backup.bzr') |
332 | + self.failIfExists('repo/branch1/backup.bzr') |
333 | + self.failIfExists('repo/branch2/backup.bzr') |
334 | |
335 | === modified file 'bzrlib/upgrade.py' |
336 | --- bzrlib/upgrade.py 2009-05-07 05:08:46 +0000 |
337 | +++ bzrlib/upgrade.py 2009-08-31 04:36:59 +0000 |
338 | @@ -17,18 +17,36 @@ |
339 | """bzr upgrade logic.""" |
340 | |
341 | |
342 | +from bzrlib import osutils, repository |
343 | from bzrlib.bzrdir import BzrDir, BzrDirFormat, format_registry |
344 | import bzrlib.errors as errors |
345 | from bzrlib.remote import RemoteBzrDir |
346 | from bzrlib.transport import get_transport |
347 | +from bzrlib.trace import mutter, note, warning |
348 | import bzrlib.ui as ui |
349 | |
350 | |
351 | class Convert(object): |
352 | |
353 | - def __init__(self, url, format=None): |
354 | + def __init__(self, url=None, format=None, control_dir=None): |
355 | + """Convert a Bazaar control directory to a given format. |
356 | + |
357 | + Either the url or control_dir parameter must be given. |
358 | + |
359 | + :param url: the URL of the control directory or None if the |
360 | + control_dir is explicitly given instead |
361 | + :param format: the format to convert to or None for the default |
362 | + :param control_dir: the control directory or None if it is |
363 | + specified via the URL parameter instead |
364 | + """ |
365 | self.format = format |
366 | - self.bzrdir = BzrDir.open_unsupported(url) |
367 | + if url is None and control_dir is None: |
368 | + raise AssertionError( |
369 | + "either the url or control_dir parameter must be set.") |
370 | + if control_dir is not None: |
371 | + self.bzrdir = control_dir |
372 | + else: |
373 | + self.bzrdir = BzrDir.open_unsupported(url) |
374 | if isinstance(self.bzrdir, RemoteBzrDir): |
375 | self.bzrdir._ensure_real() |
376 | self.bzrdir = self.bzrdir._real_bzrdir |
377 | @@ -73,13 +91,179 @@ |
378 | self.bzrdir._format) |
379 | self.bzrdir.check_conversion_target(format) |
380 | self.pb.note('starting upgrade of %s', self.transport.base) |
381 | - self.bzrdir.backup_bzrdir() |
382 | + self.backup_oldpath, self.backup_newpath = self.bzrdir.backup_bzrdir() |
383 | while self.bzrdir.needs_format_conversion(format): |
384 | converter = self.bzrdir._format.get_converter(format) |
385 | self.bzrdir = converter.convert(self.bzrdir, self.pb) |
386 | self.pb.note("finished") |
387 | |
388 | - |
389 | -def upgrade(url, format=None): |
390 | - """Upgrade to format, or the default bzrdir format if not supplied.""" |
391 | - Convert(url, format) |
392 | + def clean_up(self): |
393 | + """Clean-up after a conversion. |
394 | + |
395 | + This removes the backup.bzr directory. |
396 | + """ |
397 | + transport = self.transport |
398 | + backup_relpath = transport.relpath(self.backup_newpath) |
399 | + transport.delete_tree(backup_relpath) |
400 | + |
401 | + |
402 | +def upgrade(urls, format=None, clean_up=False, pack=False, dry_run=False): |
403 | + """Upgrade locations to format. |
404 | + |
405 | + This routine wraps the smart_upgrade() routine with a nicer UI. |
406 | + In particular, it ensures all URLs can be opened before starting |
407 | + and reports a summary at the end if more than one upgrade was attempted. |
408 | + This routine is useful for command line tools. Other bzrlib clients |
409 | + probably ought to use smart_upgrade() instead. |
410 | + |
411 | + :param urls: a sequence of URLs to the locations to upgrade. |
412 | + For backwards compatibility, if urls is a string, it is treated |
413 | + as a single URL. |
414 | + :param format: the format to convert to or None for the best default |
415 | + :param clean-up: if True, the backup.bzr directory is removed if the |
416 | + upgrade succeeded for a given repo/branch/tree |
417 | + :param pack: pack repositories that successfully upgrade |
418 | + :param dry_run: show what would happen but don't actually do any upgrades |
419 | + :return: the list of exceptions encountered |
420 | + """ |
421 | + if isinstance(urls, basestring): |
422 | + urls = [urls] |
423 | + control_dirs = [BzrDir.open_unsupported(url) for url in urls] |
424 | + attempted, succeeded, exceptions = smart_upgrade(control_dirs, |
425 | + format, clean_up=clean_up, pack=pack, dry_run=dry_run) |
426 | + if len(attempted) > 1: |
427 | + attempted_count = len(attempted) |
428 | + succeeded_count = len(succeeded) |
429 | + failed_count = attempted_count - succeeded_count |
430 | + note("\nSUMMARY: %d upgrades attempted, %d succeeded, %d failed", |
431 | + attempted_count, succeeded_count, failed_count) |
432 | + return exceptions |
433 | + |
434 | + |
435 | +def smart_upgrade(control_dirs, format, clean_up=False, pack=False, |
436 | + dry_run=False): |
437 | + """Convert control directories to a new format intelligently. |
438 | + |
439 | + If the control directory is a shared repository, dependent branches |
440 | + are also converted provided the repository converted successfully. |
441 | + If the conversion of a branch fails, remaining branches are still tried. |
442 | + |
443 | + :param control_dirs: the BzrDirs to upgrade |
444 | + :param format: the format to convert to or None for the best default |
445 | + :param clean-up: if True, the backup.bzr directory is removed if the |
446 | + upgrade succeeded for a given repo/branch/tree |
447 | + :param pack: pack repositories that successfully upgrade |
448 | + :param dry_run: show what would happen but don't actually do any upgrades |
449 | + :return: attempted-control-dirs, succeeded-control-dirs, exceptions |
450 | + """ |
451 | + all_attempted = [] |
452 | + all_succeeded = [] |
453 | + all_exceptions = [] |
454 | + for control_dir in control_dirs: |
455 | + attempted, succeeded, exceptions = _smart_upgrade_one(control_dir, |
456 | + format, clean_up=clean_up, pack=pack, dry_run=dry_run) |
457 | + all_attempted.extend(attempted) |
458 | + all_succeeded.extend(succeeded) |
459 | + all_exceptions.extend(exceptions) |
460 | + return all_attempted, all_succeeded, all_exceptions |
461 | + |
462 | + |
463 | +def _smart_upgrade_one(control_dir, format, clean_up=False, pack=False, |
464 | + dry_run=False): |
465 | + """Convert a control directory to a new format intelligently. |
466 | + |
467 | + See smart_upgrade for parameter details. |
468 | + """ |
469 | + # If the URL is a shared repository, find the dependent branches |
470 | + dependents = None |
471 | + try: |
472 | + repo = control_dir.open_repository() |
473 | + except errors.NoRepositoryPresent: |
474 | + # A branch or checkout using a shared repository higher up |
475 | + pass |
476 | + else: |
477 | + # The URL is a repository. If it successfully upgrades, |
478 | + # then upgrade the dependent branches as well. |
479 | + if repo.is_shared(): |
480 | + dependents = repo.find_branches(using=True) |
481 | + |
482 | + # Do the conversions |
483 | + attempted = [control_dir] |
484 | + succeeded, exceptions = _convert_items([control_dir], format, clean_up, |
485 | + pack, dry_run, verbose=dependents) |
486 | + if succeeded and dependents: |
487 | + note("Found %d dependent branches - upgrading ...", len(dependents)) |
488 | + |
489 | + # Convert dependent branches |
490 | + branch_cdirs = [b.bzrdir for b in dependents] |
491 | + successes, problems = _convert_items(branch_cdirs, format, clean_up, |
492 | + pack, dry_run, label="branch") |
493 | + attempted.extend(branch_cdirs) |
494 | + succeeded.extend(successes) |
495 | + exceptions.extend(problems) |
496 | + |
497 | + # Return the result |
498 | + return attempted, succeeded, exceptions |
499 | + |
500 | + |
501 | +def _convert_items(items, format, clean_up, pack, dry_run, label=None, |
502 | + verbose=True): |
503 | + """Convert a sequence of control directories to the given format. |
504 | + |
505 | + :param items: the control directories to upgrade |
506 | + :param format: the format to convert to or None for the best default |
507 | + :param clean-up: if True, the backup.bzr directory is removed if the |
508 | + upgrade succeeded for a given repo/branch/tree |
509 | + :param pack: pack repositories that successfully upgrade |
510 | + :param dry_run: show what would happen but don't actually do any upgrades |
511 | + :param label: the label for these items or None to calculate one |
512 | + :param verbose: if True, output a message before starting and |
513 | + display any problems encountered |
514 | + :return: items successfully upgraded, exceptions |
515 | + """ |
516 | + succeeded = [] |
517 | + exceptions = [] |
518 | + for control_dir in items: |
519 | + # Do the conversion |
520 | + location = control_dir.root_transport.base |
521 | + bzr_object, bzr_label = control_dir._get_object_and_label() |
522 | + if verbose: |
523 | + type_label = label or bzr_label |
524 | + note("Upgrading %s %s ...", type_label, location) |
525 | + try: |
526 | + if not dry_run: |
527 | + cv = Convert(control_dir=control_dir, format=format) |
528 | + except Exception, ex: |
529 | + _verbose_warning(verbose, "conversion error: %s" % ex) |
530 | + exceptions.append(ex) |
531 | + continue |
532 | + |
533 | + # Do any required post processing |
534 | + succeeded.append(control_dir) |
535 | + if pack and isinstance(bzr_object, repository.Repository): |
536 | + note("Packing ...") |
537 | + try: |
538 | + if not dry_run: |
539 | + bzr_object.pack() |
540 | + except Exception, ex: |
541 | + _verbose_warning(verbose, "failed to pack %s: %s" % |
542 | + (location, ex)) |
543 | + exceptions.append(ex) |
544 | + if clean_up: |
545 | + try: |
546 | + note("Removing backup ...") |
547 | + if not dry_run: |
548 | + cv.clean_up() |
549 | + except Exception, ex: |
550 | + _verbose_warning(verbose, "failed to clean-up %s: %s" % |
551 | + (location, ex)) |
552 | + exceptions.append(ex) |
553 | + |
554 | + # Return the result |
555 | + return succeeded, exceptions |
556 | + |
557 | + |
558 | +def _verbose_warning(verbose, msg): |
559 | + mutter(msg) |
560 | + if verbose: |
561 | + warning(msg) |
This patch adds numerous enhancements to the upgrade command to make upgrading a lot smoother than it currently is. In particular, it now upgrades dependent branches when a shared repository is specified. Based on feedback provided on the mailing list a few months back, it now also supports several new options:
* --dry-run for showing what will happen
* --clean to remove the backup.dir directory on successful completion
* --pack to pack the repository on successful completion.
There's room to make things even nicer still but I think this patch is large enough as is. I'd also like to get these changes landed soon to encourage those of us running Bazaar's trunk to get as many branches as possible converted to 2a prior to the Bazaar 2.0 release.