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