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: |
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) |
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 |
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 |
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): |
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)) |
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 |
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. |
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: |
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 |
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 |
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: |
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) |