comparison mercurial/verify.py @ 27447:d1b91c10ce70

verify: move err() to be a class function This is part of an effort to make it easier for extensions to hook into verify.
author Durham Goode <durham@fb.com>
date Fri, 18 Dec 2015 16:42:39 -0800
parents 6b2c1a1871a6
children f4f2179077cb
comparison
equal deleted inserted replaced
27446:6b2c1a1871a6 27447:d1b91c10ce70
62 62
63 def warn(self, msg): 63 def warn(self, msg):
64 self.ui.warn(msg + "\n") 64 self.ui.warn(msg + "\n")
65 self.warnings[0] += 1 65 self.warnings[0] += 1
66 66
67 def err(self, linkrev, msg, filename=None):
68 if linkrev is not None:
69 self.badrevs.add(linkrev)
70 else:
71 linkrev = '?'
72 msg = "%s: %s" % (linkrev, msg)
73 if filename:
74 msg = "%s@%s" % (filename, msg)
75 self.ui.warn(" " + msg + "\n")
76 self.errors[0] += 1
77
67 def verify(self): 78 def verify(self):
68 repo = self.repo 79 repo = self.repo
69 mflinkrevs = {} 80 mflinkrevs = {}
70 filelinkrevs = {} 81 filelinkrevs = {}
71 filenodes = {} 82 filenodes = {}
79 lrugetctx = self.lrugetctx 90 lrugetctx = self.lrugetctx
80 91
81 if not repo.url().startswith('file:'): 92 if not repo.url().startswith('file:'):
82 raise error.Abort(_("cannot verify bundle or remote repos")) 93 raise error.Abort(_("cannot verify bundle or remote repos"))
83 94
84 def err(linkrev, msg, filename=None):
85 if linkrev is not None:
86 badrevs.add(linkrev)
87 else:
88 linkrev = '?'
89 msg = "%s: %s" % (linkrev, msg)
90 if filename:
91 msg = "%s@%s" % (filename, msg)
92 ui.warn(" " + msg + "\n")
93 errors[0] += 1
94 95
95 def exc(linkrev, msg, inst, filename=None): 96 def exc(linkrev, msg, inst, filename=None):
96 if isinstance(inst, KeyboardInterrupt): 97 if isinstance(inst, KeyboardInterrupt):
97 ui.warn(_("interrupted")) 98 ui.warn(_("interrupted"))
98 raise 99 raise
99 if not str(inst): 100 if not str(inst):
100 inst = repr(inst) 101 inst = repr(inst)
101 err(linkrev, "%s: %s" % (msg, inst), filename) 102 self.err(linkrev, "%s: %s" % (msg, inst), filename)
102 103
103 104
104 def checklog(obj, name, linkrev): 105 def checklog(obj, name, linkrev):
105 if not len(obj) and (havecl or havemf): 106 if not len(obj) and (havecl or havemf):
106 err(linkrev, _("empty or missing %s") % name) 107 self.err(linkrev, _("empty or missing %s") % name)
107 return 108 return
108 109
109 d = obj.checksize() 110 d = obj.checksize()
110 if d[0]: 111 if d[0]:
111 err(None, _("data length off by %d bytes") % d[0], name) 112 self.err(None, _("data length off by %d bytes") % d[0], name)
112 if d[1]: 113 if d[1]:
113 err(None, _("index contains %d extra bytes") % d[1], name) 114 self.err(None, _("index contains %d extra bytes") % d[1], name)
114 115
115 if obj.version != revlog.REVLOGV0: 116 if obj.version != revlog.REVLOGV0:
116 if not revlogv1: 117 if not revlogv1:
117 self.warn(_("warning: `%s' uses revlog format 1") % name) 118 self.warn(_("warning: `%s' uses revlog format 1") % name)
118 elif revlogv1: 119 elif revlogv1:
123 if lr < 0 or (havecl and lr not in linkrevs): 124 if lr < 0 or (havecl and lr not in linkrevs):
124 if lr < 0 or lr >= len(cl): 125 if lr < 0 or lr >= len(cl):
125 msg = _("rev %d points to nonexistent changeset %d") 126 msg = _("rev %d points to nonexistent changeset %d")
126 else: 127 else:
127 msg = _("rev %d points to unexpected changeset %d") 128 msg = _("rev %d points to unexpected changeset %d")
128 err(None, msg % (i, lr), f) 129 self.err(None, msg % (i, lr), f)
129 if linkrevs: 130 if linkrevs:
130 if f and len(linkrevs) > 1: 131 if f and len(linkrevs) > 1:
131 try: 132 try:
132 # attempt to filter down to real linkrevs 133 # attempt to filter down to real linkrevs
133 linkrevs = [l for l in linkrevs 134 linkrevs = [l for l in linkrevs
139 lr = None # can't be trusted 140 lr = None # can't be trusted
140 141
141 try: 142 try:
142 p1, p2 = obj.parents(node) 143 p1, p2 = obj.parents(node)
143 if p1 not in seen and p1 != nullid: 144 if p1 not in seen and p1 != nullid:
144 err(lr, _("unknown parent 1 %s of %s") % 145 self.err(lr, _("unknown parent 1 %s of %s") %
145 (short(p1), short(node)), f) 146 (short(p1), short(node)), f)
146 if p2 not in seen and p2 != nullid: 147 if p2 not in seen and p2 != nullid:
147 err(lr, _("unknown parent 2 %s of %s") % 148 self.err(lr, _("unknown parent 2 %s of %s") %
148 (short(p2), short(node)), f) 149 (short(p2), short(node)), f)
149 except Exception as inst: 150 except Exception as inst:
150 exc(lr, _("checking parents of %s") % short(node), inst, f) 151 exc(lr, _("checking parents of %s") % short(node), inst, f)
151 152
152 if node in seen: 153 if node in seen:
153 err(lr, _("duplicate revision %d (%d)") % (i, seen[node]), f) 154 self.err(lr, _("duplicate revision %d (%d)") %
155 (i, seen[node]), f)
154 seen[node] = i 156 seen[node] = i
155 return lr 157 return lr
156 158
157 if os.path.exists(repo.sjoin("journal")): 159 if os.path.exists(repo.sjoin("journal")):
158 ui.warn(_("abandoned transaction found - run hg recover\n")) 160 ui.warn(_("abandoned transaction found - run hg recover\n"))
199 n = mf.node(i) 201 n = mf.node(i)
200 lr = checkentry(mf, i, n, seen, mflinkrevs.get(n, []), "manifest") 202 lr = checkentry(mf, i, n, seen, mflinkrevs.get(n, []), "manifest")
201 if n in mflinkrevs: 203 if n in mflinkrevs:
202 del mflinkrevs[n] 204 del mflinkrevs[n]
203 else: 205 else:
204 err(lr, _("%s not in changesets") % short(n), "manifest") 206 self.err(lr, _("%s not in changesets") % short(n), "manifest")
205 207
206 try: 208 try:
207 for f, fn in mf.readdelta(n).iteritems(): 209 for f, fn in mf.readdelta(n).iteritems():
208 if not f: 210 if not f:
209 err(lr, _("file without name in manifest")) 211 self.err(lr, _("file without name in manifest"))
210 elif f != "/dev/null": # ignore this in very old repos 212 elif f != "/dev/null": # ignore this in very old repos
211 if _validpath(repo, f): 213 if _validpath(repo, f):
212 filenodes.setdefault( 214 filenodes.setdefault(
213 _normpath(f), {}).setdefault(fn, lr) 215 _normpath(f), {}).setdefault(fn, lr)
214 except Exception as inst: 216 except Exception as inst:
224 for c in mflinkrevs[m]]): 226 for c in mflinkrevs[m]]):
225 count += 1 227 count += 1
226 if m == nullid: 228 if m == nullid:
227 continue 229 continue
228 ui.progress(_('crosschecking'), count, total=total) 230 ui.progress(_('crosschecking'), count, total=total)
229 err(c, _("changeset refers to unknown manifest %s") % short(m)) 231 self.err(c, _("changeset refers to unknown manifest %s") %
232 short(m))
230 mflinkrevs = None # del is bad here due to scope issues 233 mflinkrevs = None # del is bad here due to scope issues
231 234
232 for f in sorted(filelinkrevs): 235 for f in sorted(filelinkrevs):
233 count += 1 236 count += 1
234 ui.progress(_('crosschecking'), count, total=total) 237 ui.progress(_('crosschecking'), count, total=total)
235 if f not in filenodes: 238 if f not in filenodes:
236 lr = filelinkrevs[f][0] 239 lr = filelinkrevs[f][0]
237 err(lr, _("in changeset but not in manifest"), f) 240 self.err(lr, _("in changeset but not in manifest"), f)
238 241
239 if havecl: 242 if havecl:
240 for f in sorted(filenodes): 243 for f in sorted(filenodes):
241 count += 1 244 count += 1
242 ui.progress(_('crosschecking'), count, total=total) 245 ui.progress(_('crosschecking'), count, total=total)
244 try: 247 try:
245 fl = repo.file(f) 248 fl = repo.file(f)
246 lr = min([fl.linkrev(fl.rev(n)) for n in filenodes[f]]) 249 lr = min([fl.linkrev(fl.rev(n)) for n in filenodes[f]])
247 except Exception: 250 except Exception:
248 lr = None 251 lr = None
249 err(lr, _("in manifest but not in changeset"), f) 252 self.err(lr, _("in manifest but not in changeset"), f)
250 253
251 ui.progress(_('crosschecking'), None) 254 ui.progress(_('crosschecking'), None)
252 255
253 ui.status(_("checking files\n")) 256 ui.status(_("checking files\n"))
254 257
255 storefiles = set() 258 storefiles = set()
256 for f, f2, size in repo.store.datafiles(): 259 for f, f2, size in repo.store.datafiles():
257 if not f: 260 if not f:
258 err(None, _("cannot decode filename '%s'") % f2) 261 self.err(None, _("cannot decode filename '%s'") % f2)
259 elif size > 0 or not revlogv1: 262 elif size > 0 or not revlogv1:
260 storefiles.add(_normpath(f)) 263 storefiles.add(_normpath(f))
261 264
262 files = sorted(set(filenodes) | set(filelinkrevs)) 265 files = sorted(set(filenodes) | set(filelinkrevs))
263 total = len(files) 266 total = len(files)
275 lr = None 278 lr = None
276 279
277 try: 280 try:
278 fl = repo.file(f) 281 fl = repo.file(f)
279 except error.RevlogError as e: 282 except error.RevlogError as e:
280 err(lr, _("broken revlog! (%s)") % e, f) 283 self.err(lr, _("broken revlog! (%s)") % e, f)
281 continue 284 continue
282 285
283 for ff in fl.files(): 286 for ff in fl.files():
284 try: 287 try:
285 storefiles.remove(ff) 288 storefiles.remove(ff)
294 revisions += 1 297 revisions += 1
295 n = fl.node(i) 298 n = fl.node(i)
296 lr = checkentry(fl, i, n, seen, linkrevs, f) 299 lr = checkentry(fl, i, n, seen, linkrevs, f)
297 if f in filenodes: 300 if f in filenodes:
298 if havemf and n not in filenodes[f]: 301 if havemf and n not in filenodes[f]:
299 err(lr, _("%s not in manifests") % (short(n)), f) 302 self.err(lr, _("%s not in manifests") % (short(n)), f)
300 else: 303 else:
301 del filenodes[f][n] 304 del filenodes[f][n]
302 305
303 # verify contents 306 # verify contents
304 try: 307 try:
305 l = len(fl.read(n)) 308 l = len(fl.read(n))
306 rp = fl.renamed(n) 309 rp = fl.renamed(n)
307 if l != fl.size(i): 310 if l != fl.size(i):
308 if len(fl.revision(n)) != fl.size(i): 311 if len(fl.revision(n)) != fl.size(i):
309 err(lr, _("unpacked size is %s, %s expected") % 312 self.err(lr, _("unpacked size is %s, %s expected") %
310 (l, fl.size(i)), f) 313 (l, fl.size(i)), f)
311 except error.CensoredNodeError: 314 except error.CensoredNodeError:
312 # experimental config: censor.policy 315 # experimental config: censor.policy
313 if ui.config("censor", "policy", "abort") == "abort": 316 if ui.config("censor", "policy", "abort") == "abort":
314 err(lr, _("censored file data"), f) 317 self.err(lr, _("censored file data"), f)
315 except Exception as inst: 318 except Exception as inst:
316 exc(lr, _("unpacking %s") % short(n), inst, f) 319 exc(lr, _("unpacking %s") % short(n), inst, f)
317 320
318 # check renames 321 # check renames
319 try: 322 try:
328 if not found: 331 if not found:
329 self.warn(_("warning: copy source of '%s' not" 332 self.warn(_("warning: copy source of '%s' not"
330 " in parents of %s") % (f, ctx)) 333 " in parents of %s") % (f, ctx))
331 fl2 = repo.file(rp[0]) 334 fl2 = repo.file(rp[0])
332 if not len(fl2): 335 if not len(fl2):
333 err(lr, _("empty or missing copy source revlog " 336 self.err(lr, _("empty or missing copy source "
334 "%s:%s") % (rp[0], short(rp[1])), f) 337 "revlog %s:%s") % (rp[0], short(rp[1])), f)
335 elif rp[1] == nullid: 338 elif rp[1] == nullid:
336 ui.note(_("warning: %s@%s: copy source" 339 ui.note(_("warning: %s@%s: copy source"
337 " revision is nullid %s:%s\n") 340 " revision is nullid %s:%s\n")
338 % (f, lr, rp[0], short(rp[1]))) 341 % (f, lr, rp[0], short(rp[1])))
339 else: 342 else:
343 346
344 # cross-check 347 # cross-check
345 if f in filenodes: 348 if f in filenodes:
346 fns = [(lr, n) for n, lr in filenodes[f].iteritems()] 349 fns = [(lr, n) for n, lr in filenodes[f].iteritems()]
347 for lr, node in sorted(fns): 350 for lr, node in sorted(fns):
348 err(lr, _("%s in manifests not found") % short(node), f) 351 self.err(lr, _("%s in manifests not found") % short(node),
352 f)
349 ui.progress(_('checking'), None) 353 ui.progress(_('checking'), None)
350 354
351 for f in storefiles: 355 for f in storefiles:
352 self.warn(_("warning: orphan revlog '%s'") % f) 356 self.warn(_("warning: orphan revlog '%s'") % f)
353 357