/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/upgrade.py

  • Committer: Martin Pool
  • Date: 2011-05-20 14:46:02 UTC
  • mto: This revision was merged to the branch mainline in revision 5923.
  • Revision ID: mbp@canonical.com-20110520144602-bqli0t6dj01gl0pv
Various pyflakes import fixes.

Some modules were used for subclassing or at module load time, so there is no
point loading them lazily.

Some were not imported when they should be.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2008, 2009, 2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2008-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
17
17
"""bzr upgrade logic."""
18
18
 
19
19
 
20
 
from bzrlib.bzrdir import BzrDir, format_registry
21
 
import bzrlib.errors as errors
 
20
from bzrlib import (
 
21
    errors,
 
22
    trace,
 
23
    ui,
 
24
    )
 
25
from bzrlib.bzrdir import (
 
26
    BzrDir,
 
27
    format_registry,
 
28
    )
22
29
from bzrlib.remote import RemoteBzrDir
23
 
import bzrlib.ui as ui
24
30
 
25
31
 
26
32
class Convert(object):
27
33
 
28
 
    def __init__(self, url, format=None):
 
34
    def __init__(self, url=None, format=None, control_dir=None):
 
35
        """Convert a Bazaar control directory to a given format.
 
36
 
 
37
        Either the url or control_dir parameter must be given.
 
38
 
 
39
        :param url: the URL of the control directory or None if the
 
40
          control_dir is explicitly given instead
 
41
        :param format: the format to convert to or None for the default
 
42
        :param control_dir: the control directory or None if it is
 
43
          specified via the URL parameter instead
 
44
        """
29
45
        self.format = format
30
 
        self.bzrdir = BzrDir.open_unsupported(url)
31
46
        # XXX: Change to cleanup
32
47
        warning_id = 'cross_format_fetch'
33
48
        saved_warning = warning_id in ui.ui_factory.suppressed_warnings
 
49
        if url is None and control_dir is None:
 
50
            raise AssertionError(
 
51
                "either the url or control_dir parameter must be set.")
 
52
        if control_dir is not None:
 
53
            self.bzrdir = control_dir
 
54
        else:
 
55
            self.bzrdir = BzrDir.open_unsupported(url)
34
56
        if isinstance(self.bzrdir, RemoteBzrDir):
35
57
            self.bzrdir._ensure_real()
36
58
            self.bzrdir = self.bzrdir._real_bzrdir
48
70
        try:
49
71
            branch = self.bzrdir.open_branch()
50
72
            if branch.user_url != self.bzrdir.user_url:
51
 
                ui.ui_factory.note("This is a checkout. The branch (%s) needs to be "
52
 
                             "upgraded separately." %
53
 
                             branch.user_url)
 
73
                ui.ui_factory.note(
 
74
                    'This is a checkout. The branch (%s) needs to be upgraded'
 
75
                    ' separately.' % (branch.user_url,))
54
76
            del branch
55
77
        except (errors.NotBranchError, errors.IncompatibleRepositories):
56
78
            # might not be a format we can open without upgrading; see e.g.
76
98
        self.bzrdir.check_conversion_target(format)
77
99
        ui.ui_factory.note('starting upgrade of %s' % self.transport.base)
78
100
 
79
 
        self.bzrdir.backup_bzrdir()
 
101
        self.backup_oldpath, self.backup_newpath = self.bzrdir.backup_bzrdir()
80
102
        while self.bzrdir.needs_format_conversion(format):
81
103
            converter = self.bzrdir._format.get_converter(format)
82
104
            self.bzrdir = converter.convert(self.bzrdir, None)
83
 
        ui.ui_factory.note("finished")
84
 
 
85
 
 
86
 
def upgrade(url, format=None):
87
 
    """Upgrade to format, or the default bzrdir format if not supplied."""
88
 
    Convert(url, format)
 
105
        ui.ui_factory.note('finished')
 
106
 
 
107
    def clean_up(self):
 
108
        """Clean-up after a conversion.
 
109
 
 
110
        This removes the backup.bzr directory.
 
111
        """
 
112
        transport = self.transport
 
113
        backup_relpath = transport.relpath(self.backup_newpath)
 
114
        child_pb = ui.ui_factory.nested_progress_bar()
 
115
        child_pb.update('Deleting backup.bzr')
 
116
        try:
 
117
            transport.delete_tree(backup_relpath)
 
118
        finally:
 
119
            child_pb.finished()
 
120
 
 
121
 
 
122
def upgrade(url, format=None, clean_up=False, dry_run=False):
 
123
    """Upgrade locations to format.
 
124
 
 
125
    This routine wraps the smart_upgrade() routine with a nicer UI.
 
126
    In particular, it ensures all URLs can be opened before starting
 
127
    and reports a summary at the end if more than one upgrade was attempted.
 
128
    This routine is useful for command line tools. Other bzrlib clients
 
129
    probably ought to use smart_upgrade() instead.
 
130
 
 
131
    :param url: a URL of the locations to upgrade.
 
132
    :param format: the format to convert to or None for the best default
 
133
    :param clean-up: if True, the backup.bzr directory is removed if the
 
134
      upgrade succeeded for a given repo/branch/tree
 
135
    :param dry_run: show what would happen but don't actually do any upgrades
 
136
    :return: the list of exceptions encountered
 
137
    """
 
138
    control_dirs = [BzrDir.open_unsupported(url)]
 
139
    attempted, succeeded, exceptions = smart_upgrade(control_dirs,
 
140
        format, clean_up=clean_up, dry_run=dry_run)
 
141
    if len(attempted) > 1:
 
142
        attempted_count = len(attempted)
 
143
        succeeded_count = len(succeeded)
 
144
        failed_count = attempted_count - succeeded_count
 
145
        ui.ui_factory.note(
 
146
            '\nSUMMARY: %d upgrades attempted, %d succeeded, %d failed'
 
147
            % (attempted_count, succeeded_count, failed_count))
 
148
    return exceptions
 
149
 
 
150
 
 
151
def smart_upgrade(control_dirs, format, clean_up=False,
 
152
    dry_run=False):
 
153
    """Convert control directories to a new format intelligently.
 
154
 
 
155
    If the control directory is a shared repository, dependent branches
 
156
    are also converted provided the repository converted successfully.
 
157
    If the conversion of a branch fails, remaining branches are still tried.
 
158
 
 
159
    :param control_dirs: the BzrDirs to upgrade
 
160
    :param format: the format to convert to or None for the best default
 
161
    :param clean_up: if True, the backup.bzr directory is removed if the
 
162
      upgrade succeeded for a given repo/branch/tree
 
163
    :param dry_run: show what would happen but don't actually do any upgrades
 
164
    :return: attempted-control-dirs, succeeded-control-dirs, exceptions
 
165
    """
 
166
    all_attempted = []
 
167
    all_succeeded = []
 
168
    all_exceptions = []
 
169
    for control_dir in control_dirs:
 
170
        attempted, succeeded, exceptions = _smart_upgrade_one(control_dir,
 
171
            format, clean_up=clean_up, dry_run=dry_run)
 
172
        all_attempted.extend(attempted)
 
173
        all_succeeded.extend(succeeded)
 
174
        all_exceptions.extend(exceptions)
 
175
    return all_attempted, all_succeeded, all_exceptions
 
176
 
 
177
 
 
178
def _smart_upgrade_one(control_dir, format, clean_up=False,
 
179
    dry_run=False):
 
180
    """Convert a control directory to a new format intelligently.
 
181
 
 
182
    See smart_upgrade for parameter details.
 
183
    """
 
184
    # If the URL is a shared repository, find the dependent branches
 
185
    dependents = None
 
186
    try:
 
187
        repo = control_dir.open_repository()
 
188
    except errors.NoRepositoryPresent:
 
189
        # A branch or checkout using a shared repository higher up
 
190
        pass
 
191
    else:
 
192
        # The URL is a repository. If it successfully upgrades,
 
193
        # then upgrade the dependent branches as well.
 
194
        if repo.is_shared():
 
195
            dependents = repo.find_branches(using=True)
 
196
 
 
197
    # Do the conversions
 
198
    attempted = [control_dir]
 
199
    succeeded, exceptions = _convert_items([control_dir], format, clean_up,
 
200
                                           dry_run)
 
201
    if succeeded and dependents:
 
202
        ui.ui_factory.note('Found %d dependent branches - upgrading ...'
 
203
                           % (len(dependents),))
 
204
        # Convert dependent branches
 
205
        branch_cdirs = [b.bzrdir for b in dependents]
 
206
        successes, problems = _convert_items(branch_cdirs, format, clean_up,
 
207
            dry_run, label="branch")
 
208
        attempted.extend(branch_cdirs)
 
209
        succeeded.extend(successes)
 
210
        exceptions.extend(problems)
 
211
 
 
212
    # Return the result
 
213
    return attempted, succeeded, exceptions
 
214
 
 
215
# FIXME: There are several problems below:
 
216
# - RemoteRepository doesn't support _unsupported (really ?)
 
217
# - raising AssertionError is rude and may not be necessary
 
218
# - no tests
 
219
# - the only caller uses only the label
 
220
def _get_object_and_label(control_dir):
 
221
    """Return the primary object and type label for a control directory.
 
222
 
 
223
    :return: object, label where:
 
224
      * object is a Branch, Repository or WorkingTree and
 
225
      * label is one of:
 
226
        * branch            - a branch
 
227
        * repository        - a repository
 
228
        * tree              - a lightweight checkout
 
229
    """
 
230
    try:
 
231
        try:
 
232
            br = control_dir.open_branch(unsupported=True,
 
233
                                         ignore_fallbacks=True)
 
234
        except NotImplementedError:
 
235
            # RemoteRepository doesn't support the unsupported parameter
 
236
            br = control_dir.open_branch(ignore_fallbacks=True)
 
237
    except errors.NotBranchError:
 
238
        pass
 
239
    else:
 
240
        return br, "branch"
 
241
    try:
 
242
        repo = control_dir.open_repository()
 
243
    except errors.NoRepositoryPresent:
 
244
        pass
 
245
    else:
 
246
        return repo, "repository"
 
247
    try:
 
248
        wt = control_dir.open_workingtree()
 
249
    except (errors.NoWorkingTree, errors.NotLocalUrl):
 
250
        pass
 
251
    else:
 
252
        return wt, "tree"
 
253
    raise AssertionError("unknown type of control directory %s", control_dir)
 
254
 
 
255
 
 
256
def _convert_items(items, format, clean_up, dry_run, label=None):
 
257
    """Convert a sequence of control directories to the given format.
 
258
 
 
259
    :param items: the control directories to upgrade
 
260
    :param format: the format to convert to or None for the best default
 
261
    :param clean-up: if True, the backup.bzr directory is removed if the
 
262
      upgrade succeeded for a given repo/branch/tree
 
263
    :param dry_run: show what would happen but don't actually do any upgrades
 
264
    :param label: the label for these items or None to calculate one
 
265
    :return: items successfully upgraded, exceptions
 
266
    """
 
267
    succeeded = []
 
268
    exceptions = []
 
269
    child_pb = ui.ui_factory.nested_progress_bar()
 
270
    child_pb.update('Upgrading bzrdirs', 0, len(items))
 
271
    for i, control_dir in enumerate(items):
 
272
        # Do the conversion
 
273
        location = control_dir.root_transport.base
 
274
        bzr_object, bzr_label = _get_object_and_label(control_dir)
 
275
        type_label = label or bzr_label
 
276
        child_pb.update("Upgrading %s" % (type_label), i+1, len(items))
 
277
        ui.ui_factory.note('Upgrading %s %s ...' % (type_label, location,))
 
278
        try:
 
279
            if not dry_run:
 
280
                cv = Convert(control_dir=control_dir, format=format)
 
281
        except Exception, ex:
 
282
            trace.warning('conversion error: %s' % ex)
 
283
            exceptions.append(ex)
 
284
            continue
 
285
 
 
286
        # Do any required post processing
 
287
        succeeded.append(control_dir)
 
288
        if clean_up:
 
289
            try:
 
290
                ui.ui_factory.note('Removing backup ...')
 
291
                if not dry_run:
 
292
                    cv.clean_up()
 
293
            except Exception, ex:
 
294
                trace.warning('failed to clean-up %s: %s' % (location, ex))
 
295
                exceptions.append(ex)
 
296
 
 
297
    child_pb.finished()
 
298
 
 
299
    # Return the result
 
300
    return succeeded, exceptions