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