##// END OF EJS Templates
hgweb: explicit response status
hgweb: explicit response status

File last commit:

r5541:ceaa752f default
r5993:948a41e7 default
Show More
verify.py
274 lines | 8.7 KiB | text/x-python | PythonLexer
Matt Mackall
Move repo.verify
r2778 # verify.py - repository integrity checking for Mercurial
#
Thomas Arendsen Hein
Updated copyright notices and add "and others" to "hg version"
r4635 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
Matt Mackall
Move repo.verify
r2778 #
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
from node import *
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Matt Mackall
remove unneeded imports of mdiff
r5175 import revlog
Matt Mackall
Move repo.verify
r2778
def verify(repo):
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 lock = repo.lock()
try:
return _verify(repo)
finally:
del lock
def _verify(repo):
Matt Mackall
Move repo.verify
r2778 filelinkrevs = {}
filenodes = {}
changesets = revisions = files = 0
Matt Mackall
verify: report first bad changeset...
r5313 firstbad = [None]
Matt Mackall
Move repo.verify
r2778 errors = [0]
warnings = [0]
neededmanifests = {}
Matt Mackall
verify: report first bad changeset...
r5313 def err(linkrev, msg, filename=None):
if linkrev != None:
if firstbad[0] != None:
firstbad[0] = min(firstbad[0], linkrev)
else:
firstbad[0] = linkrev
else:
linkrev = "?"
msg = "%s: %s" % (linkrev, msg)
if filename:
msg = "%s@%s" % (filename, msg)
repo.ui.warn(" " + msg + "\n")
Matt Mackall
Move repo.verify
r2778 errors[0] += 1
def warn(msg):
repo.ui.warn(msg + "\n")
warnings[0] += 1
def checksize(obj, name):
d = obj.checksize()
if d[0]:
Matt Mackall
verify: report first bad changeset...
r5313 err(None, _("data length off by %d bytes") % d[0], name)
Matt Mackall
Move repo.verify
r2778 if d[1]:
Matt Mackall
verify: report first bad changeset...
r5313 err(None, _("index contains %d extra bytes") % d[1], name)
Matt Mackall
Move repo.verify
r2778
def checkversion(obj, name):
if obj.version != revlog.REVLOGV0:
if not revlogv1:
warn(_("warning: `%s' uses revlog format 1") % name)
elif revlogv1:
warn(_("warning: `%s' uses revlog format 0") % name)
Matt Mackall
revlog: simplify revlog version handling...
r4258 revlogv1 = repo.changelog.version != revlog.REVLOGV0
if repo.ui.verbose or not revlogv1:
Matt Mackall
Move repo.verify
r2778 repo.ui.status(_("repository uses revlog format %d\n") %
(revlogv1 and 1 or 0))
Matt Mackall
verify: improve handling of empty or missing files...
r5541 havecl = havemf = 1
Matt Mackall
Move repo.verify
r2778 seen = {}
repo.ui.status(_("checking changesets\n"))
Matt Mackall
verify: improve handling of empty or missing files...
r5541 if repo.changelog.count() == 0 and repo.manifest.count() > 1:
havecl = 0
err(0, _("empty or missing 00changelog.i"))
else:
checksize(repo.changelog, "changelog")
Matt Mackall
Move repo.verify
r2778
Benoit Boissinot
use xrange instead of range
r3473 for i in xrange(repo.changelog.count()):
Matt Mackall
Move repo.verify
r2778 changesets += 1
n = repo.changelog.node(i)
l = repo.changelog.linkrev(n)
if l != i:
Matt Mackall
verify: report first bad changeset...
r5313 err(i, _("incorrect link (%d) for changeset") %(l))
Matt Mackall
Move repo.verify
r2778 if n in seen:
Matt Mackall
verify: report first bad changeset...
r5313 err(i, _("duplicates changeset at revision %d") % seen[n])
seen[n] = i
Matt Mackall
Move repo.verify
r2778
for p in repo.changelog.parents(n):
if p not in repo.changelog.nodemap:
Matt Mackall
verify: report first bad changeset...
r5313 err(i, _("changeset has unknown parent %s") % short(p))
Matt Mackall
Move repo.verify
r2778 try:
changes = repo.changelog.read(n)
except KeyboardInterrupt:
repo.ui.warn(_("interrupted"))
raise
except Exception, inst:
Matt Mackall
verify: report first bad changeset...
r5313 err(i, _("unpacking changeset: %s") % inst)
Matt Mackall
Move repo.verify
r2778 continue
Matt Mackall
verify: report first bad changeset...
r5313 if changes[0] not in neededmanifests:
neededmanifests[changes[0]] = i
Matt Mackall
Move repo.verify
r2778
for f in changes[3]:
filelinkrevs.setdefault(f, []).append(i)
seen = {}
repo.ui.status(_("checking manifests\n"))
Matt Mackall
verify: improve handling of empty or missing files...
r5541 if repo.changelog.count() > 0 and repo.manifest.count() == 0:
havemf = 0
err(0, _("empty or missing 00manifest.i"))
else:
checkversion(repo.manifest, "manifest")
checksize(repo.manifest, "manifest")
Matt Mackall
Move repo.verify
r2778
Benoit Boissinot
use xrange instead of range
r3473 for i in xrange(repo.manifest.count()):
Matt Mackall
Move repo.verify
r2778 n = repo.manifest.node(i)
l = repo.manifest.linkrev(n)
Matt Mackall
verify: improve handling of empty or missing files...
r5541 if l < 0 or (havecl and l >= repo.changelog.count()):
Matt Mackall
verify: report first bad changeset...
r5313 err(None, _("bad link (%d) at manifest revision %d") % (l, i))
Matt Mackall
Move repo.verify
r2778
if n in neededmanifests:
del neededmanifests[n]
if n in seen:
Matt Mackall
verify: report first bad changeset...
r5313 err(l, _("duplicates manifest from %d") % seen[n])
Matt Mackall
Move repo.verify
r2778
Matt Mackall
verify: report first bad changeset...
r5313 seen[n] = l
Matt Mackall
Move repo.verify
r2778
for p in repo.manifest.parents(n):
if p not in repo.manifest.nodemap:
Matt Mackall
verify: report first bad changeset...
r5313 err(l, _("manifest has unknown parent %s") % short(p))
Matt Mackall
Move repo.verify
r2778
try:
Brendan Cully
Abstract manifest block parsing.
r3196 for f, fn in repo.manifest.readdelta(n).iteritems():
Matt Mackall
verify: report first bad changeset...
r5313 fns = filenodes.setdefault(f, {})
if fn not in fns:
fns[fn] = n
Matt Mackall
Move repo.verify
r2778 except KeyboardInterrupt:
repo.ui.warn(_("interrupted"))
raise
except Exception, inst:
Matt Mackall
verify: report first bad changeset...
r5313 err(l, _("reading manifest delta: %s") % inst)
Matt Mackall
Move repo.verify
r2778 continue
repo.ui.status(_("crosschecking files in changesets and manifests\n"))
Matt Mackall
verify: improve handling of empty or missing files...
r5541 if havemf > 0:
nm = [(c, m) for m, c in neededmanifests.items()]
nm.sort()
for c, m in nm:
err(c, _("changeset refers to unknown manifest %s") % short(m))
del neededmanifests, nm
Matt Mackall
Move repo.verify
r2778
Matt Mackall
verify: improve handling of empty or missing files...
r5541 if havecl:
fl = filenodes.keys()
fl.sort()
for f in fl:
if f not in filelinkrevs:
lrs = [repo.manifest.linkrev(n) for n in filenodes[f]]
lrs.sort()
err(lrs[0], _("in manifest but not in changeset"), f)
del fl
Matt Mackall
Move repo.verify
r2778
Matt Mackall
verify: improve handling of empty or missing files...
r5541 if havemf:
fl = filelinkrevs.keys()
fl.sort()
for f in fl:
if f not in filenodes:
lr = filelinkrevs[f][0]
err(lr, _("in changeset but not in manifest"), f)
del fl
Matt Mackall
Move repo.verify
r2778
repo.ui.status(_("checking files\n"))
Matt Mackall
verify: improve handling of empty or missing files...
r5541 ff = dict.fromkeys(filenodes.keys() + filelinkrevs.keys()).keys()
Matt Mackall
Move repo.verify
r2778 ff.sort()
for f in ff:
if f == "/dev/null":
continue
files += 1
if not f:
Matt Mackall
verify: improve handling of empty or missing files...
r5541 lr = filelinkrevs[f][0]
err(lr, _("file without name in manifest"))
Matt Mackall
Move repo.verify
r2778 continue
fl = repo.file(f)
checkversion(fl, f)
checksize(fl, f)
Matt Mackall
verify: improve handling of empty or missing files...
r5541 if fl.count() == 0:
err(filelinkrevs[f][0], _("empty or missing revlog"), f)
continue
Matt Mackall
verify: report first bad changeset...
r5313 seen = {}
Matt Mackall
Move repo.verify
r2778 nodes = {nullid: 1}
Benoit Boissinot
use xrange instead of range
r3473 for i in xrange(fl.count()):
Matt Mackall
Move repo.verify
r2778 revisions += 1
n = fl.node(i)
Matt Mackall
verify: report first bad changeset...
r5313 flr = fl.linkrev(n)
Matt Mackall
verify: improve handling of empty or missing files...
r5541 if flr < 0 or (havecl and flr not in filelinkrevs.get(f, [])):
Matt Mackall
verify: report first bad changeset...
r5313 if flr < 0 or flr >= repo.changelog.count():
err(None, _("rev %d point to nonexistent changeset %d")
% (i, flr), f)
else:
err(None, _("rev %d points to unexpected changeset %d")
% (i, flr), f)
if f in filelinkrevs:
warn(_(" (expected %s)") % filelinkrevs[f][0])
flr = None # can't be trusted
else:
Matt Mackall
verify: improve handling of empty or missing files...
r5541 if havecl:
filelinkrevs[f].remove(flr)
Matt Mackall
Move repo.verify
r2778
if n in seen:
Matt Mackall
verify: report first bad changeset...
r5313 err(flr, _("duplicate revision %d") % i, f)
Matt Mackall
verify: improve handling of empty or missing files...
r5541 if f in filenodes:
if havemf and n not in filenodes[f]:
err(flr, _("%s not in manifests") % (short(n)), f)
else:
del filenodes[f][n]
Matt Mackall
Move repo.verify
r2778
# verify contents
try:
t = fl.read(n)
except KeyboardInterrupt:
repo.ui.warn(_("interrupted"))
raise
except Exception, inst:
Matt Mackall
verify: report first bad changeset...
r5313 err(flr, _("unpacking %s: %s") % (short(n), inst), f)
Matt Mackall
Move repo.verify
r2778
# verify parents
Matt Mackall
verify: report first bad changeset...
r5313 try:
(p1, p2) = fl.parents(n)
if p1 not in nodes:
err(flr, _("unknown parent 1 %s of %s") %
(short(p1), short(n)), f)
if p2 not in nodes:
err(flr, _("unknown parent 2 %s of %s") %
(short(p2), short(p1)), f)
except KeyboardInterrupt:
repo.ui.warn(_("interrupted"))
raise
except Exception, inst:
err(flr, _("checking parents of %s: %s") % (short(n), inst), f)
Matt Mackall
Move repo.verify
r2778 nodes[n] = 1
Matt Mackall
verify: add rename link checking
r3744 # check renames
try:
rp = fl.renamed(n)
if rp:
fl2 = repo.file(rp[0])
rev = fl2.rev(rp[1])
except KeyboardInterrupt:
repo.ui.warn(_("interrupted"))
raise
except Exception, inst:
Matt Mackall
verify: report first bad changeset...
r5313 err(flr, _("checking rename of %s: %s") %
(short(n), inst), f)
Matt Mackall
verify: add rename link checking
r3744
Matt Mackall
Move repo.verify
r2778 # cross-check
Matt Mackall
verify: improve handling of empty or missing files...
r5541 if f in filenodes:
fns = [(repo.manifest.linkrev(filenodes[f][n]), n)
for n in filenodes[f]]
fns.sort()
for lr, node in fns:
err(lr, _("%s in manifests not found") % short(node), f)
Matt Mackall
Move repo.verify
r2778
repo.ui.status(_("%d files, %d changesets, %d total revisions\n") %
(files, changesets, revisions))
if warnings[0]:
repo.ui.warn(_("%d warnings encountered!\n") % warnings[0])
if errors[0]:
repo.ui.warn(_("%d integrity errors encountered!\n") % errors[0])
Matt Mackall
verify: report first bad changeset...
r5313 if firstbad[0]:
repo.ui.warn(_("(first damaged changeset appears to be %d)\n")
% firstbad[0])
Matt Mackall
Move repo.verify
r2778 return 1