13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
# TODO: Check ancestries are correct for every revision: includes
18
18
# every committed so far, and in a reasonable order.
22
22
# TODO: Check for extra files in the control directory.
24
# TODO: Check revision, inventory and entry objects have all
24
# TODO: Check revision, inventory and entry objects have all
27
27
# TODO: Get every revision in the revision-store even if they're not
63
63
self.checked_weaves = set()
64
64
self.unreferenced_versions = set()
65
65
self.inconsistent_parents = []
66
self.rich_roots = repository.supports_rich_root()
67
self.text_key_references = {}
68
70
self.repository.lock_read()
166
168
rev_id - the one to check
168
170
rev = self.repository.get_revision(rev_id)
170
172
if rev.revision_id != rev_id:
171
173
raise BzrCheckError('wrong internal revision id in revision {%s}'
174
176
for parent in rev.parent_ids:
175
177
if not parent in self.planned_revisions:
178
# rev has a parent we didn't know about.
176
179
missing_links = self.missing_parent_links.get(parent, [])
177
180
missing_links.append(rev_id)
178
181
self.missing_parent_links[parent] = missing_links
181
184
if self.repository.has_revision(parent):
182
185
missing_ancestry = self.repository.get_ancestry(parent)
183
186
for missing in missing_ancestry:
184
if (missing is not None
187
if (missing is not None
185
188
and missing not in self.planned_revisions):
186
189
self.planned_revisions.append(missing)
188
191
self.ghosts.append(rev_id)
190
193
if rev.inventory_sha1:
194
# Loopback - this is currently circular logic as the
195
# knit get_inventory_sha1 call returns rev.inventory_sha1.
196
# Repository.py's get_inventory_sha1 should instead return
197
# inventories.get_record_stream([(revid,)]).next().sha1 or
191
199
inv_sha1 = self.repository.get_inventory_sha1(rev_id)
192
200
if inv_sha1 != rev.inventory_sha1:
193
201
raise BzrCheckError('Inventory sha1 hash doesn\'t match'
203
211
self.inventory_weave.check(progress_bar=self.progress)
204
212
self.progress.update('checking text storage', 1, 2)
205
213
self.repository.texts.check(progress_bar=self.progress)
206
weave_checker = self.repository._get_versioned_file_checker()
214
weave_checker = self.repository._get_versioned_file_checker(
215
text_key_references=self.text_key_references)
207
216
result = weave_checker.check_file_version_parents(
208
217
self.repository.texts, progress_bar=self.progress)
209
218
self.checked_weaves = weave_checker.file_ids
222
231
def _check_revision_tree(self, rev_id):
223
232
tree = self.repository.revision_tree(rev_id)
224
233
inv = tree.inventory
236
for path, ie in inv.iter_entries():
237
self._add_entry_to_text_key_references(inv, ie)
227
239
if file_id in seen_ids:
228
240
raise BzrCheckError('duplicated file_id {%s} '
229
241
'in inventory for revision {%s}'
230
242
% (file_id, rev_id))
231
seen_ids[file_id] = True
243
seen_ids.add(file_id)
234
244
ie.check(self, rev_id, inv, tree)
236
for path, ie in inv.iter_entries():
237
245
if path in seen_names:
238
246
raise BzrCheckError('duplicated path %s '
239
247
'in inventory for revision {%s}'
240
248
% (path, rev_id))
241
seen_names[path] = True
251
def _add_entry_to_text_key_references(self, inv, entry):
252
if not self.rich_roots and entry == inv.root:
254
key = (entry.file_id, entry.revision)
255
self.text_key_references.setdefault(key, False)
256
if entry.revision == inv.revision_id:
257
self.text_key_references[key] = True
244
260
@deprecated_function(deprecated_in((1,6,0)))
245
261
def check(branch, verbose):
246
262
"""Run consistency checks on a branch.
248
264
Results are reported through logging.
250
266
Deprecated in 1.6. Please use check_branch instead.
252
268
:raise BzrCheckError: if there's a consistency error.