##// END OF EJS Templates
verify: show progress while verifying dirlogs...
Martin von Zweigbergk -
r28205:53f42c8d default
parent child Browse files
Show More
@@ -1,422 +1,435 b''
1 # verify.py - repository integrity checking for Mercurial
1 # verify.py - repository integrity checking for Mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import os
10 import os
11
11
12 from .i18n import _
12 from .i18n import _
13 from .node import (
13 from .node import (
14 nullid,
14 nullid,
15 short,
15 short,
16 )
16 )
17
17
18 from . import (
18 from . import (
19 error,
19 error,
20 revlog,
20 revlog,
21 util,
21 util,
22 )
22 )
23
23
24 def verify(repo):
24 def verify(repo):
25 with repo.lock():
25 with repo.lock():
26 return verifier(repo).verify()
26 return verifier(repo).verify()
27
27
28 def _normpath(f):
28 def _normpath(f):
29 # under hg < 2.4, convert didn't sanitize paths properly, so a
29 # under hg < 2.4, convert didn't sanitize paths properly, so a
30 # converted repo may contain repeated slashes
30 # converted repo may contain repeated slashes
31 while '//' in f:
31 while '//' in f:
32 f = f.replace('//', '/')
32 f = f.replace('//', '/')
33 return f
33 return f
34
34
35 def _validpath(repo, path):
35 def _validpath(repo, path):
36 """Returns False if a path should NOT be treated as part of a repo.
36 """Returns False if a path should NOT be treated as part of a repo.
37
37
38 For all in-core cases, this returns True, as we have no way for a
38 For all in-core cases, this returns True, as we have no way for a
39 path to be mentioned in the history but not actually be
39 path to be mentioned in the history but not actually be
40 relevant. For narrow clones, this is important because many
40 relevant. For narrow clones, this is important because many
41 filelogs will be missing, and changelog entries may mention
41 filelogs will be missing, and changelog entries may mention
42 modified files that are outside the narrow scope.
42 modified files that are outside the narrow scope.
43 """
43 """
44 return True
44 return True
45
45
46 class verifier(object):
46 class verifier(object):
47 def __init__(self, repo):
47 def __init__(self, repo):
48 self.repo = repo.unfiltered()
48 self.repo = repo.unfiltered()
49 self.ui = repo.ui
49 self.ui = repo.ui
50 self.badrevs = set()
50 self.badrevs = set()
51 self.errors = 0
51 self.errors = 0
52 self.warnings = 0
52 self.warnings = 0
53 self.havecl = len(repo.changelog) > 0
53 self.havecl = len(repo.changelog) > 0
54 self.havemf = len(repo.manifest) > 0
54 self.havemf = len(repo.manifest) > 0
55 self.revlogv1 = repo.changelog.version != revlog.REVLOGV0
55 self.revlogv1 = repo.changelog.version != revlog.REVLOGV0
56 self.lrugetctx = util.lrucachefunc(repo.changectx)
56 self.lrugetctx = util.lrucachefunc(repo.changectx)
57 self.refersmf = False
57 self.refersmf = False
58 self.fncachewarned = False
58 self.fncachewarned = False
59
59
60 def warn(self, msg):
60 def warn(self, msg):
61 self.ui.warn(msg + "\n")
61 self.ui.warn(msg + "\n")
62 self.warnings += 1
62 self.warnings += 1
63
63
64 def err(self, linkrev, msg, filename=None):
64 def err(self, linkrev, msg, filename=None):
65 if linkrev is not None:
65 if linkrev is not None:
66 self.badrevs.add(linkrev)
66 self.badrevs.add(linkrev)
67 else:
67 else:
68 linkrev = '?'
68 linkrev = '?'
69 msg = "%s: %s" % (linkrev, msg)
69 msg = "%s: %s" % (linkrev, msg)
70 if filename:
70 if filename:
71 msg = "%s@%s" % (filename, msg)
71 msg = "%s@%s" % (filename, msg)
72 self.ui.warn(" " + msg + "\n")
72 self.ui.warn(" " + msg + "\n")
73 self.errors += 1
73 self.errors += 1
74
74
75 def exc(self, linkrev, msg, inst, filename=None):
75 def exc(self, linkrev, msg, inst, filename=None):
76 if not str(inst):
76 if not str(inst):
77 inst = repr(inst)
77 inst = repr(inst)
78 self.err(linkrev, "%s: %s" % (msg, inst), filename)
78 self.err(linkrev, "%s: %s" % (msg, inst), filename)
79
79
80 def checklog(self, obj, name, linkrev):
80 def checklog(self, obj, name, linkrev):
81 if not len(obj) and (self.havecl or self.havemf):
81 if not len(obj) and (self.havecl or self.havemf):
82 self.err(linkrev, _("empty or missing %s") % name)
82 self.err(linkrev, _("empty or missing %s") % name)
83 return
83 return
84
84
85 d = obj.checksize()
85 d = obj.checksize()
86 if d[0]:
86 if d[0]:
87 self.err(None, _("data length off by %d bytes") % d[0], name)
87 self.err(None, _("data length off by %d bytes") % d[0], name)
88 if d[1]:
88 if d[1]:
89 self.err(None, _("index contains %d extra bytes") % d[1], name)
89 self.err(None, _("index contains %d extra bytes") % d[1], name)
90
90
91 if obj.version != revlog.REVLOGV0:
91 if obj.version != revlog.REVLOGV0:
92 if not self.revlogv1:
92 if not self.revlogv1:
93 self.warn(_("warning: `%s' uses revlog format 1") % name)
93 self.warn(_("warning: `%s' uses revlog format 1") % name)
94 elif self.revlogv1:
94 elif self.revlogv1:
95 self.warn(_("warning: `%s' uses revlog format 0") % name)
95 self.warn(_("warning: `%s' uses revlog format 0") % name)
96
96
97 def checkentry(self, obj, i, node, seen, linkrevs, f):
97 def checkentry(self, obj, i, node, seen, linkrevs, f):
98 lr = obj.linkrev(obj.rev(node))
98 lr = obj.linkrev(obj.rev(node))
99 if lr < 0 or (self.havecl and lr not in linkrevs):
99 if lr < 0 or (self.havecl and lr not in linkrevs):
100 if lr < 0 or lr >= len(self.repo.changelog):
100 if lr < 0 or lr >= len(self.repo.changelog):
101 msg = _("rev %d points to nonexistent changeset %d")
101 msg = _("rev %d points to nonexistent changeset %d")
102 else:
102 else:
103 msg = _("rev %d points to unexpected changeset %d")
103 msg = _("rev %d points to unexpected changeset %d")
104 self.err(None, msg % (i, lr), f)
104 self.err(None, msg % (i, lr), f)
105 if linkrevs:
105 if linkrevs:
106 if f and len(linkrevs) > 1:
106 if f and len(linkrevs) > 1:
107 try:
107 try:
108 # attempt to filter down to real linkrevs
108 # attempt to filter down to real linkrevs
109 linkrevs = [l for l in linkrevs
109 linkrevs = [l for l in linkrevs
110 if self.lrugetctx(l)[f].filenode() == node]
110 if self.lrugetctx(l)[f].filenode() == node]
111 except Exception:
111 except Exception:
112 pass
112 pass
113 self.warn(_(" (expected %s)") % " ".join(map(str, linkrevs)))
113 self.warn(_(" (expected %s)") % " ".join(map(str, linkrevs)))
114 lr = None # can't be trusted
114 lr = None # can't be trusted
115
115
116 try:
116 try:
117 p1, p2 = obj.parents(node)
117 p1, p2 = obj.parents(node)
118 if p1 not in seen and p1 != nullid:
118 if p1 not in seen and p1 != nullid:
119 self.err(lr, _("unknown parent 1 %s of %s") %
119 self.err(lr, _("unknown parent 1 %s of %s") %
120 (short(p1), short(node)), f)
120 (short(p1), short(node)), f)
121 if p2 not in seen and p2 != nullid:
121 if p2 not in seen and p2 != nullid:
122 self.err(lr, _("unknown parent 2 %s of %s") %
122 self.err(lr, _("unknown parent 2 %s of %s") %
123 (short(p2), short(node)), f)
123 (short(p2), short(node)), f)
124 except Exception as inst:
124 except Exception as inst:
125 self.exc(lr, _("checking parents of %s") % short(node), inst, f)
125 self.exc(lr, _("checking parents of %s") % short(node), inst, f)
126
126
127 if node in seen:
127 if node in seen:
128 self.err(lr, _("duplicate revision %d (%d)") % (i, seen[node]), f)
128 self.err(lr, _("duplicate revision %d (%d)") % (i, seen[node]), f)
129 seen[node] = i
129 seen[node] = i
130 return lr
130 return lr
131
131
132 def verify(self):
132 def verify(self):
133 repo = self.repo
133 repo = self.repo
134
134
135 ui = repo.ui
135 ui = repo.ui
136
136
137 if not repo.url().startswith('file:'):
137 if not repo.url().startswith('file:'):
138 raise error.Abort(_("cannot verify bundle or remote repos"))
138 raise error.Abort(_("cannot verify bundle or remote repos"))
139
139
140 if os.path.exists(repo.sjoin("journal")):
140 if os.path.exists(repo.sjoin("journal")):
141 ui.warn(_("abandoned transaction found - run hg recover\n"))
141 ui.warn(_("abandoned transaction found - run hg recover\n"))
142
142
143 if ui.verbose or not self.revlogv1:
143 if ui.verbose or not self.revlogv1:
144 ui.status(_("repository uses revlog format %d\n") %
144 ui.status(_("repository uses revlog format %d\n") %
145 (self.revlogv1 and 1 or 0))
145 (self.revlogv1 and 1 or 0))
146
146
147 mflinkrevs, filelinkrevs = self._verifychangelog()
147 mflinkrevs, filelinkrevs = self._verifychangelog()
148
148
149 filenodes = self._verifymanifest(mflinkrevs)
149 filenodes = self._verifymanifest(mflinkrevs)
150 del mflinkrevs
150 del mflinkrevs
151
151
152 self._crosscheckfiles(filelinkrevs, filenodes)
152 self._crosscheckfiles(filelinkrevs, filenodes)
153
153
154 totalfiles, filerevisions = self._verifyfiles(filenodes, filelinkrevs)
154 totalfiles, filerevisions = self._verifyfiles(filenodes, filelinkrevs)
155
155
156 ui.status(_("%d files, %d changesets, %d total revisions\n") %
156 ui.status(_("%d files, %d changesets, %d total revisions\n") %
157 (totalfiles, len(repo.changelog), filerevisions))
157 (totalfiles, len(repo.changelog), filerevisions))
158 if self.warnings:
158 if self.warnings:
159 ui.warn(_("%d warnings encountered!\n") % self.warnings)
159 ui.warn(_("%d warnings encountered!\n") % self.warnings)
160 if self.fncachewarned:
160 if self.fncachewarned:
161 ui.warn(_('hint: run "hg debugrebuildfncache" to recover from '
161 ui.warn(_('hint: run "hg debugrebuildfncache" to recover from '
162 'corrupt fncache\n'))
162 'corrupt fncache\n'))
163 if self.errors:
163 if self.errors:
164 ui.warn(_("%d integrity errors encountered!\n") % self.errors)
164 ui.warn(_("%d integrity errors encountered!\n") % self.errors)
165 if self.badrevs:
165 if self.badrevs:
166 ui.warn(_("(first damaged changeset appears to be %d)\n")
166 ui.warn(_("(first damaged changeset appears to be %d)\n")
167 % min(self.badrevs))
167 % min(self.badrevs))
168 return 1
168 return 1
169
169
170 def _verifychangelog(self):
170 def _verifychangelog(self):
171 ui = self.ui
171 ui = self.ui
172 repo = self.repo
172 repo = self.repo
173 cl = repo.changelog
173 cl = repo.changelog
174
174
175 ui.status(_("checking changesets\n"))
175 ui.status(_("checking changesets\n"))
176 mflinkrevs = {}
176 mflinkrevs = {}
177 filelinkrevs = {}
177 filelinkrevs = {}
178 seen = {}
178 seen = {}
179 self.checklog(cl, "changelog", 0)
179 self.checklog(cl, "changelog", 0)
180 total = len(repo)
180 total = len(repo)
181 for i in repo:
181 for i in repo:
182 ui.progress(_('checking'), i, total=total, unit=_('changesets'))
182 ui.progress(_('checking'), i, total=total, unit=_('changesets'))
183 n = cl.node(i)
183 n = cl.node(i)
184 self.checkentry(cl, i, n, seen, [i], "changelog")
184 self.checkentry(cl, i, n, seen, [i], "changelog")
185
185
186 try:
186 try:
187 changes = cl.read(n)
187 changes = cl.read(n)
188 if changes[0] != nullid:
188 if changes[0] != nullid:
189 mflinkrevs.setdefault(changes[0], []).append(i)
189 mflinkrevs.setdefault(changes[0], []).append(i)
190 self.refersmf = True
190 self.refersmf = True
191 for f in changes[3]:
191 for f in changes[3]:
192 if _validpath(repo, f):
192 if _validpath(repo, f):
193 filelinkrevs.setdefault(_normpath(f), []).append(i)
193 filelinkrevs.setdefault(_normpath(f), []).append(i)
194 except Exception as inst:
194 except Exception as inst:
195 self.refersmf = True
195 self.refersmf = True
196 self.exc(i, _("unpacking changeset %s") % short(n), inst)
196 self.exc(i, _("unpacking changeset %s") % short(n), inst)
197 ui.progress(_('checking'), None)
197 ui.progress(_('checking'), None)
198 return mflinkrevs, filelinkrevs
198 return mflinkrevs, filelinkrevs
199
199
200 def _verifymanifest(self, mflinkrevs, dir="", storefiles=None):
200 def _verifymanifest(self, mflinkrevs, dir="", storefiles=None,
201 progress=None):
201 repo = self.repo
202 repo = self.repo
202 ui = self.ui
203 ui = self.ui
203 mf = self.repo.manifest.dirlog(dir)
204 mf = self.repo.manifest.dirlog(dir)
204
205
205 if not dir:
206 if not dir:
206 self.ui.status(_("checking manifests\n"))
207 self.ui.status(_("checking manifests\n"))
207
208
208 filenodes = {}
209 filenodes = {}
209 subdirnodes = {}
210 subdirnodes = {}
210 seen = {}
211 seen = {}
211 label = "manifest"
212 label = "manifest"
212 if dir:
213 if dir:
213 label = dir
214 label = dir
214 revlogfiles = mf.files()
215 revlogfiles = mf.files()
215 storefiles.difference_update(revlogfiles)
216 storefiles.difference_update(revlogfiles)
217 if progress: # should be true since we're in a subdirectory
218 progress()
216 if self.refersmf:
219 if self.refersmf:
217 # Do not check manifest if there are only changelog entries with
220 # Do not check manifest if there are only changelog entries with
218 # null manifests.
221 # null manifests.
219 self.checklog(mf, label, 0)
222 self.checklog(mf, label, 0)
220 total = len(mf)
223 total = len(mf)
221 for i in mf:
224 for i in mf:
222 if not dir:
225 if not dir:
223 ui.progress(_('checking'), i, total=total, unit=_('manifests'))
226 ui.progress(_('checking'), i, total=total, unit=_('manifests'))
224 n = mf.node(i)
227 n = mf.node(i)
225 lr = self.checkentry(mf, i, n, seen, mflinkrevs.get(n, []), label)
228 lr = self.checkentry(mf, i, n, seen, mflinkrevs.get(n, []), label)
226 if n in mflinkrevs:
229 if n in mflinkrevs:
227 del mflinkrevs[n]
230 del mflinkrevs[n]
228 elif dir:
231 elif dir:
229 self.err(lr, _("%s not in parent-directory manifest") %
232 self.err(lr, _("%s not in parent-directory manifest") %
230 short(n), label)
233 short(n), label)
231 else:
234 else:
232 self.err(lr, _("%s not in changesets") % short(n), label)
235 self.err(lr, _("%s not in changesets") % short(n), label)
233
236
234 try:
237 try:
235 for f, fn, fl in mf.readshallowdelta(n).iterentries():
238 for f, fn, fl in mf.readshallowdelta(n).iterentries():
236 if not f:
239 if not f:
237 self.err(lr, _("entry without name in manifest"))
240 self.err(lr, _("entry without name in manifest"))
238 elif f == "/dev/null": # ignore this in very old repos
241 elif f == "/dev/null": # ignore this in very old repos
239 continue
242 continue
240 fullpath = dir + _normpath(f)
243 fullpath = dir + _normpath(f)
241 if not _validpath(repo, fullpath):
244 if not _validpath(repo, fullpath):
242 continue
245 continue
243 if fl == 't':
246 if fl == 't':
244 subdirnodes.setdefault(fullpath + '/', {}).setdefault(
247 subdirnodes.setdefault(fullpath + '/', {}).setdefault(
245 fn, []).append(lr)
248 fn, []).append(lr)
246 else:
249 else:
247 filenodes.setdefault(fullpath, {}).setdefault(fn, lr)
250 filenodes.setdefault(fullpath, {}).setdefault(fn, lr)
248 except Exception as inst:
251 except Exception as inst:
249 self.exc(lr, _("reading delta %s") % short(n), inst, label)
252 self.exc(lr, _("reading delta %s") % short(n), inst, label)
250 if not dir:
253 if not dir:
251 ui.progress(_('checking'), None)
254 ui.progress(_('checking'), None)
252
255
253 if self.havemf:
256 if self.havemf:
254 for c, m in sorted([(c, m) for m in mflinkrevs
257 for c, m in sorted([(c, m) for m in mflinkrevs
255 for c in mflinkrevs[m]]):
258 for c in mflinkrevs[m]]):
256 if dir:
259 if dir:
257 self.err(c, _("parent-directory manifest refers to unknown "
260 self.err(c, _("parent-directory manifest refers to unknown "
258 "revision %s") % short(m), label)
261 "revision %s") % short(m), label)
259 else:
262 else:
260 self.err(c, _("changeset refers to unknown revision %s") %
263 self.err(c, _("changeset refers to unknown revision %s") %
261 short(m), label)
264 short(m), label)
262
265
263 if not dir and subdirnodes:
266 if not dir and subdirnodes:
264 self.ui.status(_("checking directory manifests\n"))
267 self.ui.status(_("checking directory manifests\n"))
265 storefiles = set()
268 storefiles = set()
269 subdirs = set()
266 revlogv1 = self.revlogv1
270 revlogv1 = self.revlogv1
267 for f, f2, size in repo.store.datafiles():
271 for f, f2, size in repo.store.datafiles():
268 if not f:
272 if not f:
269 self.err(None, _("cannot decode filename '%s'") % f2)
273 self.err(None, _("cannot decode filename '%s'") % f2)
270 elif (size > 0 or not revlogv1) and f.startswith('meta/'):
274 elif (size > 0 or not revlogv1) and f.startswith('meta/'):
271 storefiles.add(_normpath(f))
275 storefiles.add(_normpath(f))
276 subdirs.add(os.path.dirname(f))
277 subdircount = len(subdirs)
278 currentsubdir = [0]
279 def progress():
280 currentsubdir[0] += 1
281 ui.progress(_('checking'), currentsubdir[0], total=subdircount,
282 unit=_('manifests'))
272
283
273 for subdir, linkrevs in subdirnodes.iteritems():
284 for subdir, linkrevs in subdirnodes.iteritems():
274 subdirfilenodes = self._verifymanifest(linkrevs, subdir, storefiles)
285 subdirfilenodes = self._verifymanifest(linkrevs, subdir, storefiles,
286 progress)
275 for f, onefilenodes in subdirfilenodes.iteritems():
287 for f, onefilenodes in subdirfilenodes.iteritems():
276 filenodes.setdefault(f, {}).update(onefilenodes)
288 filenodes.setdefault(f, {}).update(onefilenodes)
277
289
278 if not dir and subdirnodes:
290 if not dir and subdirnodes:
291 ui.progress(_('checking'), None)
279 for f in sorted(storefiles):
292 for f in sorted(storefiles):
280 self.warn(_("warning: orphan revlog '%s'") % f)
293 self.warn(_("warning: orphan revlog '%s'") % f)
281
294
282 return filenodes
295 return filenodes
283
296
284 def _crosscheckfiles(self, filelinkrevs, filenodes):
297 def _crosscheckfiles(self, filelinkrevs, filenodes):
285 repo = self.repo
298 repo = self.repo
286 ui = self.ui
299 ui = self.ui
287 ui.status(_("crosschecking files in changesets and manifests\n"))
300 ui.status(_("crosschecking files in changesets and manifests\n"))
288
301
289 total = len(filelinkrevs) + len(filenodes)
302 total = len(filelinkrevs) + len(filenodes)
290 count = 0
303 count = 0
291 if self.havemf:
304 if self.havemf:
292 for f in sorted(filelinkrevs):
305 for f in sorted(filelinkrevs):
293 count += 1
306 count += 1
294 ui.progress(_('crosschecking'), count, total=total)
307 ui.progress(_('crosschecking'), count, total=total)
295 if f not in filenodes:
308 if f not in filenodes:
296 lr = filelinkrevs[f][0]
309 lr = filelinkrevs[f][0]
297 self.err(lr, _("in changeset but not in manifest"), f)
310 self.err(lr, _("in changeset but not in manifest"), f)
298
311
299 if self.havecl:
312 if self.havecl:
300 for f in sorted(filenodes):
313 for f in sorted(filenodes):
301 count += 1
314 count += 1
302 ui.progress(_('crosschecking'), count, total=total)
315 ui.progress(_('crosschecking'), count, total=total)
303 if f not in filelinkrevs:
316 if f not in filelinkrevs:
304 try:
317 try:
305 fl = repo.file(f)
318 fl = repo.file(f)
306 lr = min([fl.linkrev(fl.rev(n)) for n in filenodes[f]])
319 lr = min([fl.linkrev(fl.rev(n)) for n in filenodes[f]])
307 except Exception:
320 except Exception:
308 lr = None
321 lr = None
309 self.err(lr, _("in manifest but not in changeset"), f)
322 self.err(lr, _("in manifest but not in changeset"), f)
310
323
311 ui.progress(_('crosschecking'), None)
324 ui.progress(_('crosschecking'), None)
312
325
313 def _verifyfiles(self, filenodes, filelinkrevs):
326 def _verifyfiles(self, filenodes, filelinkrevs):
314 repo = self.repo
327 repo = self.repo
315 ui = self.ui
328 ui = self.ui
316 lrugetctx = self.lrugetctx
329 lrugetctx = self.lrugetctx
317 revlogv1 = self.revlogv1
330 revlogv1 = self.revlogv1
318 havemf = self.havemf
331 havemf = self.havemf
319 ui.status(_("checking files\n"))
332 ui.status(_("checking files\n"))
320
333
321 storefiles = set()
334 storefiles = set()
322 for f, f2, size in repo.store.datafiles():
335 for f, f2, size in repo.store.datafiles():
323 if not f:
336 if not f:
324 self.err(None, _("cannot decode filename '%s'") % f2)
337 self.err(None, _("cannot decode filename '%s'") % f2)
325 elif (size > 0 or not revlogv1) and f.startswith('data/'):
338 elif (size > 0 or not revlogv1) and f.startswith('data/'):
326 storefiles.add(_normpath(f))
339 storefiles.add(_normpath(f))
327
340
328 files = sorted(set(filenodes) | set(filelinkrevs))
341 files = sorted(set(filenodes) | set(filelinkrevs))
329 total = len(files)
342 total = len(files)
330 revisions = 0
343 revisions = 0
331 for i, f in enumerate(files):
344 for i, f in enumerate(files):
332 ui.progress(_('checking'), i, item=f, total=total)
345 ui.progress(_('checking'), i, item=f, total=total)
333 try:
346 try:
334 linkrevs = filelinkrevs[f]
347 linkrevs = filelinkrevs[f]
335 except KeyError:
348 except KeyError:
336 # in manifest but not in changelog
349 # in manifest but not in changelog
337 linkrevs = []
350 linkrevs = []
338
351
339 if linkrevs:
352 if linkrevs:
340 lr = linkrevs[0]
353 lr = linkrevs[0]
341 else:
354 else:
342 lr = None
355 lr = None
343
356
344 try:
357 try:
345 fl = repo.file(f)
358 fl = repo.file(f)
346 except error.RevlogError as e:
359 except error.RevlogError as e:
347 self.err(lr, _("broken revlog! (%s)") % e, f)
360 self.err(lr, _("broken revlog! (%s)") % e, f)
348 continue
361 continue
349
362
350 for ff in fl.files():
363 for ff in fl.files():
351 try:
364 try:
352 storefiles.remove(ff)
365 storefiles.remove(ff)
353 except KeyError:
366 except KeyError:
354 self.warn(_(" warning: revlog '%s' not in fncache!") % ff)
367 self.warn(_(" warning: revlog '%s' not in fncache!") % ff)
355 self.fncachewarned = True
368 self.fncachewarned = True
356
369
357 self.checklog(fl, f, lr)
370 self.checklog(fl, f, lr)
358 seen = {}
371 seen = {}
359 rp = None
372 rp = None
360 for i in fl:
373 for i in fl:
361 revisions += 1
374 revisions += 1
362 n = fl.node(i)
375 n = fl.node(i)
363 lr = self.checkentry(fl, i, n, seen, linkrevs, f)
376 lr = self.checkentry(fl, i, n, seen, linkrevs, f)
364 if f in filenodes:
377 if f in filenodes:
365 if havemf and n not in filenodes[f]:
378 if havemf and n not in filenodes[f]:
366 self.err(lr, _("%s not in manifests") % (short(n)), f)
379 self.err(lr, _("%s not in manifests") % (short(n)), f)
367 else:
380 else:
368 del filenodes[f][n]
381 del filenodes[f][n]
369
382
370 # verify contents
383 # verify contents
371 try:
384 try:
372 l = len(fl.read(n))
385 l = len(fl.read(n))
373 rp = fl.renamed(n)
386 rp = fl.renamed(n)
374 if l != fl.size(i):
387 if l != fl.size(i):
375 if len(fl.revision(n)) != fl.size(i):
388 if len(fl.revision(n)) != fl.size(i):
376 self.err(lr, _("unpacked size is %s, %s expected") %
389 self.err(lr, _("unpacked size is %s, %s expected") %
377 (l, fl.size(i)), f)
390 (l, fl.size(i)), f)
378 except error.CensoredNodeError:
391 except error.CensoredNodeError:
379 # experimental config: censor.policy
392 # experimental config: censor.policy
380 if ui.config("censor", "policy", "abort") == "abort":
393 if ui.config("censor", "policy", "abort") == "abort":
381 self.err(lr, _("censored file data"), f)
394 self.err(lr, _("censored file data"), f)
382 except Exception as inst:
395 except Exception as inst:
383 self.exc(lr, _("unpacking %s") % short(n), inst, f)
396 self.exc(lr, _("unpacking %s") % short(n), inst, f)
384
397
385 # check renames
398 # check renames
386 try:
399 try:
387 if rp:
400 if rp:
388 if lr is not None and ui.verbose:
401 if lr is not None and ui.verbose:
389 ctx = lrugetctx(lr)
402 ctx = lrugetctx(lr)
390 found = False
403 found = False
391 for pctx in ctx.parents():
404 for pctx in ctx.parents():
392 if rp[0] in pctx:
405 if rp[0] in pctx:
393 found = True
406 found = True
394 break
407 break
395 if not found:
408 if not found:
396 self.warn(_("warning: copy source of '%s' not"
409 self.warn(_("warning: copy source of '%s' not"
397 " in parents of %s") % (f, ctx))
410 " in parents of %s") % (f, ctx))
398 fl2 = repo.file(rp[0])
411 fl2 = repo.file(rp[0])
399 if not len(fl2):
412 if not len(fl2):
400 self.err(lr, _("empty or missing copy source "
413 self.err(lr, _("empty or missing copy source "
401 "revlog %s:%s") % (rp[0], short(rp[1])), f)
414 "revlog %s:%s") % (rp[0], short(rp[1])), f)
402 elif rp[1] == nullid:
415 elif rp[1] == nullid:
403 ui.note(_("warning: %s@%s: copy source"
416 ui.note(_("warning: %s@%s: copy source"
404 " revision is nullid %s:%s\n")
417 " revision is nullid %s:%s\n")
405 % (f, lr, rp[0], short(rp[1])))
418 % (f, lr, rp[0], short(rp[1])))
406 else:
419 else:
407 fl2.rev(rp[1])
420 fl2.rev(rp[1])
408 except Exception as inst:
421 except Exception as inst:
409 self.exc(lr, _("checking rename of %s") % short(n), inst, f)
422 self.exc(lr, _("checking rename of %s") % short(n), inst, f)
410
423
411 # cross-check
424 # cross-check
412 if f in filenodes:
425 if f in filenodes:
413 fns = [(lr, n) for n, lr in filenodes[f].iteritems()]
426 fns = [(lr, n) for n, lr in filenodes[f].iteritems()]
414 for lr, node in sorted(fns):
427 for lr, node in sorted(fns):
415 self.err(lr, _("manifest refers to unknown revision %s") %
428 self.err(lr, _("manifest refers to unknown revision %s") %
416 short(node), f)
429 short(node), f)
417 ui.progress(_('checking'), None)
430 ui.progress(_('checking'), None)
418
431
419 for f in sorted(storefiles):
432 for f in sorted(storefiles):
420 self.warn(_("warning: orphan revlog '%s'") % f)
433 self.warn(_("warning: orphan revlog '%s'") % f)
421
434
422 return len(files), revisions
435 return len(files), revisions
General Comments 0
You need to be logged in to leave comments. Login now