##// END OF EJS Templates
verify: make the `warn` method private...
marmoute -
r42028:c66037fb default
parent child Browse files
Show More
@@ -1,455 +1,455 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 pycompat,
20 pycompat,
21 revlog,
21 revlog,
22 util,
22 util,
23 )
23 )
24
24
25 def verify(repo):
25 def verify(repo):
26 with repo.lock():
26 with repo.lock():
27 return verifier(repo).verify()
27 return verifier(repo).verify()
28
28
29 def _normpath(f):
29 def _normpath(f):
30 # under hg < 2.4, convert didn't sanitize paths properly, so a
30 # under hg < 2.4, convert didn't sanitize paths properly, so a
31 # converted repo may contain repeated slashes
31 # converted repo may contain repeated slashes
32 while '//' in f:
32 while '//' in f:
33 f = f.replace('//', '/')
33 f = f.replace('//', '/')
34 return f
34 return f
35
35
36 class verifier(object):
36 class verifier(object):
37 def __init__(self, repo):
37 def __init__(self, repo):
38 self.repo = repo.unfiltered()
38 self.repo = repo.unfiltered()
39 self.ui = repo.ui
39 self.ui = repo.ui
40 self.match = repo.narrowmatch()
40 self.match = repo.narrowmatch()
41 self.badrevs = set()
41 self.badrevs = set()
42 self.errors = 0
42 self.errors = 0
43 self.warnings = 0
43 self.warnings = 0
44 self.havecl = len(repo.changelog) > 0
44 self.havecl = len(repo.changelog) > 0
45 self.havemf = len(repo.manifestlog.getstorage(b'')) > 0
45 self.havemf = len(repo.manifestlog.getstorage(b'')) > 0
46 self.revlogv1 = repo.changelog.version != revlog.REVLOGV0
46 self.revlogv1 = repo.changelog.version != revlog.REVLOGV0
47 self.lrugetctx = util.lrucachefunc(repo.__getitem__)
47 self.lrugetctx = util.lrucachefunc(repo.__getitem__)
48 self.refersmf = False
48 self.refersmf = False
49 self.fncachewarned = False
49 self.fncachewarned = False
50 # developer config: verify.skipflags
50 # developer config: verify.skipflags
51 self.skipflags = repo.ui.configint('verify', 'skipflags')
51 self.skipflags = repo.ui.configint('verify', 'skipflags')
52 self.warnorphanstorefiles = True
52 self.warnorphanstorefiles = True
53
53
54 def warn(self, msg):
54 def _warn(self, msg):
55 """record a "warning" level issue"""
55 """record a "warning" level issue"""
56 self.ui.warn(msg + "\n")
56 self.ui.warn(msg + "\n")
57 self.warnings += 1
57 self.warnings += 1
58
58
59 def err(self, linkrev, msg, filename=None):
59 def err(self, linkrev, msg, filename=None):
60 if linkrev is not None:
60 if linkrev is not None:
61 self.badrevs.add(linkrev)
61 self.badrevs.add(linkrev)
62 linkrev = "%d" % linkrev
62 linkrev = "%d" % linkrev
63 else:
63 else:
64 linkrev = '?'
64 linkrev = '?'
65 msg = "%s: %s" % (linkrev, msg)
65 msg = "%s: %s" % (linkrev, msg)
66 if filename:
66 if filename:
67 msg = "%s@%s" % (filename, msg)
67 msg = "%s@%s" % (filename, msg)
68 self.ui.warn(" " + msg + "\n")
68 self.ui.warn(" " + msg + "\n")
69 self.errors += 1
69 self.errors += 1
70
70
71 def exc(self, linkrev, msg, inst, filename=None):
71 def exc(self, linkrev, msg, inst, filename=None):
72 fmsg = pycompat.bytestr(inst)
72 fmsg = pycompat.bytestr(inst)
73 if not fmsg:
73 if not fmsg:
74 fmsg = pycompat.byterepr(inst)
74 fmsg = pycompat.byterepr(inst)
75 self.err(linkrev, "%s: %s" % (msg, fmsg), filename)
75 self.err(linkrev, "%s: %s" % (msg, fmsg), filename)
76
76
77 def checklog(self, obj, name, linkrev):
77 def checklog(self, obj, name, linkrev):
78 if not len(obj) and (self.havecl or self.havemf):
78 if not len(obj) and (self.havecl or self.havemf):
79 self.err(linkrev, _("empty or missing %s") % name)
79 self.err(linkrev, _("empty or missing %s") % name)
80 return
80 return
81
81
82 d = obj.checksize()
82 d = obj.checksize()
83 if d[0]:
83 if d[0]:
84 self.err(None, _("data length off by %d bytes") % d[0], name)
84 self.err(None, _("data length off by %d bytes") % d[0], name)
85 if d[1]:
85 if d[1]:
86 self.err(None, _("index contains %d extra bytes") % d[1], name)
86 self.err(None, _("index contains %d extra bytes") % d[1], name)
87
87
88 if obj.version != revlog.REVLOGV0:
88 if obj.version != revlog.REVLOGV0:
89 if not self.revlogv1:
89 if not self.revlogv1:
90 self.warn(_("warning: `%s' uses revlog format 1") % name)
90 self._warn(_("warning: `%s' uses revlog format 1") % name)
91 elif self.revlogv1:
91 elif self.revlogv1:
92 self.warn(_("warning: `%s' uses revlog format 0") % name)
92 self._warn(_("warning: `%s' uses revlog format 0") % name)
93
93
94 def checkentry(self, obj, i, node, seen, linkrevs, f):
94 def checkentry(self, obj, i, node, seen, linkrevs, f):
95 lr = obj.linkrev(obj.rev(node))
95 lr = obj.linkrev(obj.rev(node))
96 if lr < 0 or (self.havecl and lr not in linkrevs):
96 if lr < 0 or (self.havecl and lr not in linkrevs):
97 if lr < 0 or lr >= len(self.repo.changelog):
97 if lr < 0 or lr >= len(self.repo.changelog):
98 msg = _("rev %d points to nonexistent changeset %d")
98 msg = _("rev %d points to nonexistent changeset %d")
99 else:
99 else:
100 msg = _("rev %d points to unexpected changeset %d")
100 msg = _("rev %d points to unexpected changeset %d")
101 self.err(None, msg % (i, lr), f)
101 self.err(None, msg % (i, lr), f)
102 if linkrevs:
102 if linkrevs:
103 if f and len(linkrevs) > 1:
103 if f and len(linkrevs) > 1:
104 try:
104 try:
105 # attempt to filter down to real linkrevs
105 # attempt to filter down to real linkrevs
106 linkrevs = [l for l in linkrevs
106 linkrevs = [l for l in linkrevs
107 if self.lrugetctx(l)[f].filenode() == node]
107 if self.lrugetctx(l)[f].filenode() == node]
108 except Exception:
108 except Exception:
109 pass
109 pass
110 self.warn(_(" (expected %s)") % " ".join
110 self._warn(_(" (expected %s)") % " ".join
111 (map(pycompat.bytestr, linkrevs)))
111 (map(pycompat.bytestr, linkrevs)))
112 lr = None # can't be trusted
112 lr = None # can't be trusted
113
113
114 try:
114 try:
115 p1, p2 = obj.parents(node)
115 p1, p2 = obj.parents(node)
116 if p1 not in seen and p1 != nullid:
116 if p1 not in seen and p1 != nullid:
117 self.err(lr, _("unknown parent 1 %s of %s") %
117 self.err(lr, _("unknown parent 1 %s of %s") %
118 (short(p1), short(node)), f)
118 (short(p1), short(node)), f)
119 if p2 not in seen and p2 != nullid:
119 if p2 not in seen and p2 != nullid:
120 self.err(lr, _("unknown parent 2 %s of %s") %
120 self.err(lr, _("unknown parent 2 %s of %s") %
121 (short(p2), short(node)), f)
121 (short(p2), short(node)), f)
122 except Exception as inst:
122 except Exception as inst:
123 self.exc(lr, _("checking parents of %s") % short(node), inst, f)
123 self.exc(lr, _("checking parents of %s") % short(node), inst, f)
124
124
125 if node in seen:
125 if node in seen:
126 self.err(lr, _("duplicate revision %d (%d)") % (i, seen[node]), f)
126 self.err(lr, _("duplicate revision %d (%d)") % (i, seen[node]), f)
127 seen[node] = i
127 seen[node] = i
128 return lr
128 return lr
129
129
130 def verify(self):
130 def verify(self):
131 repo = self.repo
131 repo = self.repo
132
132
133 ui = repo.ui
133 ui = repo.ui
134
134
135 if not repo.url().startswith('file:'):
135 if not repo.url().startswith('file:'):
136 raise error.Abort(_("cannot verify bundle or remote repos"))
136 raise error.Abort(_("cannot verify bundle or remote repos"))
137
137
138 if os.path.exists(repo.sjoin("journal")):
138 if os.path.exists(repo.sjoin("journal")):
139 ui.warn(_("abandoned transaction found - run hg recover\n"))
139 ui.warn(_("abandoned transaction found - run hg recover\n"))
140
140
141 if ui.verbose or not self.revlogv1:
141 if ui.verbose or not self.revlogv1:
142 ui.status(_("repository uses revlog format %d\n") %
142 ui.status(_("repository uses revlog format %d\n") %
143 (self.revlogv1 and 1 or 0))
143 (self.revlogv1 and 1 or 0))
144
144
145 mflinkrevs, filelinkrevs = self._verifychangelog()
145 mflinkrevs, filelinkrevs = self._verifychangelog()
146
146
147 filenodes = self._verifymanifest(mflinkrevs)
147 filenodes = self._verifymanifest(mflinkrevs)
148 del mflinkrevs
148 del mflinkrevs
149
149
150 self._crosscheckfiles(filelinkrevs, filenodes)
150 self._crosscheckfiles(filelinkrevs, filenodes)
151
151
152 totalfiles, filerevisions = self._verifyfiles(filenodes, filelinkrevs)
152 totalfiles, filerevisions = self._verifyfiles(filenodes, filelinkrevs)
153
153
154 ui.status(_("checked %d changesets with %d changes to %d files\n") %
154 ui.status(_("checked %d changesets with %d changes to %d files\n") %
155 (len(repo.changelog), filerevisions, totalfiles))
155 (len(repo.changelog), filerevisions, totalfiles))
156 if self.warnings:
156 if self.warnings:
157 ui.warn(_("%d warnings encountered!\n") % self.warnings)
157 ui.warn(_("%d warnings encountered!\n") % self.warnings)
158 if self.fncachewarned:
158 if self.fncachewarned:
159 ui.warn(_('hint: run "hg debugrebuildfncache" to recover from '
159 ui.warn(_('hint: run "hg debugrebuildfncache" to recover from '
160 'corrupt fncache\n'))
160 'corrupt fncache\n'))
161 if self.errors:
161 if self.errors:
162 ui.warn(_("%d integrity errors encountered!\n") % self.errors)
162 ui.warn(_("%d integrity errors encountered!\n") % self.errors)
163 if self.badrevs:
163 if self.badrevs:
164 ui.warn(_("(first damaged changeset appears to be %d)\n")
164 ui.warn(_("(first damaged changeset appears to be %d)\n")
165 % min(self.badrevs))
165 % min(self.badrevs))
166 return 1
166 return 1
167
167
168 def _verifychangelog(self):
168 def _verifychangelog(self):
169 ui = self.ui
169 ui = self.ui
170 repo = self.repo
170 repo = self.repo
171 match = self.match
171 match = self.match
172 cl = repo.changelog
172 cl = repo.changelog
173
173
174 ui.status(_("checking changesets\n"))
174 ui.status(_("checking changesets\n"))
175 mflinkrevs = {}
175 mflinkrevs = {}
176 filelinkrevs = {}
176 filelinkrevs = {}
177 seen = {}
177 seen = {}
178 self.checklog(cl, "changelog", 0)
178 self.checklog(cl, "changelog", 0)
179 progress = ui.makeprogress(_('checking'), unit=_('changesets'),
179 progress = ui.makeprogress(_('checking'), unit=_('changesets'),
180 total=len(repo))
180 total=len(repo))
181 for i in repo:
181 for i in repo:
182 progress.update(i)
182 progress.update(i)
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 match(f):
192 if match(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 progress.complete()
197 progress.complete()
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 subdirprogress=None):
201 subdirprogress=None):
202 repo = self.repo
202 repo = self.repo
203 ui = self.ui
203 ui = self.ui
204 match = self.match
204 match = self.match
205 mfl = self.repo.manifestlog
205 mfl = self.repo.manifestlog
206 mf = mfl.getstorage(dir)
206 mf = mfl.getstorage(dir)
207
207
208 if not dir:
208 if not dir:
209 self.ui.status(_("checking manifests\n"))
209 self.ui.status(_("checking manifests\n"))
210
210
211 filenodes = {}
211 filenodes = {}
212 subdirnodes = {}
212 subdirnodes = {}
213 seen = {}
213 seen = {}
214 label = "manifest"
214 label = "manifest"
215 if dir:
215 if dir:
216 label = dir
216 label = dir
217 revlogfiles = mf.files()
217 revlogfiles = mf.files()
218 storefiles.difference_update(revlogfiles)
218 storefiles.difference_update(revlogfiles)
219 if subdirprogress: # should be true since we're in a subdirectory
219 if subdirprogress: # should be true since we're in a subdirectory
220 subdirprogress.increment()
220 subdirprogress.increment()
221 if self.refersmf:
221 if self.refersmf:
222 # Do not check manifest if there are only changelog entries with
222 # Do not check manifest if there are only changelog entries with
223 # null manifests.
223 # null manifests.
224 self.checklog(mf, label, 0)
224 self.checklog(mf, label, 0)
225 progress = ui.makeprogress(_('checking'), unit=_('manifests'),
225 progress = ui.makeprogress(_('checking'), unit=_('manifests'),
226 total=len(mf))
226 total=len(mf))
227 for i in mf:
227 for i in mf:
228 if not dir:
228 if not dir:
229 progress.update(i)
229 progress.update(i)
230 n = mf.node(i)
230 n = mf.node(i)
231 lr = self.checkentry(mf, i, n, seen, mflinkrevs.get(n, []), label)
231 lr = self.checkentry(mf, i, n, seen, mflinkrevs.get(n, []), label)
232 if n in mflinkrevs:
232 if n in mflinkrevs:
233 del mflinkrevs[n]
233 del mflinkrevs[n]
234 elif dir:
234 elif dir:
235 self.err(lr, _("%s not in parent-directory manifest") %
235 self.err(lr, _("%s not in parent-directory manifest") %
236 short(n), label)
236 short(n), label)
237 else:
237 else:
238 self.err(lr, _("%s not in changesets") % short(n), label)
238 self.err(lr, _("%s not in changesets") % short(n), label)
239
239
240 try:
240 try:
241 mfdelta = mfl.get(dir, n).readdelta(shallow=True)
241 mfdelta = mfl.get(dir, n).readdelta(shallow=True)
242 for f, fn, fl in mfdelta.iterentries():
242 for f, fn, fl in mfdelta.iterentries():
243 if not f:
243 if not f:
244 self.err(lr, _("entry without name in manifest"))
244 self.err(lr, _("entry without name in manifest"))
245 elif f == "/dev/null": # ignore this in very old repos
245 elif f == "/dev/null": # ignore this in very old repos
246 continue
246 continue
247 fullpath = dir + _normpath(f)
247 fullpath = dir + _normpath(f)
248 if fl == 't':
248 if fl == 't':
249 if not match.visitdir(fullpath):
249 if not match.visitdir(fullpath):
250 continue
250 continue
251 subdirnodes.setdefault(fullpath + '/', {}).setdefault(
251 subdirnodes.setdefault(fullpath + '/', {}).setdefault(
252 fn, []).append(lr)
252 fn, []).append(lr)
253 else:
253 else:
254 if not match(fullpath):
254 if not match(fullpath):
255 continue
255 continue
256 filenodes.setdefault(fullpath, {}).setdefault(fn, lr)
256 filenodes.setdefault(fullpath, {}).setdefault(fn, lr)
257 except Exception as inst:
257 except Exception as inst:
258 self.exc(lr, _("reading delta %s") % short(n), inst, label)
258 self.exc(lr, _("reading delta %s") % short(n), inst, label)
259 if not dir:
259 if not dir:
260 progress.complete()
260 progress.complete()
261
261
262 if self.havemf:
262 if self.havemf:
263 for c, m in sorted([(c, m) for m in mflinkrevs
263 for c, m in sorted([(c, m) for m in mflinkrevs
264 for c in mflinkrevs[m]]):
264 for c in mflinkrevs[m]]):
265 if dir:
265 if dir:
266 self.err(c, _("parent-directory manifest refers to unknown "
266 self.err(c, _("parent-directory manifest refers to unknown "
267 "revision %s") % short(m), label)
267 "revision %s") % short(m), label)
268 else:
268 else:
269 self.err(c, _("changeset refers to unknown revision %s") %
269 self.err(c, _("changeset refers to unknown revision %s") %
270 short(m), label)
270 short(m), label)
271
271
272 if not dir and subdirnodes:
272 if not dir and subdirnodes:
273 self.ui.status(_("checking directory manifests\n"))
273 self.ui.status(_("checking directory manifests\n"))
274 storefiles = set()
274 storefiles = set()
275 subdirs = set()
275 subdirs = set()
276 revlogv1 = self.revlogv1
276 revlogv1 = self.revlogv1
277 for f, f2, size in repo.store.datafiles():
277 for f, f2, size in repo.store.datafiles():
278 if not f:
278 if not f:
279 self.err(None, _("cannot decode filename '%s'") % f2)
279 self.err(None, _("cannot decode filename '%s'") % f2)
280 elif (size > 0 or not revlogv1) and f.startswith('meta/'):
280 elif (size > 0 or not revlogv1) and f.startswith('meta/'):
281 storefiles.add(_normpath(f))
281 storefiles.add(_normpath(f))
282 subdirs.add(os.path.dirname(f))
282 subdirs.add(os.path.dirname(f))
283 subdirprogress = ui.makeprogress(_('checking'), unit=_('manifests'),
283 subdirprogress = ui.makeprogress(_('checking'), unit=_('manifests'),
284 total=len(subdirs))
284 total=len(subdirs))
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 subdirprogress)
288 subdirprogress)
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 subdirprogress.complete()
293 subdirprogress.complete()
294 if self.warnorphanstorefiles:
294 if self.warnorphanstorefiles:
295 for f in sorted(storefiles):
295 for f in sorted(storefiles):
296 self.warn(_("warning: orphan data file '%s'") % f)
296 self._warn(_("warning: orphan data file '%s'") % f)
297
297
298 return filenodes
298 return filenodes
299
299
300 def _crosscheckfiles(self, filelinkrevs, filenodes):
300 def _crosscheckfiles(self, filelinkrevs, filenodes):
301 repo = self.repo
301 repo = self.repo
302 ui = self.ui
302 ui = self.ui
303 ui.status(_("crosschecking files in changesets and manifests\n"))
303 ui.status(_("crosschecking files in changesets and manifests\n"))
304
304
305 total = len(filelinkrevs) + len(filenodes)
305 total = len(filelinkrevs) + len(filenodes)
306 progress = ui.makeprogress(_('crosschecking'), unit=_('files'),
306 progress = ui.makeprogress(_('crosschecking'), unit=_('files'),
307 total=total)
307 total=total)
308 if self.havemf:
308 if self.havemf:
309 for f in sorted(filelinkrevs):
309 for f in sorted(filelinkrevs):
310 progress.increment()
310 progress.increment()
311 if f not in filenodes:
311 if f not in filenodes:
312 lr = filelinkrevs[f][0]
312 lr = filelinkrevs[f][0]
313 self.err(lr, _("in changeset but not in manifest"), f)
313 self.err(lr, _("in changeset but not in manifest"), f)
314
314
315 if self.havecl:
315 if self.havecl:
316 for f in sorted(filenodes):
316 for f in sorted(filenodes):
317 progress.increment()
317 progress.increment()
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 progress.complete()
326 progress.complete()
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 state = {
343 state = {
344 # TODO this assumes revlog storage for changelog.
344 # TODO this assumes revlog storage for changelog.
345 'expectedversion': self.repo.changelog.version & 0xFFFF,
345 'expectedversion': self.repo.changelog.version & 0xFFFF,
346 'skipflags': self.skipflags,
346 'skipflags': self.skipflags,
347 # experimental config: censor.policy
347 # experimental config: censor.policy
348 'erroroncensored': ui.config('censor', 'policy') == 'abort',
348 'erroroncensored': ui.config('censor', 'policy') == 'abort',
349 }
349 }
350
350
351 files = sorted(set(filenodes) | set(filelinkrevs))
351 files = sorted(set(filenodes) | set(filelinkrevs))
352 revisions = 0
352 revisions = 0
353 progress = ui.makeprogress(_('checking'), unit=_('files'),
353 progress = ui.makeprogress(_('checking'), unit=_('files'),
354 total=len(files))
354 total=len(files))
355 for i, f in enumerate(files):
355 for i, f in enumerate(files):
356 progress.update(i, item=f)
356 progress.update(i, item=f)
357 try:
357 try:
358 linkrevs = filelinkrevs[f]
358 linkrevs = filelinkrevs[f]
359 except KeyError:
359 except KeyError:
360 # in manifest but not in changelog
360 # in manifest but not in changelog
361 linkrevs = []
361 linkrevs = []
362
362
363 if linkrevs:
363 if linkrevs:
364 lr = linkrevs[0]
364 lr = linkrevs[0]
365 else:
365 else:
366 lr = None
366 lr = None
367
367
368 try:
368 try:
369 fl = repo.file(f)
369 fl = repo.file(f)
370 except error.StorageError as e:
370 except error.StorageError as e:
371 self.err(lr, _("broken revlog! (%s)") % e, f)
371 self.err(lr, _("broken revlog! (%s)") % e, f)
372 continue
372 continue
373
373
374 for ff in fl.files():
374 for ff in fl.files():
375 try:
375 try:
376 storefiles.remove(ff)
376 storefiles.remove(ff)
377 except KeyError:
377 except KeyError:
378 if self.warnorphanstorefiles:
378 if self.warnorphanstorefiles:
379 self.warn(_(" warning: revlog '%s' not in fncache!") %
379 self._warn(_(" warning: revlog '%s' not in fncache!") %
380 ff)
380 ff)
381 self.fncachewarned = True
381 self.fncachewarned = True
382
382
383 if not len(fl) and (self.havecl or self.havemf):
383 if not len(fl) and (self.havecl or self.havemf):
384 self.err(lr, _("empty or missing %s") % f)
384 self.err(lr, _("empty or missing %s") % f)
385 else:
385 else:
386 # Guard against implementations not setting this.
386 # Guard against implementations not setting this.
387 state['skipread'] = set()
387 state['skipread'] = set()
388 for problem in fl.verifyintegrity(state):
388 for problem in fl.verifyintegrity(state):
389 if problem.node is not None:
389 if problem.node is not None:
390 linkrev = fl.linkrev(fl.rev(problem.node))
390 linkrev = fl.linkrev(fl.rev(problem.node))
391 else:
391 else:
392 linkrev = None
392 linkrev = None
393
393
394 if problem.warning:
394 if problem.warning:
395 self.warn(problem.warning)
395 self._warn(problem.warning)
396 elif problem.error:
396 elif problem.error:
397 self.err(linkrev if linkrev is not None else lr,
397 self.err(linkrev if linkrev is not None else lr,
398 problem.error, f)
398 problem.error, f)
399 else:
399 else:
400 raise error.ProgrammingError(
400 raise error.ProgrammingError(
401 'problem instance does not set warning or error '
401 'problem instance does not set warning or error '
402 'attribute: %s' % problem.msg)
402 'attribute: %s' % problem.msg)
403
403
404 seen = {}
404 seen = {}
405 for i in fl:
405 for i in fl:
406 revisions += 1
406 revisions += 1
407 n = fl.node(i)
407 n = fl.node(i)
408 lr = self.checkentry(fl, i, n, seen, linkrevs, f)
408 lr = self.checkentry(fl, i, n, seen, linkrevs, f)
409 if f in filenodes:
409 if f in filenodes:
410 if havemf and n not in filenodes[f]:
410 if havemf and n not in filenodes[f]:
411 self.err(lr, _("%s not in manifests") % (short(n)), f)
411 self.err(lr, _("%s not in manifests") % (short(n)), f)
412 else:
412 else:
413 del filenodes[f][n]
413 del filenodes[f][n]
414
414
415 if n in state['skipread']:
415 if n in state['skipread']:
416 continue
416 continue
417
417
418 # check renames
418 # check renames
419 try:
419 try:
420 # This requires resolving fulltext (at least on revlogs). We
420 # This requires resolving fulltext (at least on revlogs). We
421 # may want ``verifyintegrity()`` to pass a set of nodes with
421 # may want ``verifyintegrity()`` to pass a set of nodes with
422 # rename metadata as an optimization.
422 # rename metadata as an optimization.
423 rp = fl.renamed(n)
423 rp = fl.renamed(n)
424 if rp:
424 if rp:
425 if lr is not None and ui.verbose:
425 if lr is not None and ui.verbose:
426 ctx = lrugetctx(lr)
426 ctx = lrugetctx(lr)
427 if not any(rp[0] in pctx for pctx in ctx.parents()):
427 if not any(rp[0] in pctx for pctx in ctx.parents()):
428 self.warn(_("warning: copy source of '%s' not"
428 self._warn(_("warning: copy source of '%s' not"
429 " in parents of %s") % (f, ctx))
429 " in parents of %s") % (f, ctx))
430 fl2 = repo.file(rp[0])
430 fl2 = repo.file(rp[0])
431 if not len(fl2):
431 if not len(fl2):
432 self.err(lr, _("empty or missing copy source "
432 self.err(lr, _("empty or missing copy source "
433 "revlog %s:%s") % (rp[0], short(rp[1])), f)
433 "revlog %s:%s") % (rp[0], short(rp[1])), f)
434 elif rp[1] == nullid:
434 elif rp[1] == nullid:
435 ui.note(_("warning: %s@%s: copy source"
435 ui.note(_("warning: %s@%s: copy source"
436 " revision is nullid %s:%s\n")
436 " revision is nullid %s:%s\n")
437 % (f, lr, rp[0], short(rp[1])))
437 % (f, lr, rp[0], short(rp[1])))
438 else:
438 else:
439 fl2.rev(rp[1])
439 fl2.rev(rp[1])
440 except Exception as inst:
440 except Exception as inst:
441 self.exc(lr, _("checking rename of %s") % short(n), inst, f)
441 self.exc(lr, _("checking rename of %s") % short(n), inst, f)
442
442
443 # cross-check
443 # cross-check
444 if f in filenodes:
444 if f in filenodes:
445 fns = [(v, k) for k, v in filenodes[f].iteritems()]
445 fns = [(v, k) for k, v in filenodes[f].iteritems()]
446 for lr, node in sorted(fns):
446 for lr, node in sorted(fns):
447 self.err(lr, _("manifest refers to unknown revision %s") %
447 self.err(lr, _("manifest refers to unknown revision %s") %
448 short(node), f)
448 short(node), f)
449 progress.complete()
449 progress.complete()
450
450
451 if self.warnorphanstorefiles:
451 if self.warnorphanstorefiles:
452 for f in sorted(storefiles):
452 for f in sorted(storefiles):
453 self.warn(_("warning: orphan data file '%s'") % f)
453 self._warn(_("warning: orphan data file '%s'") % f)
454
454
455 return len(files), revisions
455 return len(files), revisions
General Comments 0
You need to be logged in to leave comments. Login now