##// END OF EJS Templates
verify: specify unit for ui.progress when checking files
av6 -
r28467:bd37f0d5 default
parent child Browse files
Show More
@@ -1,435 +1,435
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 progress=None):
202 repo = self.repo
202 repo = self.repo
203 ui = self.ui
203 ui = self.ui
204 mf = self.repo.manifest.dirlog(dir)
204 mf = self.repo.manifest.dirlog(dir)
205
205
206 if not dir:
206 if not dir:
207 self.ui.status(_("checking manifests\n"))
207 self.ui.status(_("checking manifests\n"))
208
208
209 filenodes = {}
209 filenodes = {}
210 subdirnodes = {}
210 subdirnodes = {}
211 seen = {}
211 seen = {}
212 label = "manifest"
212 label = "manifest"
213 if dir:
213 if dir:
214 label = dir
214 label = dir
215 revlogfiles = mf.files()
215 revlogfiles = mf.files()
216 storefiles.difference_update(revlogfiles)
216 storefiles.difference_update(revlogfiles)
217 if progress: # should be true since we're in a subdirectory
217 if progress: # should be true since we're in a subdirectory
218 progress()
218 progress()
219 if self.refersmf:
219 if self.refersmf:
220 # Do not check manifest if there are only changelog entries with
220 # Do not check manifest if there are only changelog entries with
221 # null manifests.
221 # null manifests.
222 self.checklog(mf, label, 0)
222 self.checklog(mf, label, 0)
223 total = len(mf)
223 total = len(mf)
224 for i in mf:
224 for i in mf:
225 if not dir:
225 if not dir:
226 ui.progress(_('checking'), i, total=total, unit=_('manifests'))
226 ui.progress(_('checking'), i, total=total, unit=_('manifests'))
227 n = mf.node(i)
227 n = mf.node(i)
228 lr = self.checkentry(mf, i, n, seen, mflinkrevs.get(n, []), label)
228 lr = self.checkentry(mf, i, n, seen, mflinkrevs.get(n, []), label)
229 if n in mflinkrevs:
229 if n in mflinkrevs:
230 del mflinkrevs[n]
230 del mflinkrevs[n]
231 elif dir:
231 elif dir:
232 self.err(lr, _("%s not in parent-directory manifest") %
232 self.err(lr, _("%s not in parent-directory manifest") %
233 short(n), label)
233 short(n), label)
234 else:
234 else:
235 self.err(lr, _("%s not in changesets") % short(n), label)
235 self.err(lr, _("%s not in changesets") % short(n), label)
236
236
237 try:
237 try:
238 for f, fn, fl in mf.readshallowdelta(n).iterentries():
238 for f, fn, fl in mf.readshallowdelta(n).iterentries():
239 if not f:
239 if not f:
240 self.err(lr, _("entry without name in manifest"))
240 self.err(lr, _("entry without name in manifest"))
241 elif f == "/dev/null": # ignore this in very old repos
241 elif f == "/dev/null": # ignore this in very old repos
242 continue
242 continue
243 fullpath = dir + _normpath(f)
243 fullpath = dir + _normpath(f)
244 if not _validpath(repo, fullpath):
244 if not _validpath(repo, fullpath):
245 continue
245 continue
246 if fl == 't':
246 if fl == 't':
247 subdirnodes.setdefault(fullpath + '/', {}).setdefault(
247 subdirnodes.setdefault(fullpath + '/', {}).setdefault(
248 fn, []).append(lr)
248 fn, []).append(lr)
249 else:
249 else:
250 filenodes.setdefault(fullpath, {}).setdefault(fn, lr)
250 filenodes.setdefault(fullpath, {}).setdefault(fn, lr)
251 except Exception as inst:
251 except Exception as inst:
252 self.exc(lr, _("reading delta %s") % short(n), inst, label)
252 self.exc(lr, _("reading delta %s") % short(n), inst, label)
253 if not dir:
253 if not dir:
254 ui.progress(_('checking'), None)
254 ui.progress(_('checking'), None)
255
255
256 if self.havemf:
256 if self.havemf:
257 for c, m in sorted([(c, m) for m in mflinkrevs
257 for c, m in sorted([(c, m) for m in mflinkrevs
258 for c in mflinkrevs[m]]):
258 for c in mflinkrevs[m]]):
259 if dir:
259 if dir:
260 self.err(c, _("parent-directory manifest refers to unknown "
260 self.err(c, _("parent-directory manifest refers to unknown "
261 "revision %s") % short(m), label)
261 "revision %s") % short(m), label)
262 else:
262 else:
263 self.err(c, _("changeset refers to unknown revision %s") %
263 self.err(c, _("changeset refers to unknown revision %s") %
264 short(m), label)
264 short(m), label)
265
265
266 if not dir and subdirnodes:
266 if not dir and subdirnodes:
267 self.ui.status(_("checking directory manifests\n"))
267 self.ui.status(_("checking directory manifests\n"))
268 storefiles = set()
268 storefiles = set()
269 subdirs = set()
269 subdirs = set()
270 revlogv1 = self.revlogv1
270 revlogv1 = self.revlogv1
271 for f, f2, size in repo.store.datafiles():
271 for f, f2, size in repo.store.datafiles():
272 if not f:
272 if not f:
273 self.err(None, _("cannot decode filename '%s'") % f2)
273 self.err(None, _("cannot decode filename '%s'") % f2)
274 elif (size > 0 or not revlogv1) and f.startswith('meta/'):
274 elif (size > 0 or not revlogv1) and f.startswith('meta/'):
275 storefiles.add(_normpath(f))
275 storefiles.add(_normpath(f))
276 subdirs.add(os.path.dirname(f))
276 subdirs.add(os.path.dirname(f))
277 subdircount = len(subdirs)
277 subdircount = len(subdirs)
278 currentsubdir = [0]
278 currentsubdir = [0]
279 def progress():
279 def progress():
280 currentsubdir[0] += 1
280 currentsubdir[0] += 1
281 ui.progress(_('checking'), currentsubdir[0], total=subdircount,
281 ui.progress(_('checking'), currentsubdir[0], total=subdircount,
282 unit=_('manifests'))
282 unit=_('manifests'))
283
283
284 for subdir, linkrevs in subdirnodes.iteritems():
284 for subdir, linkrevs in subdirnodes.iteritems():
285 subdirfilenodes = self._verifymanifest(linkrevs, subdir, storefiles,
285 subdirfilenodes = self._verifymanifest(linkrevs, subdir, storefiles,
286 progress)
286 progress)
287 for f, onefilenodes in subdirfilenodes.iteritems():
287 for f, onefilenodes in subdirfilenodes.iteritems():
288 filenodes.setdefault(f, {}).update(onefilenodes)
288 filenodes.setdefault(f, {}).update(onefilenodes)
289
289
290 if not dir and subdirnodes:
290 if not dir and subdirnodes:
291 ui.progress(_('checking'), None)
291 ui.progress(_('checking'), None)
292 for f in sorted(storefiles):
292 for f in sorted(storefiles):
293 self.warn(_("warning: orphan revlog '%s'") % f)
293 self.warn(_("warning: orphan revlog '%s'") % f)
294
294
295 return filenodes
295 return filenodes
296
296
297 def _crosscheckfiles(self, filelinkrevs, filenodes):
297 def _crosscheckfiles(self, filelinkrevs, filenodes):
298 repo = self.repo
298 repo = self.repo
299 ui = self.ui
299 ui = self.ui
300 ui.status(_("crosschecking files in changesets and manifests\n"))
300 ui.status(_("crosschecking files in changesets and manifests\n"))
301
301
302 total = len(filelinkrevs) + len(filenodes)
302 total = len(filelinkrevs) + len(filenodes)
303 count = 0
303 count = 0
304 if self.havemf:
304 if self.havemf:
305 for f in sorted(filelinkrevs):
305 for f in sorted(filelinkrevs):
306 count += 1
306 count += 1
307 ui.progress(_('crosschecking'), count, total=total)
307 ui.progress(_('crosschecking'), count, total=total)
308 if f not in filenodes:
308 if f not in filenodes:
309 lr = filelinkrevs[f][0]
309 lr = filelinkrevs[f][0]
310 self.err(lr, _("in changeset but not in manifest"), f)
310 self.err(lr, _("in changeset but not in manifest"), f)
311
311
312 if self.havecl:
312 if self.havecl:
313 for f in sorted(filenodes):
313 for f in sorted(filenodes):
314 count += 1
314 count += 1
315 ui.progress(_('crosschecking'), count, total=total)
315 ui.progress(_('crosschecking'), count, total=total)
316 if f not in filelinkrevs:
316 if f not in filelinkrevs:
317 try:
317 try:
318 fl = repo.file(f)
318 fl = repo.file(f)
319 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]])
320 except Exception:
320 except Exception:
321 lr = None
321 lr = None
322 self.err(lr, _("in manifest but not in changeset"), f)
322 self.err(lr, _("in manifest but not in changeset"), f)
323
323
324 ui.progress(_('crosschecking'), None)
324 ui.progress(_('crosschecking'), None)
325
325
326 def _verifyfiles(self, filenodes, filelinkrevs):
326 def _verifyfiles(self, filenodes, filelinkrevs):
327 repo = self.repo
327 repo = self.repo
328 ui = self.ui
328 ui = self.ui
329 lrugetctx = self.lrugetctx
329 lrugetctx = self.lrugetctx
330 revlogv1 = self.revlogv1
330 revlogv1 = self.revlogv1
331 havemf = self.havemf
331 havemf = self.havemf
332 ui.status(_("checking files\n"))
332 ui.status(_("checking files\n"))
333
333
334 storefiles = set()
334 storefiles = set()
335 for f, f2, size in repo.store.datafiles():
335 for f, f2, size in repo.store.datafiles():
336 if not f:
336 if not f:
337 self.err(None, _("cannot decode filename '%s'") % f2)
337 self.err(None, _("cannot decode filename '%s'") % f2)
338 elif (size > 0 or not revlogv1) and f.startswith('data/'):
338 elif (size > 0 or not revlogv1) and f.startswith('data/'):
339 storefiles.add(_normpath(f))
339 storefiles.add(_normpath(f))
340
340
341 files = sorted(set(filenodes) | set(filelinkrevs))
341 files = sorted(set(filenodes) | set(filelinkrevs))
342 total = len(files)
342 total = len(files)
343 revisions = 0
343 revisions = 0
344 for i, f in enumerate(files):
344 for i, f in enumerate(files):
345 ui.progress(_('checking'), i, item=f, total=total)
345 ui.progress(_('checking'), i, item=f, total=total, unit=_('files'))
346 try:
346 try:
347 linkrevs = filelinkrevs[f]
347 linkrevs = filelinkrevs[f]
348 except KeyError:
348 except KeyError:
349 # in manifest but not in changelog
349 # in manifest but not in changelog
350 linkrevs = []
350 linkrevs = []
351
351
352 if linkrevs:
352 if linkrevs:
353 lr = linkrevs[0]
353 lr = linkrevs[0]
354 else:
354 else:
355 lr = None
355 lr = None
356
356
357 try:
357 try:
358 fl = repo.file(f)
358 fl = repo.file(f)
359 except error.RevlogError as e:
359 except error.RevlogError as e:
360 self.err(lr, _("broken revlog! (%s)") % e, f)
360 self.err(lr, _("broken revlog! (%s)") % e, f)
361 continue
361 continue
362
362
363 for ff in fl.files():
363 for ff in fl.files():
364 try:
364 try:
365 storefiles.remove(ff)
365 storefiles.remove(ff)
366 except KeyError:
366 except KeyError:
367 self.warn(_(" warning: revlog '%s' not in fncache!") % ff)
367 self.warn(_(" warning: revlog '%s' not in fncache!") % ff)
368 self.fncachewarned = True
368 self.fncachewarned = True
369
369
370 self.checklog(fl, f, lr)
370 self.checklog(fl, f, lr)
371 seen = {}
371 seen = {}
372 rp = None
372 rp = None
373 for i in fl:
373 for i in fl:
374 revisions += 1
374 revisions += 1
375 n = fl.node(i)
375 n = fl.node(i)
376 lr = self.checkentry(fl, i, n, seen, linkrevs, f)
376 lr = self.checkentry(fl, i, n, seen, linkrevs, f)
377 if f in filenodes:
377 if f in filenodes:
378 if havemf and n not in filenodes[f]:
378 if havemf and n not in filenodes[f]:
379 self.err(lr, _("%s not in manifests") % (short(n)), f)
379 self.err(lr, _("%s not in manifests") % (short(n)), f)
380 else:
380 else:
381 del filenodes[f][n]
381 del filenodes[f][n]
382
382
383 # verify contents
383 # verify contents
384 try:
384 try:
385 l = len(fl.read(n))
385 l = len(fl.read(n))
386 rp = fl.renamed(n)
386 rp = fl.renamed(n)
387 if l != fl.size(i):
387 if l != fl.size(i):
388 if len(fl.revision(n)) != fl.size(i):
388 if len(fl.revision(n)) != fl.size(i):
389 self.err(lr, _("unpacked size is %s, %s expected") %
389 self.err(lr, _("unpacked size is %s, %s expected") %
390 (l, fl.size(i)), f)
390 (l, fl.size(i)), f)
391 except error.CensoredNodeError:
391 except error.CensoredNodeError:
392 # experimental config: censor.policy
392 # experimental config: censor.policy
393 if ui.config("censor", "policy", "abort") == "abort":
393 if ui.config("censor", "policy", "abort") == "abort":
394 self.err(lr, _("censored file data"), f)
394 self.err(lr, _("censored file data"), f)
395 except Exception as inst:
395 except Exception as inst:
396 self.exc(lr, _("unpacking %s") % short(n), inst, f)
396 self.exc(lr, _("unpacking %s") % short(n), inst, f)
397
397
398 # check renames
398 # check renames
399 try:
399 try:
400 if rp:
400 if rp:
401 if lr is not None and ui.verbose:
401 if lr is not None and ui.verbose:
402 ctx = lrugetctx(lr)
402 ctx = lrugetctx(lr)
403 found = False
403 found = False
404 for pctx in ctx.parents():
404 for pctx in ctx.parents():
405 if rp[0] in pctx:
405 if rp[0] in pctx:
406 found = True
406 found = True
407 break
407 break
408 if not found:
408 if not found:
409 self.warn(_("warning: copy source of '%s' not"
409 self.warn(_("warning: copy source of '%s' not"
410 " in parents of %s") % (f, ctx))
410 " in parents of %s") % (f, ctx))
411 fl2 = repo.file(rp[0])
411 fl2 = repo.file(rp[0])
412 if not len(fl2):
412 if not len(fl2):
413 self.err(lr, _("empty or missing copy source "
413 self.err(lr, _("empty or missing copy source "
414 "revlog %s:%s") % (rp[0], short(rp[1])), f)
414 "revlog %s:%s") % (rp[0], short(rp[1])), f)
415 elif rp[1] == nullid:
415 elif rp[1] == nullid:
416 ui.note(_("warning: %s@%s: copy source"
416 ui.note(_("warning: %s@%s: copy source"
417 " revision is nullid %s:%s\n")
417 " revision is nullid %s:%s\n")
418 % (f, lr, rp[0], short(rp[1])))
418 % (f, lr, rp[0], short(rp[1])))
419 else:
419 else:
420 fl2.rev(rp[1])
420 fl2.rev(rp[1])
421 except Exception as inst:
421 except Exception as inst:
422 self.exc(lr, _("checking rename of %s") % short(n), inst, f)
422 self.exc(lr, _("checking rename of %s") % short(n), inst, f)
423
423
424 # cross-check
424 # cross-check
425 if f in filenodes:
425 if f in filenodes:
426 fns = [(lr, n) for n, lr in filenodes[f].iteritems()]
426 fns = [(lr, n) for n, lr in filenodes[f].iteritems()]
427 for lr, node in sorted(fns):
427 for lr, node in sorted(fns):
428 self.err(lr, _("manifest refers to unknown revision %s") %
428 self.err(lr, _("manifest refers to unknown revision %s") %
429 short(node), f)
429 short(node), f)
430 ui.progress(_('checking'), None)
430 ui.progress(_('checking'), None)
431
431
432 for f in sorted(storefiles):
432 for f in sorted(storefiles):
433 self.warn(_("warning: orphan revlog '%s'") % f)
433 self.warn(_("warning: orphan revlog '%s'") % f)
434
434
435 return len(files), revisions
435 return len(files), revisions
General Comments 0
You need to be logged in to leave comments. Login now