25
25
# TODO: Check revision, inventory and entry objects have all
28
# TODO: Get every revision in the revision-store even if they're not
29
# referenced by history and make sure they're all valid.
30
32
from bzrlib.trace import note, warning
32
34
from bzrlib.trace import mutter
33
35
from bzrlib.errors import BzrCheckError, NoSuchRevision
34
36
from bzrlib.inventory import ROOT_ID
35
from bzrlib.branch import gen_root_id
38
39
class Check(object):
49
50
self.missing_revision_cnt = 0
50
51
# maps (file-id, version) -> sha1
51
52
self.checked_texts = {}
53
self.checked_weaves = {}
54
56
self.branch.lock_read()
57
self.progress = bzrlib.ui.ui_factory.progress_bar()
59
self.progress.update('retrieving inventory', 0, 0)
60
# do not put in init, as it should be done with progess,
61
# and inside the lock.
62
self.inventory_weave = self.branch._get_inventory_weave()
56
63
self.history = self.branch.revision_history()
57
64
if not len(self.history):
58
65
# nothing to see here
60
self.planned_revisions = self.branch.get_ancestry(self.history[-1])
61
self.planned_revisions.remove(None)
64
self.progress = bzrlib.ui.ui_factory.progress_bar()
65
70
while revno < len(self.planned_revisions):
66
71
rev_id = self.planned_revisions[revno]
67
72
self.progress.update('checking revision', revno,
68
73
len(self.planned_revisions))
70
75
self.check_one_rev(rev_id)
73
78
self.branch.unlock()
80
def plan_revisions(self):
81
if not self.branch.revision_store.listable():
82
self.planned_revisions = self.branch.get_ancestry(self.history[-1])
83
self.planned_revisions.remove(None)
84
# FIXME progress bars should support this more nicely.
86
print ("Checking reachable history -"
87
" for a complete check use a local branch.")
90
self.planned_revisions = set(self.branch.revision_store)
91
inventoried = set(self.inventory_weave.names())
92
awol = self.planned_revisions - inventoried
94
raise BzrCheckError('Stored revisions missing from inventory'
95
'{%s}' % ','.join([f for f in awol]))
96
self.planned_revisions = list(self.planned_revisions)
75
98
def report_results(self, verbose):
76
99
note('checked branch %s format %d',
80
103
note('%6d revisions', self.checked_rev_cnt)
81
104
note('%6d unique file texts', self.checked_text_cnt)
82
105
note('%6d repeated file texts', self.repeated_text_cnt)
106
note('%6d weaves', len(self.checked_weaves))
83
107
if self.missing_inventory_sha_cnt:
84
108
note('%6d revisions are missing inventory_sha1',
85
109
self.missing_inventory_sha_cnt)
108
132
last_rev_id - the previous one on the mainline, if any.
111
# mutter(' revision {%s}' % rev_id)
135
# mutter(' revision {%s}', rev_id)
112
136
branch = self.branch
114
138
rev_history_position = self.history.index(rev_id)
129
153
# check the previous history entry is a parent of this entry
130
154
if rev.parent_ids:
131
if last_rev_id is None and rev_history_position is not None:
132
# what if the start is a ghost ? i.e. conceptually the
134
raise BzrCheckError("revision {%s} has %d parents, but is the "
135
"start of the branch"
136
% (rev_id, len(rev.parent_ids)))
137
155
if last_rev_id is not None:
138
156
for parent_id in rev.parent_ids:
139
157
if parent_id == last_rev_id:
147
165
missing_links = self.missing_parent_links.get(parent, [])
148
166
missing_links.append(rev_id)
149
167
self.missing_parent_links[parent] = missing_links
150
# list based so slow, TODO have a planned_revisions list and set.
168
# list based so somewhat slow,
169
# TODO have a planned_revisions list and set.
151
170
if self.branch.has_revision(parent):
152
171
missing_ancestry = self.branch.get_ancestry(parent)
153
172
for missing in missing_ancestry:
168
187
' value in revision {%s}' % rev_id)
170
189
missing_inventory_sha_cnt += 1
171
mutter("no inventory_sha1 on revision {%s}" % rev_id)
190
mutter("no inventory_sha1 on revision {%s}", rev_id)
172
191
self._check_revision_tree(rev_id)
173
192
self.checked_rev_cnt += 1
194
def check_weaves(self):
195
"""Check all the weaves we can get our hands on.
199
if self.branch.weave_store.listable():
200
weave_ids = list(self.branch.weave_store)
201
n_weaves = len(weave_ids)
202
self.progress.update('checking weave', 0, n_weaves)
203
self.inventory_weave.check(progress_bar=self.progress)
204
for i, weave_id in enumerate(weave_ids):
205
self.progress.update('checking weave', i, n_weaves)
206
w = self.branch.weave_store.get_weave(weave_id,
207
self.branch.get_transaction())
208
# No progress here, because it looks ugly.
210
self.checked_weaves[weave_id] = True
175
212
def _check_revision_tree(self, rev_id):
176
213
tree = self.branch.revision_tree(rev_id)
177
214
inv = tree.inventory