/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2005, 2006 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1 by mbp at sourcefrog
import from baz patch-364
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1 by mbp at sourcefrog
import from baz patch-364
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1 by mbp at sourcefrog
import from baz patch-364
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1 by mbp at sourcefrog
import from baz patch-364
16
1335 by Martin Pool
doc
17
# TODO: Check ancestries are correct for every revision: includes
18
# every committed so far, and in a reasonable order.
19
1347 by Martin Pool
- refactor check code into method object
20
# TODO: Also check non-mainline revisions mentioned as parents.
21
22
# TODO: Check for extra files in the control directory.
23
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
24
# TODO: Check revision, inventory and entry objects have all
1348 by Martin Pool
- more refactoring of check code
25
# required fields.
26
1185.16.101 by mbp at sourcefrog
todo
27
# TODO: Get every revision in the revision-store even if they're not
28
# referenced by history and make sure they're all valid.
1347 by Martin Pool
- refactor check code into method object
29
1616.1.5 by Martin Pool
Cleanup and document some check code
30
# TODO: Perhaps have a way to record errors other than by raising exceptions;
31
# would perhaps be enough to accumulate exception objects in a list without
32
# raising them.  If there's more than one exception it'd be good to see them
33
# all.
34
4332.3.2 by Robert Collins
Extract repository access in WorkingTree._check to be data driven, adding a new _get_check_refs method to support this.
35
"""Checking of bzr objects.
36
37
check_refs is a concept used for optimising check. Objects that depend on other
38
objects (e.g. tree on repository) can list the objects they would be requesting
39
so that when the dependent object is checked, matches can be pulled out and
40
evaluated in-line rather than re-reading the same data many times.
41
check_refs are tuples (kind, value). Currently defined kinds are:
5891.1.2 by Andrew Bennetts
Fix a bunch of docstring formatting nits, making pydoctor a bit happier.
42
4332.3.5 by Robert Collins
Add Branch._get_check_refs.
43
* 'trees', where value is a revid and the looked up objects are revision trees.
44
* 'lefthand-distance', where value is a revid and the looked up objects are the
45
  distance along the lefthand path to NULL for that revid.
46
* 'revision-existence', where value is a revid, and the result is True or False
47
  indicating that the revision was found/not found.
4332.3.2 by Robert Collins
Extract repository access in WorkingTree._check to be data driven, adding a new _get_check_refs method to support this.
48
"""
49
6379.6.7 by Jelmer Vernooij
Move importing from future until after doc string, otherwise the doc string will disappear.
50
from __future__ import absolute_import
51
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
52
from . import (
5582.10.8 by Jelmer Vernooij
More fixes.
53
    errors,
54
    ui,
55
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
56
from .branch import Branch
57
from .controldir import ControlDir
58
from .revision import NULL_REVISION
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
59
from .sixish import (
60
    viewitems,
61
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
62
from .trace import note
63
from .workingtree import WorkingTree
64
from .i18n import gettext
5850.1.3 by Jelmer Vernooij
Add VersionedFileCheck.
65
1347 by Martin Pool
- refactor check code into method object
66
class Check(object):
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
67
    """Check a repository"""
1449 by Robert Collins
teach check about ghosts
68
5850.1.3 by Jelmer Vernooij
Add VersionedFileCheck.
69
    def __init__(self, repository, check_repo=True):
70
        self.repository = repository
71
72
    def report_results(self, verbose):
73
        raise NotImplementedError(self.report_results)
74
75
76
class VersionedFileCheck(Check):
77
    """Check a versioned file repository"""
78
1616.1.5 by Martin Pool
Cleanup and document some check code
79
    # The Check object interacts with InventoryEntry.check, etc.
80
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
81
    def __init__(self, repository, check_repo=True):
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
82
        self.repository = repository
1383 by Martin Pool
- untabify only
83
        self.checked_rev_cnt = 0
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
84
        self.ghosts = set()
1449 by Robert Collins
teach check about ghosts
85
        self.missing_parent_links = {}
1348 by Martin Pool
- more refactoring of check code
86
        self.missing_inventory_sha_cnt = 0
87
        self.missing_revision_cnt = 0
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
88
        self.checked_weaves = set()
2988.1.8 by Robert Collins
Change check and reconcile to use the new _generate_text_key_index rather
89
        self.unreferenced_versions = set()
2745.6.33 by Andrew Bennetts
Add VersionedFile.check_parents, and use it instead of find_bad_ancestors in reconcile.
90
        self.inconsistent_parents = []
4145.2.1 by Ian Clatworthy
faster check
91
        self.rich_roots = repository.supports_rich_root()
92
        self.text_key_references = {}
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
93
        self.check_repo = check_repo
94
        self.other_results = []
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
95
        # Plain text lines to include in the report
96
        self._report_items = []
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
97
        # Keys we are looking for; may be large and need spilling to disk.
98
        # key->(type(revision/inventory/text/signature/map), sha1, first-referer)
99
        self.pending_keys = {}
4332.3.15 by Robert Collins
Keep an ancestors dict in check rather than recreating one multiple times.
100
        # Ancestors map for all of revisions being checked; while large helper
101
        # functions we call would create it anyway, so better to have once and
102
        # keep.
103
        self.ancestors = {}
676 by Martin Pool
- lock branch while checking
104
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
105
    def check(self, callback_refs=None, check_repo=True):
106
        if callback_refs is None:
107
            callback_refs = {}
6861.4.1 by Jelmer Vernooij
Make progress bars context managers.
108
        with self.repository.lock_read(), ui.ui_factory.nested_progress_bar() as self.progress:
6138.4.1 by Jonathan Riddell
add gettext to progress bar strings
109
            self.progress.update(gettext('check'), 0, 4)
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
110
            if self.check_repo:
6138.4.1 by Jonathan Riddell
add gettext to progress bar strings
111
                self.progress.update(gettext('checking revisions'), 0)
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
112
                self.check_revisions()
6138.4.1 by Jonathan Riddell
add gettext to progress bar strings
113
                self.progress.update(gettext('checking commit contents'), 1)
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
114
                self.repository._check_inventories(self)
6138.4.1 by Jonathan Riddell
add gettext to progress bar strings
115
                self.progress.update(gettext('checking file graphs'), 2)
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
116
                # check_weaves is done after the revision scan so that
117
                # revision index is known to be valid.
118
                self.check_weaves()
6138.4.1 by Jonathan Riddell
add gettext to progress bar strings
119
            self.progress.update(gettext('checking branches and trees'), 3)
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
120
            if callback_refs:
121
                repo = self.repository
122
                # calculate all refs, and callback the objects requesting them.
123
                refs = {}
124
                wanting_items = set()
125
                # Current crude version calculates everything and calls
126
                # everything at once. Doing a queue and popping as things are
127
                # satisfied would be cheaper on memory [but few people have
128
                # huge numbers of working trees today. TODO: fix before
129
                # landing].
130
                distances = set()
131
                existences = set()
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
132
                for ref, wantlist in viewitems(callback_refs):
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
133
                    wanting_items.update(wantlist)
134
                    kind, value = ref
135
                    if kind == 'trees':
136
                        refs[ref] = repo.revision_tree(value)
137
                    elif kind == 'lefthand-distance':
138
                        distances.add(value)
139
                    elif kind == 'revision-existence':
140
                        existences.add(value)
141
                    else:
142
                        raise AssertionError(
143
                            'unknown ref kind for ref %s' % ref)
144
                node_distances = repo.get_graph().find_lefthand_distances(distances)
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
145
                for key, distance in viewitems(node_distances):
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
146
                    refs[('lefthand-distance', key)] = distance
147
                    if key in existences and distance > 0:
148
                        refs[('revision-existence', key)] = True
149
                        existences.remove(key)
150
                parent_map = repo.get_graph().get_parent_map(existences)
151
                for key in parent_map:
152
                    refs[('revision-existence', key)] = True
153
                    existences.remove(key)
154
                for key in existences:
155
                    refs[('revision-existence', key)] = False
156
                for item in wanting_items:
157
                    if isinstance(item, WorkingTree):
158
                        item._check(refs)
159
                    if isinstance(item, Branch):
160
                        self.other_results.append(item.check(refs))
1449 by Robert Collins
teach check about ghosts
161
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
162
    def _check_revisions(self, revisions_iterator):
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
163
        """Check revision objects by decorating a generator.
164
165
        :param revisions_iterator: An iterator of(revid, Revision-or-None).
166
        :return: A generator of the contents of revisions_iterator.
167
        """
168
        self.planned_revisions = set()
169
        for revid, revision in revisions_iterator:
170
            yield revid, revision
171
            self._check_one_rev(revid, revision)
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
172
        # Flatten the revisions we found to guarantee consistent later
173
        # iteration.
4332.3.21 by Robert Collins
Clearer code.
174
        self.planned_revisions = list(self.planned_revisions)
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
175
        # TODO: extract digital signatures as items to callback on too.
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
176
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
177
    def check_revisions(self):
178
        """Scan revisions, checking data directly available as we go."""
6714.1.3 by Jelmer Vernooij
Add Repository.iter_revisions.
179
        revision_iterator = self.repository.iter_revisions(
6714.1.1 by Jelmer Vernooij
Stop accepting revision_ids=None to get_revisions().
180
            self.repository.all_revision_ids())
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
181
        revision_iterator = self._check_revisions(revision_iterator)
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
182
        # We read the all revisions here:
183
        # - doing this allows later code to depend on the revision index.
184
        # - we can fill out existence flags at this point
185
        # - we can read the revision inventory sha at this point
186
        # - we can check properties and serialisers etc.
5766.1.1 by Jelmer Vernooij
Make revision-graph-can-have-wrong-parents a repository format attribute rather than a repository method.
187
        if not self.repository._format.revision_graph_can_have_wrong_parents:
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
188
            # The check against the index isn't needed.
2819.2.3 by Andrew Bennetts
Add test that repo.check will report on wrong parents in the revision graph.
189
            self.revs_with_bad_parents_in_index = None
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
190
            for thing in revision_iterator:
191
                pass
192
        else:
193
            bad_revisions = self.repository._find_inconsistent_revision_parents(
194
                revision_iterator)
195
            self.revs_with_bad_parents_in_index = list(bad_revisions)
2819.2.3 by Andrew Bennetts
Add test that repo.check will report on wrong parents in the revision graph.
196
1449 by Robert Collins
teach check about ghosts
197
    def report_results(self, verbose):
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
198
        if self.check_repo:
199
            self._report_repo_results(verbose)
200
        for result in self.other_results:
201
            result.report_results(verbose)
202
203
    def _report_repo_results(self, verbose):
6138.3.1 by Jonathan Riddell
use gettext() in more files
204
        note(gettext('checked repository {0} format {1}').format(
5158.6.10 by Martin Pool
Update more code to use user_transport when it should
205
            self.repository.user_url,
6138.3.1 by Jonathan Riddell
use gettext() in more files
206
            self.repository._format))
207
        note(gettext('%6d revisions'), self.checked_rev_cnt)
208
        note(gettext('%6d file-ids'), len(self.checked_weaves))
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
209
        if verbose:
6138.3.1 by Jonathan Riddell
use gettext() in more files
210
            note(gettext('%6d unreferenced text versions'),
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
211
                len(self.unreferenced_versions))
212
        if verbose and len(self.unreferenced_versions):
213
                for file_id, revision_id in self.unreferenced_versions:
6138.3.1 by Jonathan Riddell
use gettext() in more files
214
                    note(gettext('unreferenced version: {{{0}}} in {1}').format(revision_id,
215
                        file_id))
1348 by Martin Pool
- more refactoring of check code
216
        if self.missing_inventory_sha_cnt:
6138.3.1 by Jonathan Riddell
use gettext() in more files
217
            note(gettext('%6d revisions are missing inventory_sha1'),
1383 by Martin Pool
- untabify only
218
                 self.missing_inventory_sha_cnt)
1348 by Martin Pool
- more refactoring of check code
219
        if self.missing_revision_cnt:
6138.3.1 by Jonathan Riddell
use gettext() in more files
220
            note(gettext('%6d revisions are mentioned but not present'),
1383 by Martin Pool
- untabify only
221
                 self.missing_revision_cnt)
1449 by Robert Collins
teach check about ghosts
222
        if len(self.ghosts):
6138.3.1 by Jonathan Riddell
use gettext() in more files
223
            note(gettext('%6d ghost revisions'), len(self.ghosts))
1449 by Robert Collins
teach check about ghosts
224
            if verbose:
225
                for ghost in self.ghosts:
226
                    note('      %s', ghost)
227
        if len(self.missing_parent_links):
6138.3.1 by Jonathan Riddell
use gettext() in more files
228
            note(gettext('%6d revisions missing parents in ancestry'),
1449 by Robert Collins
teach check about ghosts
229
                 len(self.missing_parent_links))
230
            if verbose:
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
231
                for link, linkers in viewitems(self.missing_parent_links):
6138.3.1 by Jonathan Riddell
use gettext() in more files
232
                    note(gettext('      %s should be in the ancestry for:'), link)
1449 by Robert Collins
teach check about ghosts
233
                    for linker in linkers:
234
                        note('       * %s', linker)
2745.6.39 by Andrew Bennetts
Use scenario in test_check too, and make check actually report inconsistent parents to the end user.
235
        if len(self.inconsistent_parents):
6138.3.1 by Jonathan Riddell
use gettext() in more files
236
            note(gettext('%6d inconsistent parents'), len(self.inconsistent_parents))
2745.6.39 by Andrew Bennetts
Use scenario in test_check too, and make check actually report inconsistent parents to the end user.
237
            if verbose:
238
                for info in self.inconsistent_parents:
239
                    revision_id, file_id, found_parents, correct_parents = info
6138.3.1 by Jonathan Riddell
use gettext() in more files
240
                    note(gettext('      * {0} version {1} has parents {2!r} '
241
                         'but should have {3!r}').format(
242
                         file_id, revision_id, found_parents,
2745.6.39 by Andrew Bennetts
Use scenario in test_check too, and make check actually report inconsistent parents to the end user.
243
                             correct_parents))
2819.2.3 by Andrew Bennetts
Add test that repo.check will report on wrong parents in the revision graph.
244
        if self.revs_with_bad_parents_in_index:
6138.3.1 by Jonathan Riddell
use gettext() in more files
245
            note(gettext(
246
                 '%6d revisions have incorrect parents in the revision index'),
2819.2.3 by Andrew Bennetts
Add test that repo.check will report on wrong parents in the revision graph.
247
                 len(self.revs_with_bad_parents_in_index))
248
            if verbose:
249
                for item in self.revs_with_bad_parents_in_index:
250
                    revision_id, index_parents, actual_parents = item
6138.3.1 by Jonathan Riddell
use gettext() in more files
251
                    note(gettext(
252
                        '       {0} has wrong parents in index: '
6138.3.5 by Jonathan Riddell
make the test suite pass
253
                        '{1!r} should be {2!r}').format(
254
                        revision_id, index_parents, actual_parents))
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
255
        for item in self._report_items:
256
            note(item)
257
258
    def _check_one_rev(self, rev_id, rev):
259
        """Cross-check one revision.
260
261
        :param rev_id: A revision id to check.
262
        :param rev: A revision or None to indicate a missing revision.
1383 by Martin Pool
- untabify only
263
        """
264
        if rev.revision_id != rev_id:
6138.3.1 by Jonathan Riddell
use gettext() in more files
265
            self._report_items.append(gettext(
266
                'Mismatched internal revid {{{0}}} and index revid {{{1}}}').format(
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
267
                rev.revision_id, rev_id))
268
            rev_id = rev.revision_id
269
        # Check this revision tree etc, and count as seen when we encounter a
270
        # reference to it.
271
        self.planned_revisions.add(rev_id)
272
        # It is not a ghost
273
        self.ghosts.discard(rev_id)
274
        # Count all parents as ghosts if we haven't seen them yet.
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
275
        for parent in rev.parent_ids:
276
            if not parent in self.planned_revisions:
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
277
                self.ghosts.add(parent)
278
        
4332.3.15 by Robert Collins
Keep an ancestors dict in check rather than recreating one multiple times.
279
        self.ancestors[rev_id] = tuple(rev.parent_ids) or (NULL_REVISION,)
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
280
        self.add_pending_item(rev_id, ('inventories', rev_id), 'inventory',
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
281
            rev.inventory_sha1)
1362 by Martin Pool
- keep track of number of checked revisions
282
        self.checked_rev_cnt += 1
1349 by Martin Pool
- more refactoring of check code
283
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
284
    def add_pending_item(self, referer, key, kind, sha1):
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
285
        """Add a reference to a sha1 to be cross checked against a key.
286
287
        :param referer: The referer that expects key to have sha1.
288
        :param key: A storage key e.g. ('texts', 'foo@bar-20040504-1234')
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
289
        :param kind: revision/inventory/text/map/signature
290
        :param sha1: A hex sha1 or None if no sha1 is known.
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
291
        """
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
292
        existing = self.pending_keys.get(key)
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
293
        if existing:
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
294
            if sha1 != existing[1]:
6138.3.1 by Jonathan Riddell
use gettext() in more files
295
                self._report_items.append(gettext('Multiple expected sha1s for {0}. {{{1}}}'
296
                    ' expects {{{2}}}, {{{3}}} expects {{{4}}}').format(
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
297
                    key, referer, sha1, existing[1], existing[0]))
298
        else:
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
299
            self.pending_keys[key] = (kind, sha1, referer)
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
300
1185.50.28 by John Arbash Meinel
Lots of updates for 'bzr check'
301
    def check_weaves(self):
302
        """Check all the weaves we can get our hands on.
303
        """
304
        weave_ids = []
6861.4.1 by Jelmer Vernooij
Make progress bars context managers.
305
        with ui.ui_factory.nested_progress_bar() as storebar:
4332.3.20 by Robert Collins
Cleanup progress reporting for check to go left to right once and only once.
306
            self._check_weaves(storebar)
307
308
    def _check_weaves(self, storebar):
4332.3.28 by Robert Collins
Start checking file texts in a single pass.
309
        storebar.update('text-index', 0, 2)
310
        if self.repository._format.fast_deltas:
311
            # We haven't considered every fileid instance so far.
4332.3.30 by Robert Collins
Fix check_weaves.
312
            weave_checker = self.repository._get_versioned_file_checker(
313
                ancestors=self.ancestors)
4332.3.28 by Robert Collins
Start checking file texts in a single pass.
314
        else:
4332.3.30 by Robert Collins
Fix check_weaves.
315
            weave_checker = self.repository._get_versioned_file_checker(
4332.3.28 by Robert Collins
Start checking file texts in a single pass.
316
                text_key_references=self.text_key_references,
4332.3.30 by Robert Collins
Fix check_weaves.
317
                ancestors=self.ancestors)
318
        storebar.update('file-graph', 1)
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
319
        wrongs, unused_versions = weave_checker.check_file_version_parents(
4332.3.30 by Robert Collins
Fix check_weaves.
320
            self.repository.texts)
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
321
        self.checked_weaves = weave_checker.file_ids
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
322
        for text_key, (stored_parents, correct_parents) in viewitems(wrongs):
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
323
            # XXX not ready for id join/split operations.
324
            weave_id = text_key[0]
325
            revision_id = text_key[-1]
326
            weave_parents = tuple([parent[-1] for parent in stored_parents])
327
            correct_parents = tuple([parent[-1] for parent in correct_parents])
328
            self.inconsistent_parents.append(
329
                (revision_id, weave_id, weave_parents, correct_parents))
330
        self.unreferenced_versions.update(unused_versions)
1185.50.28 by John Arbash Meinel
Lots of updates for 'bzr check'
331
4145.2.1 by Ian Clatworthy
faster check
332
    def _add_entry_to_text_key_references(self, inv, entry):
4332.3.28 by Robert Collins
Start checking file texts in a single pass.
333
        if not self.rich_roots and entry.name == '':
4145.2.1 by Ian Clatworthy
faster check
334
            return
335
        key = (entry.file_id, entry.revision)
336
        self.text_key_references.setdefault(key, False)
337
        if entry.revision == inv.revision_id:
338
            self.text_key_references[key] = True
1349 by Martin Pool
- more refactoring of check code
339
1347 by Martin Pool
- refactor check code into method object
340
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
341
def scan_branch(branch, needed_refs, to_unlock):
342
    """Scan a branch for refs.
343
344
    :param branch:  The branch to schedule for checking.
345
    :param needed_refs: Refs we are accumulating.
346
    :param to_unlock: The unlock list accumulating.
347
    """
6138.3.1 by Jonathan Riddell
use gettext() in more files
348
    note(gettext("Checking branch at '%s'.") % (branch.base,))
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
349
    branch.lock_read()
350
    to_unlock.append(branch)
351
    branch_refs = branch._get_check_refs()
352
    for ref in branch_refs:
353
        reflist = needed_refs.setdefault(ref, [])
354
        reflist.append(branch)
355
356
357
def scan_tree(base_tree, tree, needed_refs, to_unlock):
358
    """Scan a tree for refs.
359
360
    :param base_tree: The original tree check opened, used to detect duplicate
361
        tree checks.
362
    :param tree:  The tree to schedule for checking.
363
    :param needed_refs: Refs we are accumulating.
364
    :param to_unlock: The unlock list accumulating.
365
    """
366
    if base_tree is not None and tree.basedir == base_tree.basedir:
367
        return
6138.3.1 by Jonathan Riddell
use gettext() in more files
368
    note(gettext("Checking working tree at '%s'.") % (tree.basedir,))
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
369
    tree.lock_read()
370
    to_unlock.append(tree)
371
    tree_refs = tree._get_check_refs()
372
    for ref in tree_refs:
373
        reflist = needed_refs.setdefault(ref, [])
374
        reflist.append(tree)
375
376
3015.4.5 by Daniel Watkins
Each option selects only the specific thing to be checked.
377
def check_dwim(path, verbose, do_branch=False, do_repo=False, do_tree=False):
4332.3.35 by Robert Collins
Fix failing tests.
378
    """Check multiple objects.
379
380
    If errors occur they are accumulated and reported as far as possible, and
381
    an exception raised at the end of the process.
382
    """
3015.4.16 by Daniel Watkins
Added implementation of error reporting when objects are missing.
383
    try:
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
384
        base_tree, branch, repo, relpath = \
6207.3.1 by jelmer at samba
use classmethods.
385
                        ControlDir.open_containing_tree_branch_or_repository(path)
3015.4.16 by Daniel Watkins
Added implementation of error reporting when objects are missing.
386
    except errors.NotBranchError:
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
387
        base_tree = branch = repo = None
3015.3.23 by Daniel Watkins
Abstracted discovery of elements away.
388
4332.3.9 by Robert Collins
Less lock thrashing in check.py.
389
    to_unlock = []
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
390
    needed_refs= {}
4332.3.9 by Robert Collins
Less lock thrashing in check.py.
391
    try:
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
392
        if base_tree is not None:
393
            # If the tree is a lightweight checkout we won't see it in
394
            # repo.find_branches - add now.
395
            if do_tree:
396
                scan_tree(None, base_tree, needed_refs, to_unlock)
397
            branch = base_tree.branch
4332.3.9 by Robert Collins
Less lock thrashing in check.py.
398
        if branch is not None:
399
            # We have a branch
400
            if repo is None:
401
                # The branch is in a shared repository
402
                repo = branch.repository
403
        if repo is not None:
404
            repo.lock_read()
405
            to_unlock.append(repo)
406
            branches = repo.find_branches(using=True)
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
407
            saw_tree = False
408
            if do_branch or do_tree:
409
                for branch in branches:
410
                    if do_tree:
411
                        try:
6653.6.1 by Jelmer Vernooij
Rename a number of attributes from bzrdir to controldir.
412
                            tree = branch.controldir.open_workingtree()
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
413
                            saw_tree = True
414
                        except (errors.NotLocalUrl, errors.NoWorkingTree):
415
                            pass
416
                        else:
417
                            scan_tree(base_tree, tree, needed_refs, to_unlock)
418
                    if do_branch:
419
                        scan_branch(branch, needed_refs, to_unlock)
420
            if do_branch and not branches:
6138.3.1 by Jonathan Riddell
use gettext() in more files
421
                note(gettext("No branch found at specified location."))
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
422
            if do_tree and base_tree is None and not saw_tree:
6138.3.1 by Jonathan Riddell
use gettext() in more files
423
                note(gettext("No working tree found at specified location."))
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
424
            if do_repo or do_branch or do_tree:
425
                if do_repo:
6138.3.1 by Jonathan Riddell
use gettext() in more files
426
                    note(gettext("Checking repository at '%s'.")
5158.6.9 by Martin Pool
Simplify various code to use user_url
427
                         % (repo.user_url,))
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
428
                result = repo.check(None, callback_refs=needed_refs,
429
                    check_repo=do_repo)
3015.4.3 by Daniel Watkins
Implemented CLI options.
430
                result.report_results(verbose)
4332.3.9 by Robert Collins
Less lock thrashing in check.py.
431
        else:
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
432
            if do_tree:
6138.3.1 by Jonathan Riddell
use gettext() in more files
433
                note(gettext("No working tree found at specified location."))
4332.3.9 by Robert Collins
Less lock thrashing in check.py.
434
            if do_branch:
6138.3.1 by Jonathan Riddell
use gettext() in more files
435
                note(gettext("No branch found at specified location."))
4332.3.9 by Robert Collins
Less lock thrashing in check.py.
436
            if do_repo:
6138.3.1 by Jonathan Riddell
use gettext() in more files
437
                note(gettext("No repository found at specified location."))
4332.3.9 by Robert Collins
Less lock thrashing in check.py.
438
    finally:
439
        for thing in to_unlock:
440
            thing.unlock()