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