Merge lp:~bzr/bzr/smooth-upgrades into lp:~bzr/bzr/trunk-old

Proposed by Ian Clatworthy
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
Reviewer Review Type Date Requested Status
Martin Pool Needs Information
Review via email: mp+8921@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Ian Clatworthy (ian-clatworthy) wrote :

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.

Revision history for this message
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://enigmail.mozdev.org

iEYEARECAAYFAkpgAO8ACgkQ0F+nu1YWqI1dTACfdxd519YTqoOuTz1OOa9zjtjY
Ot8Ani+XpR4URG8cbbbh5sBDWVr+/t6H
=7UNy
-----END PGP SIGNATURE-----

Revision history for this message
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

Revision history for this message
Martin Pool (mbp) wrote :
Download full text (22.4 KiB)

=== 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/builtins.py'
--- 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(Command):
- """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('format',
- help='Upgrade to a specific format. See "bzr help'
- ...

review: Needs Information
Revision history for this message
Martin Pool (mbp) wrote :

I think this is now back in Ian's court.

Revision history for this message
Matthew Fuller (fullermd) wrote :

See mp42746 for an updated version of this.

Revision history for this message
Vincent Ladeuil (vila) wrote :

This could be considered merged now.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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)