~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/reconcile.py

  • Committer: Vincent Ladeuil
  • Date: 2012-03-13 17:25:29 UTC
  • mfrom: (6499 +trunk)
  • mto: This revision was merged to the branch mainline in revision 6501.
  • Revision ID: v.ladeuil+lp@free.fr-20120313172529-i0suyjnepsor25i7
Merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Reconcilers are able to fix some potential data errors in a branch."""
18
18
 
 
19
from __future__ import absolute_import
19
20
 
20
21
__all__ = [
21
22
    'KnitReconciler',
29
30
from bzrlib import (
30
31
    cleanup,
31
32
    errors,
 
33
    revision as _mod_revision,
32
34
    ui,
33
35
    )
34
36
from bzrlib.trace import mutter
35
37
from bzrlib.tsort import topo_sort
36
38
from bzrlib.versionedfile import AdapterFactory, FulltextContentFactory
 
39
from bzrlib.i18n import gettext
37
40
 
38
41
 
39
42
def reconcile(dir, canonicalize_chks=False):
64
67
        """Perform reconciliation.
65
68
 
66
69
        After reconciliation the following attributes document found issues:
67
 
        inconsistent_parents: The number of revisions in the repository whose
68
 
                              ancestry was being reported incorrectly.
69
 
        garbage_inventories: The number of inventory objects without revisions
70
 
                             that were garbage collected.
71
 
        fixed_branch_history: None if there was no branch, False if the branch
72
 
                              history was correct, True if the branch history
73
 
                              needed to be re-normalized.
 
70
 
 
71
        * `inconsistent_parents`: The number of revisions in the repository
 
72
          whose ancestry was being reported incorrectly.
 
73
        * `garbage_inventories`: The number of inventory objects without
 
74
          revisions that were garbage collected.
 
75
        * `fixed_branch_history`: None if there was no branch, False if the
 
76
          branch history was correct, True if the branch history needed to be
 
77
          re-normalized.
74
78
        """
75
79
        self.pb = ui.ui_factory.nested_progress_bar()
76
80
        try:
90
94
            # Nothing to check here
91
95
            self.fixed_branch_history = None
92
96
            return
93
 
        ui.ui_factory.note('Reconciling branch %s' % self.branch.base)
 
97
        ui.ui_factory.note(gettext('Reconciling branch %s') % self.branch.base)
94
98
        branch_reconciler = self.branch.reconcile(thorough=True)
95
99
        self.fixed_branch_history = branch_reconciler.fixed_history
96
100
 
97
101
    def _reconcile_repository(self):
98
102
        self.repo = self.bzrdir.find_repository()
99
 
        ui.ui_factory.note('Reconciling repository %s' %
 
103
        ui.ui_factory.note(gettext('Reconciling repository %s') %
100
104
            self.repo.user_url)
101
 
        self.pb.update("Reconciling repository", 0, 1)
 
105
        self.pb.update(gettext("Reconciling repository"), 0, 1)
102
106
        if self.canonicalize_chks:
103
107
            try:
104
108
                self.repo.reconcile_canonicalize_chks
105
109
            except AttributeError:
106
110
                raise errors.BzrError(
107
 
                    "%s cannot canonicalize CHKs." % (self.repo,))
 
111
                    gettext("%s cannot canonicalize CHKs.") % (self.repo,))
108
112
            repo_reconciler = self.repo.reconcile_canonicalize_chks()
109
113
        else:
110
114
            repo_reconciler = self.repo.reconcile(thorough=True)
111
115
        self.inconsistent_parents = repo_reconciler.inconsistent_parents
112
116
        self.garbage_inventories = repo_reconciler.garbage_inventories
113
117
        if repo_reconciler.aborted:
114
 
            ui.ui_factory.note(
115
 
                'Reconcile aborted: revision index has inconsistent parents.')
116
 
            ui.ui_factory.note(
117
 
                'Run "bzr check" for more details.')
 
118
            ui.ui_factory.note(gettext(
 
119
                'Reconcile aborted: revision index has inconsistent parents.'))
 
120
            ui.ui_factory.note(gettext(
 
121
                'Run "bzr check" for more details.'))
118
122
        else:
119
 
            ui.ui_factory.note('Reconciliation complete.')
 
123
            ui.ui_factory.note(gettext('Reconciliation complete.'))
120
124
 
121
125
 
122
126
class BranchReconciler(object):
143
147
        self._reconcile_revision_history()
144
148
 
145
149
    def _reconcile_revision_history(self):
146
 
        repo = self.branch.repository
147
150
        last_revno, last_revision_id = self.branch.last_revision_info()
148
151
        real_history = []
 
152
        graph = self.branch.repository.get_graph()
149
153
        try:
150
 
            for revid in repo.iter_reverse_revision_history(
151
 
                    last_revision_id):
 
154
            for revid in graph.iter_lefthand_ancestry(
 
155
                    last_revision_id, (_mod_revision.NULL_REVISION,)):
152
156
                real_history.append(revid)
153
157
        except errors.RevisionNotPresent:
154
158
            pass # Hit a ghost left hand parent
159
163
            # set_revision_history, as this will regenerate it again.
160
164
            # Not really worth a whole BranchReconciler class just for this,
161
165
            # though.
162
 
            ui.ui_factory.note('Fixing last revision info %s => %s' % (
163
 
                 last_revno, len(real_history)))
 
166
            ui.ui_factory.note(gettext('Fixing last revision info {0} '\
 
167
                                       ' => {1}').format(
 
168
                                       last_revno, len(real_history)))
164
169
            self.branch.set_last_revision_info(len(real_history),
165
170
                                               last_revision_id)
166
171
        else:
167
172
            self.fixed_history = False
168
 
            ui.ui_factory.note('revision_history ok.')
 
173
            ui.ui_factory.note(gettext('revision_history ok.'))
169
174
 
170
175
 
171
176
class RepoReconciler(object):
196
201
        """Perform reconciliation.
197
202
 
198
203
        After reconciliation the following attributes document found issues:
199
 
        inconsistent_parents: The number of revisions in the repository whose
200
 
                              ancestry was being reported incorrectly.
201
 
        garbage_inventories: The number of inventory objects without revisions
202
 
                             that were garbage collected.
 
204
 
 
205
        * `inconsistent_parents`: The number of revisions in the repository
 
206
          whose ancestry was being reported incorrectly.
 
207
        * `garbage_inventories`: The number of inventory objects without
 
208
          revisions that were garbage collected.
203
209
        """
204
210
        operation = cleanup.OperationWithCleanups(self._reconcile)
205
211
        self.add_cleanup = operation.add_cleanup
224
230
        only data-loss causing issues (!self.thorough) or all issues
225
231
        (self.thorough) are treated as requiring the reweave.
226
232
        """
227
 
        # local because needing to know about WeaveFile is a wart we want to hide
228
 
        from bzrlib.weave import WeaveFile, Weave
229
233
        transaction = self.repo.get_transaction()
230
 
        self.pb.update('Reading inventory data')
 
234
        self.pb.update(gettext('Reading inventory data'))
231
235
        self.inventory = self.repo.inventories
232
236
        self.revisions = self.repo.revisions
233
237
        # the total set of revisions to process
247
251
        # (no garbage inventories or we are not doing a thorough check)
248
252
        if (not self.inconsistent_parents and
249
253
            (not self.garbage_inventories or not self.thorough)):
250
 
            ui.ui_factory.note('Inventory ok.')
 
254
            ui.ui_factory.note(gettext('Inventory ok.'))
251
255
            return
252
 
        self.pb.update('Backing up inventory', 0, 0)
 
256
        self.pb.update(gettext('Backing up inventory'), 0, 0)
253
257
        self.repo._backup_inventory()
254
 
        ui.ui_factory.note('Backup inventory created.')
 
258
        ui.ui_factory.note(gettext('Backup inventory created.'))
255
259
        new_inventories = self.repo._temp_inventories()
256
260
 
257
261
        # we have topological order of revisions and non ghost parents ready.
267
271
        if not (set(new_inventories.keys()) ==
268
272
            set([(revid,) for revid in self.pending])):
269
273
            raise AssertionError()
270
 
        self.pb.update('Writing weave')
 
274
        self.pb.update(gettext('Writing weave'))
271
275
        self.repo._activate_new_inventory()
272
276
        self.inventory = None
273
 
        ui.ui_factory.note('Inventory regenerated.')
 
277
        ui.ui_factory.note(gettext('Inventory regenerated.'))
274
278
 
275
279
    def _new_inv_parents(self, revision_key):
276
280
        """Lookup ghost-filtered parents for revision_key."""
364
368
    def _load_indexes(self):
365
369
        """Load indexes for the reconciliation."""
366
370
        self.transaction = self.repo.get_transaction()
367
 
        self.pb.update('Reading indexes', 0, 2)
 
371
        self.pb.update(gettext('Reading indexes'), 0, 2)
368
372
        self.inventory = self.repo.inventories
369
 
        self.pb.update('Reading indexes', 1, 2)
 
373
        self.pb.update(gettext('Reading indexes'), 1, 2)
370
374
        self.repo._check_for_inconsistent_revision_parents()
371
375
        self.revisions = self.repo.revisions
372
 
        self.pb.update('Reading indexes', 2, 2)
 
376
        self.pb.update(gettext('Reading indexes'), 2, 2)
373
377
 
374
378
    def _gc_inventory(self):
375
379
        """Remove inventories that are not referenced from the revision store."""
376
 
        self.pb.update('Checking unused inventories', 0, 1)
 
380
        self.pb.update(gettext('Checking unused inventories'), 0, 1)
377
381
        self._check_garbage_inventories()
378
 
        self.pb.update('Checking unused inventories', 1, 3)
 
382
        self.pb.update(gettext('Checking unused inventories'), 1, 3)
379
383
        if not self.garbage_inventories:
380
 
            ui.ui_factory.note('Inventory ok.')
 
384
            ui.ui_factory.note(gettext('Inventory ok.'))
381
385
            return
382
 
        self.pb.update('Backing up inventory', 0, 0)
 
386
        self.pb.update(gettext('Backing up inventory'), 0, 0)
383
387
        self.repo._backup_inventory()
384
 
        ui.ui_factory.note('Backup Inventory created')
 
388
        ui.ui_factory.note(gettext('Backup Inventory created'))
385
389
        # asking for '' should never return a non-empty weave
386
390
        new_inventories = self.repo._temp_inventories()
387
391
        # we have topological order of revisions and non ghost parents ready.
398
402
        # the revisionds list
399
403
        if not(set(new_inventories.keys()) == set(revision_keys)):
400
404
            raise AssertionError()
401
 
        self.pb.update('Writing weave')
 
405
        self.pb.update(gettext('Writing weave'))
402
406
        self.repo._activate_new_inventory()
403
407
        self.inventory = None
404
 
        ui.ui_factory.note('Inventory regenerated.')
 
408
        ui.ui_factory.note(gettext('Inventory regenerated.'))
405
409
 
406
410
    def _fix_text_parents(self):
407
411
        """Fix bad versionedfile parent entries.
439
443
            versions_list.append(text_key[1])
440
444
        # Do the reconcile of individual weaves.
441
445
        for num, file_id in enumerate(per_id_bad_parents):
442
 
            self.pb.update('Fixing text parents', num,
 
446
            self.pb.update(gettext('Fixing text parents'), num,
443
447
                           len(per_id_bad_parents))
444
448
            versions_with_bad_parents = per_id_bad_parents[file_id]
445
449
            id_unused_versions = set(key[-1] for key in unused_versions