/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 = {}
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
108
        self.repository.lock_read()
5582.10.8 by Jelmer Vernooij
More fixes.
109
        self.progress = ui.ui_factory.nested_progress_bar()
1449 by Robert Collins
teach check about ghosts
110
        try:
6138.4.1 by Jonathan Riddell
add gettext to progress bar strings
111
            self.progress.update(gettext('check'), 0, 4)
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
112
            if self.check_repo:
6138.4.1 by Jonathan Riddell
add gettext to progress bar strings
113
                self.progress.update(gettext('checking revisions'), 0)
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
114
                self.check_revisions()
6138.4.1 by Jonathan Riddell
add gettext to progress bar strings
115
                self.progress.update(gettext('checking commit contents'), 1)
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
116
                self.repository._check_inventories(self)
6138.4.1 by Jonathan Riddell
add gettext to progress bar strings
117
                self.progress.update(gettext('checking file graphs'), 2)
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
118
                # check_weaves is done after the revision scan so that
119
                # revision index is known to be valid.
120
                self.check_weaves()
6138.4.1 by Jonathan Riddell
add gettext to progress bar strings
121
            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.
122
            if callback_refs:
123
                repo = self.repository
124
                # calculate all refs, and callback the objects requesting them.
125
                refs = {}
126
                wanting_items = set()
127
                # Current crude version calculates everything and calls
128
                # everything at once. Doing a queue and popping as things are
129
                # satisfied would be cheaper on memory [but few people have
130
                # huge numbers of working trees today. TODO: fix before
131
                # landing].
132
                distances = set()
133
                existences = set()
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
134
                for ref, wantlist in viewitems(callback_refs):
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
135
                    wanting_items.update(wantlist)
136
                    kind, value = ref
137
                    if kind == 'trees':
138
                        refs[ref] = repo.revision_tree(value)
139
                    elif kind == 'lefthand-distance':
140
                        distances.add(value)
141
                    elif kind == 'revision-existence':
142
                        existences.add(value)
143
                    else:
144
                        raise AssertionError(
145
                            'unknown ref kind for ref %s' % ref)
146
                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
147
                for key, distance in viewitems(node_distances):
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
148
                    refs[('lefthand-distance', key)] = distance
149
                    if key in existences and distance > 0:
150
                        refs[('revision-existence', key)] = True
151
                        existences.remove(key)
152
                parent_map = repo.get_graph().get_parent_map(existences)
153
                for key in parent_map:
154
                    refs[('revision-existence', key)] = True
155
                    existences.remove(key)
156
                for key in existences:
157
                    refs[('revision-existence', key)] = False
158
                for item in wanting_items:
159
                    if isinstance(item, WorkingTree):
160
                        item._check(refs)
161
                    if isinstance(item, Branch):
162
                        self.other_results.append(item.check(refs))
1185.35.34 by Aaron Bentley
Made bzr check for stored revisions missing from ancestry
163
        finally:
1594.1.3 by Robert Collins
Fixup pb usage to use nested_progress_bar.
164
            self.progress.finished()
1732.2.4 by Martin Pool
Split check into Branch.check and Repository.check
165
            self.repository.unlock()
1449 by Robert Collins
teach check about ghosts
166
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
167
    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.
168
        """Check revision objects by decorating a generator.
169
170
        :param revisions_iterator: An iterator of(revid, Revision-or-None).
171
        :return: A generator of the contents of revisions_iterator.
172
        """
173
        self.planned_revisions = set()
174
        for revid, revision in revisions_iterator:
175
            yield revid, revision
176
            self._check_one_rev(revid, revision)
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
177
        # Flatten the revisions we found to guarantee consistent later
178
        # iteration.
4332.3.21 by Robert Collins
Clearer code.
179
        self.planned_revisions = list(self.planned_revisions)
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
180
        # 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.
181
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
182
    def check_revisions(self):
183
        """Scan revisions, checking data directly available as we go."""
4332.3.17 by Robert Collins
Check revisions as we cross check the revision index, rather than in a separate pass.
184
        revision_iterator = self.repository._iter_revisions(None)
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
185
        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.
186
        # We read the all revisions here:
187
        # - doing this allows later code to depend on the revision index.
188
        # - we can fill out existence flags at this point
189
        # - we can read the revision inventory sha at this point
190
        # - 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.
191
        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.
192
            # 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.
193
            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.
194
            for thing in revision_iterator:
195
                pass
196
        else:
197
            bad_revisions = self.repository._find_inconsistent_revision_parents(
198
                revision_iterator)
199
            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.
200
1449 by Robert Collins
teach check about ghosts
201
    def report_results(self, verbose):
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
202
        if self.check_repo:
203
            self._report_repo_results(verbose)
204
        for result in self.other_results:
205
            result.report_results(verbose)
206
207
    def _report_repo_results(self, verbose):
6138.3.1 by Jonathan Riddell
use gettext() in more files
208
        note(gettext('checked repository {0} format {1}').format(
5158.6.10 by Martin Pool
Update more code to use user_transport when it should
209
            self.repository.user_url,
6138.3.1 by Jonathan Riddell
use gettext() in more files
210
            self.repository._format))
211
        note(gettext('%6d revisions'), self.checked_rev_cnt)
212
        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.
213
        if verbose:
6138.3.1 by Jonathan Riddell
use gettext() in more files
214
            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.
215
                len(self.unreferenced_versions))
216
        if verbose and len(self.unreferenced_versions):
217
                for file_id, revision_id in self.unreferenced_versions:
6138.3.1 by Jonathan Riddell
use gettext() in more files
218
                    note(gettext('unreferenced version: {{{0}}} in {1}').format(revision_id,
219
                        file_id))
1348 by Martin Pool
- more refactoring of check code
220
        if self.missing_inventory_sha_cnt:
6138.3.1 by Jonathan Riddell
use gettext() in more files
221
            note(gettext('%6d revisions are missing inventory_sha1'),
1383 by Martin Pool
- untabify only
222
                 self.missing_inventory_sha_cnt)
1348 by Martin Pool
- more refactoring of check code
223
        if self.missing_revision_cnt:
6138.3.1 by Jonathan Riddell
use gettext() in more files
224
            note(gettext('%6d revisions are mentioned but not present'),
1383 by Martin Pool
- untabify only
225
                 self.missing_revision_cnt)
1449 by Robert Collins
teach check about ghosts
226
        if len(self.ghosts):
6138.3.1 by Jonathan Riddell
use gettext() in more files
227
            note(gettext('%6d ghost revisions'), len(self.ghosts))
1449 by Robert Collins
teach check about ghosts
228
            if verbose:
229
                for ghost in self.ghosts:
230
                    note('      %s', ghost)
231
        if len(self.missing_parent_links):
6138.3.1 by Jonathan Riddell
use gettext() in more files
232
            note(gettext('%6d revisions missing parents in ancestry'),
1449 by Robert Collins
teach check about ghosts
233
                 len(self.missing_parent_links))
234
            if verbose:
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
235
                for link, linkers in viewitems(self.missing_parent_links):
6138.3.1 by Jonathan Riddell
use gettext() in more files
236
                    note(gettext('      %s should be in the ancestry for:'), link)
1449 by Robert Collins
teach check about ghosts
237
                    for linker in linkers:
238
                        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.
239
        if len(self.inconsistent_parents):
6138.3.1 by Jonathan Riddell
use gettext() in more files
240
            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.
241
            if verbose:
242
                for info in self.inconsistent_parents:
243
                    revision_id, file_id, found_parents, correct_parents = info
6138.3.1 by Jonathan Riddell
use gettext() in more files
244
                    note(gettext('      * {0} version {1} has parents {2!r} '
245
                         'but should have {3!r}').format(
246
                         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.
247
                             correct_parents))
2819.2.3 by Andrew Bennetts
Add test that repo.check will report on wrong parents in the revision graph.
248
        if self.revs_with_bad_parents_in_index:
6138.3.1 by Jonathan Riddell
use gettext() in more files
249
            note(gettext(
250
                 '%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.
251
                 len(self.revs_with_bad_parents_in_index))
252
            if verbose:
253
                for item in self.revs_with_bad_parents_in_index:
254
                    revision_id, index_parents, actual_parents = item
6138.3.1 by Jonathan Riddell
use gettext() in more files
255
                    note(gettext(
256
                        '       {0} has wrong parents in index: '
6138.3.5 by Jonathan Riddell
make the test suite pass
257
                        '{1!r} should be {2!r}').format(
258
                        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.
259
        for item in self._report_items:
260
            note(item)
261
262
    def _check_one_rev(self, rev_id, rev):
263
        """Cross-check one revision.
264
265
        :param rev_id: A revision id to check.
266
        :param rev: A revision or None to indicate a missing revision.
1383 by Martin Pool
- untabify only
267
        """
268
        if rev.revision_id != rev_id:
6138.3.1 by Jonathan Riddell
use gettext() in more files
269
            self._report_items.append(gettext(
270
                '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.
271
                rev.revision_id, rev_id))
272
            rev_id = rev.revision_id
273
        # Check this revision tree etc, and count as seen when we encounter a
274
        # reference to it.
275
        self.planned_revisions.add(rev_id)
276
        # It is not a ghost
277
        self.ghosts.discard(rev_id)
278
        # 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
279
        for parent in rev.parent_ids:
280
            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.
281
                self.ghosts.add(parent)
282
        
4332.3.15 by Robert Collins
Keep an ancestors dict in check rather than recreating one multiple times.
283
        self.ancestors[rev_id] = tuple(rev.parent_ids) or (NULL_REVISION,)
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
284
        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.
285
            rev.inventory_sha1)
1362 by Martin Pool
- keep track of number of checked revisions
286
        self.checked_rev_cnt += 1
1349 by Martin Pool
- more refactoring of check code
287
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
288
    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.
289
        """Add a reference to a sha1 to be cross checked against a key.
290
291
        :param referer: The referer that expects key to have sha1.
292
        :param key: A storage key e.g. ('texts', 'foo@bar-20040504-1234')
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
293
        :param kind: revision/inventory/text/map/signature
294
        :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.
295
        """
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
296
        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.
297
        if existing:
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
298
            if sha1 != existing[1]:
6138.3.1 by Jonathan Riddell
use gettext() in more files
299
                self._report_items.append(gettext('Multiple expected sha1s for {0}. {{{1}}}'
300
                    ' 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.
301
                    key, referer, sha1, existing[1], existing[0]))
302
        else:
4332.3.25 by Robert Collins
Checkpointing refactoring of inventory/file checks.
303
            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.
304
1185.50.28 by John Arbash Meinel
Lots of updates for 'bzr check'
305
    def check_weaves(self):
306
        """Check all the weaves we can get our hands on.
307
        """
308
        weave_ids = []
5582.10.8 by Jelmer Vernooij
More fixes.
309
        storebar = ui.ui_factory.nested_progress_bar()
4332.3.20 by Robert Collins
Cleanup progress reporting for check to go left to right once and only once.
310
        try:
311
            self._check_weaves(storebar)
312
        finally:
313
            storebar.finished()
314
315
    def _check_weaves(self, storebar):
4332.3.28 by Robert Collins
Start checking file texts in a single pass.
316
        storebar.update('text-index', 0, 2)
317
        if self.repository._format.fast_deltas:
318
            # We haven't considered every fileid instance so far.
4332.3.30 by Robert Collins
Fix check_weaves.
319
            weave_checker = self.repository._get_versioned_file_checker(
320
                ancestors=self.ancestors)
4332.3.28 by Robert Collins
Start checking file texts in a single pass.
321
        else:
4332.3.30 by Robert Collins
Fix check_weaves.
322
            weave_checker = self.repository._get_versioned_file_checker(
4332.3.28 by Robert Collins
Start checking file texts in a single pass.
323
                text_key_references=self.text_key_references,
4332.3.30 by Robert Collins
Fix check_weaves.
324
                ancestors=self.ancestors)
325
        storebar.update('file-graph', 1)
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
326
        wrongs, unused_versions = weave_checker.check_file_version_parents(
4332.3.30 by Robert Collins
Fix check_weaves.
327
            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.
328
        self.checked_weaves = weave_checker.file_ids
6656.1.1 by Martin
Apply 2to3 dict fixer and clean up resulting mess using view helpers
329
        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.
330
            # XXX not ready for id join/split operations.
331
            weave_id = text_key[0]
332
            revision_id = text_key[-1]
333
            weave_parents = tuple([parent[-1] for parent in stored_parents])
334
            correct_parents = tuple([parent[-1] for parent in correct_parents])
335
            self.inconsistent_parents.append(
336
                (revision_id, weave_id, weave_parents, correct_parents))
337
        self.unreferenced_versions.update(unused_versions)
1185.50.28 by John Arbash Meinel
Lots of updates for 'bzr check'
338
4145.2.1 by Ian Clatworthy
faster check
339
    def _add_entry_to_text_key_references(self, inv, entry):
4332.3.28 by Robert Collins
Start checking file texts in a single pass.
340
        if not self.rich_roots and entry.name == '':
4145.2.1 by Ian Clatworthy
faster check
341
            return
342
        key = (entry.file_id, entry.revision)
343
        self.text_key_references.setdefault(key, False)
344
        if entry.revision == inv.revision_id:
345
            self.text_key_references[key] = True
1349 by Martin Pool
- more refactoring of check code
346
1347 by Martin Pool
- refactor check code into method object
347
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
348
def scan_branch(branch, needed_refs, to_unlock):
349
    """Scan a branch for refs.
350
351
    :param branch:  The branch to schedule for checking.
352
    :param needed_refs: Refs we are accumulating.
353
    :param to_unlock: The unlock list accumulating.
354
    """
6138.3.1 by Jonathan Riddell
use gettext() in more files
355
    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.
356
    branch.lock_read()
357
    to_unlock.append(branch)
358
    branch_refs = branch._get_check_refs()
359
    for ref in branch_refs:
360
        reflist = needed_refs.setdefault(ref, [])
361
        reflist.append(branch)
362
363
364
def scan_tree(base_tree, tree, needed_refs, to_unlock):
365
    """Scan a tree for refs.
366
367
    :param base_tree: The original tree check opened, used to detect duplicate
368
        tree checks.
369
    :param tree:  The tree to schedule for checking.
370
    :param needed_refs: Refs we are accumulating.
371
    :param to_unlock: The unlock list accumulating.
372
    """
373
    if base_tree is not None and tree.basedir == base_tree.basedir:
374
        return
6138.3.1 by Jonathan Riddell
use gettext() in more files
375
    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.
376
    tree.lock_read()
377
    to_unlock.append(tree)
378
    tree_refs = tree._get_check_refs()
379
    for ref in tree_refs:
380
        reflist = needed_refs.setdefault(ref, [])
381
        reflist.append(tree)
382
383
3015.4.5 by Daniel Watkins
Each option selects only the specific thing to be checked.
384
def check_dwim(path, verbose, do_branch=False, do_repo=False, do_tree=False):
4332.3.35 by Robert Collins
Fix failing tests.
385
    """Check multiple objects.
386
387
    If errors occur they are accumulated and reported as far as possible, and
388
    an exception raised at the end of the process.
389
    """
3015.4.16 by Daniel Watkins
Added implementation of error reporting when objects are missing.
390
    try:
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
391
        base_tree, branch, repo, relpath = \
6207.3.1 by jelmer at samba
use classmethods.
392
                        ControlDir.open_containing_tree_branch_or_repository(path)
3015.4.16 by Daniel Watkins
Added implementation of error reporting when objects are missing.
393
    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.
394
        base_tree = branch = repo = None
3015.3.23 by Daniel Watkins
Abstracted discovery of elements away.
395
4332.3.9 by Robert Collins
Less lock thrashing in check.py.
396
    to_unlock = []
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
397
    needed_refs= {}
4332.3.9 by Robert Collins
Less lock thrashing in check.py.
398
    try:
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
399
        if base_tree is not None:
400
            # If the tree is a lightweight checkout we won't see it in
401
            # repo.find_branches - add now.
402
            if do_tree:
403
                scan_tree(None, base_tree, needed_refs, to_unlock)
404
            branch = base_tree.branch
4332.3.9 by Robert Collins
Less lock thrashing in check.py.
405
        if branch is not None:
406
            # We have a branch
407
            if repo is None:
408
                # The branch is in a shared repository
409
                repo = branch.repository
410
        if repo is not None:
411
            repo.lock_read()
412
            to_unlock.append(repo)
413
            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.
414
            saw_tree = False
415
            if do_branch or do_tree:
416
                for branch in branches:
417
                    if do_tree:
418
                        try:
419
                            tree = branch.bzrdir.open_workingtree()
420
                            saw_tree = True
421
                        except (errors.NotLocalUrl, errors.NoWorkingTree):
422
                            pass
423
                        else:
424
                            scan_tree(base_tree, tree, needed_refs, to_unlock)
425
                    if do_branch:
426
                        scan_branch(branch, needed_refs, to_unlock)
427
            if do_branch and not branches:
6138.3.1 by Jonathan Riddell
use gettext() in more files
428
                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.
429
            if do_tree and base_tree is None and not saw_tree:
6138.3.1 by Jonathan Riddell
use gettext() in more files
430
                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.
431
            if do_repo or do_branch or do_tree:
432
                if do_repo:
6138.3.1 by Jonathan Riddell
use gettext() in more files
433
                    note(gettext("Checking repository at '%s'.")
5158.6.9 by Martin Pool
Simplify various code to use user_url
434
                         % (repo.user_url,))
4332.3.11 by Robert Collins
Move tree and back callbacks into the repository check core.
435
                result = repo.check(None, callback_refs=needed_refs,
436
                    check_repo=do_repo)
3015.4.3 by Daniel Watkins
Implemented CLI options.
437
                result.report_results(verbose)
4332.3.9 by Robert Collins
Less lock thrashing in check.py.
438
        else:
4332.3.10 by Robert Collins
Invert control of check so that trees and branches are checked by calling back into them.
439
            if do_tree:
6138.3.1 by Jonathan Riddell
use gettext() in more files
440
                note(gettext("No working tree found at specified location."))
4332.3.9 by Robert Collins
Less lock thrashing in check.py.
441
            if do_branch:
6138.3.1 by Jonathan Riddell
use gettext() in more files
442
                note(gettext("No branch found at specified location."))
4332.3.9 by Robert Collins
Less lock thrashing in check.py.
443
            if do_repo:
6138.3.1 by Jonathan Riddell
use gettext() in more files
444
                note(gettext("No repository found at specified location."))
4332.3.9 by Robert Collins
Less lock thrashing in check.py.
445
    finally:
446
        for thing in to_unlock:
447
            thing.unlock()