~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/reconcile.py

  • Committer: Matthew Fuller
  • Date: 2009-08-18 08:10:44 UTC
  • mto: (4772.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 4773.
  • Revision ID: fullermd@over-yonder.net-20090818081044-2due6ius01c4pwjl
Fix up some doctests to handle things ending up as RevisionSpec_dwim's
instead of RS_revno, and ending up as _dwim's (which may error
eventually, but won't until we try to evaluate them) instead of
insta-errors.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 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
27
27
 
28
28
 
29
29
from bzrlib import (
30
 
    cleanup,
31
30
    errors,
32
31
    ui,
33
32
    repository,
 
33
    repofmt,
34
34
    )
35
 
from bzrlib.trace import mutter
36
 
from bzrlib.tsort import topo_sort
 
35
from bzrlib.trace import mutter, note
 
36
from bzrlib.tsort import TopoSorter
37
37
from bzrlib.versionedfile import AdapterFactory, FulltextContentFactory
38
38
 
39
39
 
90
90
            # Nothing to check here
91
91
            self.fixed_branch_history = None
92
92
            return
93
 
        ui.ui_factory.note('Reconciling branch %s' % self.branch.base)
 
93
        self.pb.note('Reconciling branch %s',
 
94
                     self.branch.base)
94
95
        branch_reconciler = self.branch.reconcile(thorough=True)
95
96
        self.fixed_branch_history = branch_reconciler.fixed_history
96
97
 
97
98
    def _reconcile_repository(self):
98
99
        self.repo = self.bzrdir.find_repository()
99
 
        ui.ui_factory.note('Reconciling repository %s' %
100
 
            self.repo.bzrdir.root_transport.base)
 
100
        self.pb.note('Reconciling repository %s',
 
101
                     self.repo.bzrdir.root_transport.base)
101
102
        self.pb.update("Reconciling repository", 0, 1)
102
103
        repo_reconciler = self.repo.reconcile(thorough=True)
103
104
        self.inconsistent_parents = repo_reconciler.inconsistent_parents
104
105
        self.garbage_inventories = repo_reconciler.garbage_inventories
105
106
        if repo_reconciler.aborted:
106
 
            ui.ui_factory.note(
 
107
            self.pb.note(
107
108
                'Reconcile aborted: revision index has inconsistent parents.')
108
 
            ui.ui_factory.note(
 
109
            self.pb.note(
109
110
                'Run "bzr check" for more details.')
110
111
        else:
111
 
            ui.ui_factory.note('Reconciliation complete.')
 
112
            self.pb.note('Reconciliation complete.')
112
113
 
113
114
 
114
115
class BranchReconciler(object):
120
121
        self.branch = a_branch
121
122
 
122
123
    def reconcile(self):
123
 
        operation = cleanup.OperationWithCleanups(self._reconcile)
124
 
        self.add_cleanup = operation.add_cleanup
125
 
        operation.run_simple()
126
 
 
127
 
    def _reconcile(self):
128
124
        self.branch.lock_write()
129
 
        self.add_cleanup(self.branch.unlock)
130
 
        self.pb = ui.ui_factory.nested_progress_bar()
131
 
        self.add_cleanup(self.pb.finished)
132
 
        self._reconcile_steps()
 
125
        try:
 
126
            self.pb = ui.ui_factory.nested_progress_bar()
 
127
            try:
 
128
                self._reconcile_steps()
 
129
            finally:
 
130
                self.pb.finished()
 
131
        finally:
 
132
            self.branch.unlock()
133
133
 
134
134
    def _reconcile_steps(self):
135
135
        self._reconcile_revision_history()
151
151
            # set_revision_history, as this will regenerate it again.
152
152
            # Not really worth a whole BranchReconciler class just for this,
153
153
            # though.
154
 
            ui.ui_factory.note('Fixing last revision info %s => %s' % (
155
 
                 last_revno, len(real_history)))
 
154
            self.pb.note('Fixing last revision info %s => %s',
 
155
                         last_revno, len(real_history))
156
156
            self.branch.set_last_revision_info(len(real_history),
157
157
                                               last_revision_id)
158
158
        else:
159
159
            self.fixed_history = False
160
 
            ui.ui_factory.note('revision_history ok.')
 
160
            self.pb.note('revision_history ok.')
161
161
 
162
162
 
163
163
class RepoReconciler(object):
193
193
        garbage_inventories: The number of inventory objects without revisions
194
194
                             that were garbage collected.
195
195
        """
196
 
        operation = cleanup.OperationWithCleanups(self._reconcile)
197
 
        self.add_cleanup = operation.add_cleanup
198
 
        operation.run_simple()
199
 
 
200
 
    def _reconcile(self):
201
196
        self.repo.lock_write()
202
 
        self.add_cleanup(self.repo.unlock)
203
 
        self.pb = ui.ui_factory.nested_progress_bar()
204
 
        self.add_cleanup(self.pb.finished)
205
 
        self._reconcile_steps()
 
197
        try:
 
198
            self.pb = ui.ui_factory.nested_progress_bar()
 
199
            try:
 
200
                self._reconcile_steps()
 
201
            finally:
 
202
                self.pb.finished()
 
203
        finally:
 
204
            self.repo.unlock()
206
205
 
207
206
    def _reconcile_steps(self):
208
207
        """Perform the steps to reconcile this repository."""
239
238
        # (no garbage inventories or we are not doing a thorough check)
240
239
        if (not self.inconsistent_parents and
241
240
            (not self.garbage_inventories or not self.thorough)):
242
 
            ui.ui_factory.note('Inventory ok.')
 
241
            self.pb.note('Inventory ok.')
243
242
            return
244
243
        self.pb.update('Backing up inventory', 0, 0)
245
244
        self.repo._backup_inventory()
246
 
        ui.ui_factory.note('Backup inventory created.')
 
245
        self.pb.note('Backup inventory created.')
247
246
        new_inventories = self.repo._temp_inventories()
248
247
 
249
248
        # we have topological order of revisions and non ghost parents ready.
250
249
        self._setup_steps(len(self._rev_graph))
251
 
        revision_keys = [(rev_id,) for rev_id in topo_sort(self._rev_graph)]
 
250
        revision_keys = [(rev_id,) for rev_id in
 
251
            TopoSorter(self._rev_graph.items()).iter_topo_order()]
252
252
        stream = self._change_inv_parents(
253
253
            self.inventory.get_record_stream(revision_keys, 'unordered', True),
254
254
            self._new_inv_parents,
262
262
        self.pb.update('Writing weave')
263
263
        self.repo._activate_new_inventory()
264
264
        self.inventory = None
265
 
        ui.ui_factory.note('Inventory regenerated.')
 
265
        self.pb.note('Inventory regenerated.')
266
266
 
267
267
    def _new_inv_parents(self, revision_key):
268
268
        """Lookup ghost-filtered parents for revision_key."""
369
369
        self._check_garbage_inventories()
370
370
        self.pb.update('Checking unused inventories', 1, 3)
371
371
        if not self.garbage_inventories:
372
 
            ui.ui_factory.note('Inventory ok.')
 
372
            self.pb.note('Inventory ok.')
373
373
            return
374
374
        self.pb.update('Backing up inventory', 0, 0)
375
375
        self.repo._backup_inventory()
376
 
        ui.ui_factory.note('Backup Inventory created')
 
376
        self.pb.note('Backup Inventory created')
377
377
        # asking for '' should never return a non-empty weave
378
378
        new_inventories = self.repo._temp_inventories()
379
379
        # we have topological order of revisions and non ghost parents ready.
380
380
        graph = self.revisions.get_parent_map(self.revisions.keys())
381
 
        revision_keys = topo_sort(graph)
 
381
        revision_keys = list(TopoSorter(graph).iter_topo_order())
382
382
        revision_ids = [key[-1] for key in revision_keys]
383
383
        self._setup_steps(len(revision_keys))
384
384
        stream = self._change_inv_parents(
393
393
        self.pb.update('Writing weave')
394
394
        self.repo._activate_new_inventory()
395
395
        self.inventory = None
396
 
        ui.ui_factory.note('Inventory regenerated.')
 
396
        self.pb.note('Inventory regenerated.')
397
397
 
398
398
    def _fix_text_parents(self):
399
399
        """Fix bad versionedfile parent entries.
504
504
        collection = self.repo._pack_collection
505
505
        collection.ensure_loaded()
506
506
        collection.lock_names()
507
 
        self.add_cleanup(collection._unlock_names)
508
 
        packs = collection.all_packs()
509
 
        all_revisions = self.repo.all_revision_ids()
510
 
        total_inventories = len(list(
511
 
            collection.inventory_index.combined_index.iter_all_entries()))
512
 
        if len(all_revisions):
513
 
            new_pack =  self.repo._reconcile_pack(collection, packs,
514
 
                ".reconcile", all_revisions, self.pb)
515
 
            if new_pack is not None:
 
507
        try:
 
508
            packs = collection.all_packs()
 
509
            all_revisions = self.repo.all_revision_ids()
 
510
            total_inventories = len(list(
 
511
                collection.inventory_index.combined_index.iter_all_entries()))
 
512
            if len(all_revisions):
 
513
                new_pack =  self.repo._reconcile_pack(collection, packs,
 
514
                    ".reconcile", all_revisions, self.pb)
 
515
                if new_pack is not None:
 
516
                    self._discard_and_save(packs)
 
517
            else:
 
518
                # only make a new pack when there is data to copy.
516
519
                self._discard_and_save(packs)
517
 
        else:
518
 
            # only make a new pack when there is data to copy.
519
 
            self._discard_and_save(packs)
520
 
        self.garbage_inventories = total_inventories - len(list(
521
 
            collection.inventory_index.combined_index.iter_all_entries()))
 
520
            self.garbage_inventories = total_inventories - len(list(
 
521
                collection.inventory_index.combined_index.iter_all_entries()))
 
522
        finally:
 
523
            collection._unlock_names()
522
524
 
523
525
    def _discard_and_save(self, packs):
524
526
        """Discard some packs from the repository.