mercurial/verify.py
changeset 5323 29be4228303b
parent 5186 2da57dc04aa8
equal deleted inserted replaced
5322:fb070713ff36 5323:29be4228303b
    18 
    18 
    19 def _verify(repo):
    19 def _verify(repo):
    20     filelinkrevs = {}
    20     filelinkrevs = {}
    21     filenodes = {}
    21     filenodes = {}
    22     changesets = revisions = files = 0
    22     changesets = revisions = files = 0
       
    23     firstbad = [None]
    23     errors = [0]
    24     errors = [0]
    24     warnings = [0]
    25     warnings = [0]
    25     neededmanifests = {}
    26     neededmanifests = {}
    26 
    27 
    27     def err(msg):
    28     def err(linkrev, msg, filename=None):
    28         repo.ui.warn(msg + "\n")
    29         if linkrev != None:
       
    30             if firstbad[0] != None:
       
    31                 firstbad[0] = min(firstbad[0], linkrev)
       
    32             else:
       
    33                 firstbad[0] = linkrev
       
    34         else:
       
    35             linkrev = "?"
       
    36         msg = "%s: %s" % (linkrev, msg)
       
    37         if filename:
       
    38             msg = "%s@%s" % (filename, msg)
       
    39         repo.ui.warn(" " + msg + "\n")
    29         errors[0] += 1
    40         errors[0] += 1
    30 
    41 
    31     def warn(msg):
    42     def warn(msg):
    32         repo.ui.warn(msg + "\n")
    43         repo.ui.warn(msg + "\n")
    33         warnings[0] += 1
    44         warnings[0] += 1
    34 
    45 
    35     def checksize(obj, name):
    46     def checksize(obj, name):
    36         d = obj.checksize()
    47         d = obj.checksize()
    37         if d[0]:
    48         if d[0]:
    38             err(_("%s data length off by %d bytes") % (name, d[0]))
    49             err(None, _("data length off by %d bytes") % d[0], name)
    39         if d[1]:
    50         if d[1]:
    40             err(_("%s index contains %d extra bytes") % (name, d[1]))
    51             err(None, _("index contains %d extra bytes") % d[1], name)
    41 
    52 
    42     def checkversion(obj, name):
    53     def checkversion(obj, name):
    43         if obj.version != revlog.REVLOGV0:
    54         if obj.version != revlog.REVLOGV0:
    44             if not revlogv1:
    55             if not revlogv1:
    45                 warn(_("warning: `%s' uses revlog format 1") % name)
    56                 warn(_("warning: `%s' uses revlog format 1") % name)
    58     for i in xrange(repo.changelog.count()):
    69     for i in xrange(repo.changelog.count()):
    59         changesets += 1
    70         changesets += 1
    60         n = repo.changelog.node(i)
    71         n = repo.changelog.node(i)
    61         l = repo.changelog.linkrev(n)
    72         l = repo.changelog.linkrev(n)
    62         if l != i:
    73         if l != i:
    63             err(_("incorrect link (%d) for changeset revision %d") %(l, i))
    74             err(i, _("incorrect link (%d) for changeset") %(l))
    64         if n in seen:
    75         if n in seen:
    65             err(_("duplicate changeset at revision %d") % i)
    76             err(i, _("duplicates changeset at revision %d") % seen[n])
    66         seen[n] = 1
    77         seen[n] = i
    67 
    78 
    68         for p in repo.changelog.parents(n):
    79         for p in repo.changelog.parents(n):
    69             if p not in repo.changelog.nodemap:
    80             if p not in repo.changelog.nodemap:
    70                 err(_("changeset %s has unknown parent %s") %
    81                 err(i, _("changeset has unknown parent %s") % short(p))
    71                              (short(n), short(p)))
       
    72         try:
    82         try:
    73             changes = repo.changelog.read(n)
    83             changes = repo.changelog.read(n)
    74         except KeyboardInterrupt:
    84         except KeyboardInterrupt:
    75             repo.ui.warn(_("interrupted"))
    85             repo.ui.warn(_("interrupted"))
    76             raise
    86             raise
    77         except Exception, inst:
    87         except Exception, inst:
    78             err(_("unpacking changeset %s: %s") % (short(n), inst))
    88             err(i, _("unpacking changeset: %s") % inst)
    79             continue
    89             continue
    80 
    90 
    81         neededmanifests[changes[0]] = n
    91         if changes[0] not in neededmanifests:
       
    92             neededmanifests[changes[0]] = i
    82 
    93 
    83         for f in changes[3]:
    94         for f in changes[3]:
    84             filelinkrevs.setdefault(f, []).append(i)
    95             filelinkrevs.setdefault(f, []).append(i)
    85 
    96 
    86     seen = {}
    97     seen = {}
    91     for i in xrange(repo.manifest.count()):
   102     for i in xrange(repo.manifest.count()):
    92         n = repo.manifest.node(i)
   103         n = repo.manifest.node(i)
    93         l = repo.manifest.linkrev(n)
   104         l = repo.manifest.linkrev(n)
    94 
   105 
    95         if l < 0 or l >= repo.changelog.count():
   106         if l < 0 or l >= repo.changelog.count():
    96             err(_("bad manifest link (%d) at revision %d") % (l, i))
   107             err(None, _("bad link (%d) at manifest revision %d") % (l, i))
    97 
   108 
    98         if n in neededmanifests:
   109         if n in neededmanifests:
    99             del neededmanifests[n]
   110             del neededmanifests[n]
   100 
   111 
   101         if n in seen:
   112         if n in seen:
   102             err(_("duplicate manifest at revision %d") % i)
   113             err(l, _("duplicates manifest from %d") % seen[n])
   103 
   114 
   104         seen[n] = 1
   115         seen[n] = l
   105 
   116 
   106         for p in repo.manifest.parents(n):
   117         for p in repo.manifest.parents(n):
   107             if p not in repo.manifest.nodemap:
   118             if p not in repo.manifest.nodemap:
   108                 err(_("manifest %s has unknown parent %s") %
   119                 err(l, _("manifest has unknown parent %s") % short(p))
   109                     (short(n), short(p)))
       
   110 
   120 
   111         try:
   121         try:
   112             for f, fn in repo.manifest.readdelta(n).iteritems():
   122             for f, fn in repo.manifest.readdelta(n).iteritems():
   113                 filenodes.setdefault(f, {})[fn] = 1
   123                 fns = filenodes.setdefault(f, {})
       
   124                 if fn not in fns:
       
   125                     fns[fn] = n
   114         except KeyboardInterrupt:
   126         except KeyboardInterrupt:
   115             repo.ui.warn(_("interrupted"))
   127             repo.ui.warn(_("interrupted"))
   116             raise
   128             raise
   117         except Exception, inst:
   129         except Exception, inst:
   118             err(_("reading delta for manifest %s: %s") % (short(n), inst))
   130             err(l, _("reading manifest delta: %s") % inst)
   119             continue
   131             continue
   120 
   132 
   121     repo.ui.status(_("crosschecking files in changesets and manifests\n"))
   133     repo.ui.status(_("crosschecking files in changesets and manifests\n"))
   122 
   134 
   123     for m, c in neededmanifests.items():
   135     nm = neededmanifests.items()
   124         err(_("Changeset %s refers to unknown manifest %s") %
   136     nm.sort()
   125             (short(m), short(c)))
   137     for m, c in nm:
   126     del neededmanifests
   138         err(m, _("changeset refers to unknown manifest %s") % short(c))
       
   139     del neededmanifests, nm
   127 
   140 
   128     for f in filenodes:
   141     for f in filenodes:
   129         if f not in filelinkrevs:
   142         if f not in filelinkrevs:
   130             err(_("file %s in manifest but not in changesets") % f)
   143             lrs = [repo.manifest.linkrev(n) for n in filenodes[f]]
       
   144             lrs.sort()
       
   145             err(lrs[0], _("in manifest but not in changeset"), f)
   131 
   146 
   132     for f in filelinkrevs:
   147     for f in filelinkrevs:
   133         if f not in filenodes:
   148         if f not in filenodes:
   134             err(_("file %s in changeset but not in manifest") % f)
   149             lr = filelinkrevs[f][0]
       
   150             err(lr, _("in changeset but not in manifest"), f)
   135 
   151 
   136     repo.ui.status(_("checking files\n"))
   152     repo.ui.status(_("checking files\n"))
   137     ff = filenodes.keys()
   153     ff = filenodes.keys()
   138     ff.sort()
   154     ff.sort()
   139     for f in ff:
   155     for f in ff:
   140         if f == "/dev/null":
   156         if f == "/dev/null":
   141             continue
   157             continue
   142         files += 1
   158         files += 1
   143         if not f:
   159         if not f:
   144             err(_("file without name in manifest %s") % short(n))
   160             lr = repo.manifest.linkrev(filenodes[f][0])
       
   161             err(lr, _("file without name in manifest %s") % short(ff[n]))
   145             continue
   162             continue
   146         fl = repo.file(f)
   163         fl = repo.file(f)
   147         checkversion(fl, f)
   164         checkversion(fl, f)
   148         checksize(fl, f)
   165         checksize(fl, f)
   149 
   166 
       
   167         seen = {}
   150         nodes = {nullid: 1}
   168         nodes = {nullid: 1}
   151         seen = {}
       
   152         for i in xrange(fl.count()):
   169         for i in xrange(fl.count()):
   153             revisions += 1
   170             revisions += 1
   154             n = fl.node(i)
   171             n = fl.node(i)
       
   172             flr = fl.linkrev(n)
       
   173 
       
   174             if flr not in filelinkrevs.get(f, []):
       
   175                 if flr < 0 or flr >= repo.changelog.count():
       
   176                     err(None, _("rev %d point to nonexistent changeset %d")
       
   177                         % (i, flr), f)
       
   178                 else:
       
   179                     err(None, _("rev %d points to unexpected changeset %d")
       
   180                         % (i, flr), f)
       
   181                 if f in filelinkrevs:
       
   182                     warn(_(" (expected %s)") % filelinkrevs[f][0])
       
   183                 flr = None # can't be trusted
       
   184             else:
       
   185                 filelinkrevs[f].remove(flr)
   155 
   186 
   156             if n in seen:
   187             if n in seen:
   157                 err(_("%s: duplicate revision %d") % (f, i))
   188                 err(flr, _("duplicate revision %d") % i, f)
   158             if n not in filenodes[f]:
   189             if n not in filenodes[f]:
   159                 err(_("%s: %d:%s not in manifests") % (f, i, short(n)))
   190                 err(flr, _("%s not in manifests") % (short(n)), f)
   160             else:
   191             else:
   161                 del filenodes[f][n]
   192                 del filenodes[f][n]
   162 
       
   163             flr = fl.linkrev(n)
       
   164             if flr not in filelinkrevs.get(f, []):
       
   165                 err(_("%s:%s points to unexpected changeset %d")
       
   166                         % (f, short(n), flr))
       
   167                 err(_("expecting one of %s" % filelinkrevs.get(f, [])))
       
   168             else:
       
   169                 filelinkrevs[f].remove(flr)
       
   170 
   193 
   171             # verify contents
   194             # verify contents
   172             try:
   195             try:
   173                 t = fl.read(n)
   196                 t = fl.read(n)
   174             except KeyboardInterrupt:
   197             except KeyboardInterrupt:
   175                 repo.ui.warn(_("interrupted"))
   198                 repo.ui.warn(_("interrupted"))
   176                 raise
   199                 raise
   177             except Exception, inst:
   200             except Exception, inst:
   178                 err(_("unpacking file %s %s: %s") % (f, short(n), inst))
   201                 err(flr, _("unpacking %s: %s") % (short(n), inst), f)
   179 
   202 
   180             # verify parents
   203             # verify parents
   181             (p1, p2) = fl.parents(n)
   204             try:
   182             if p1 not in nodes:
   205                 (p1, p2) = fl.parents(n)
   183                 err(_("file %s:%s unknown parent 1 %s") %
   206                 if p1 not in nodes:
   184                     (f, short(n), short(p1)))
   207                     err(flr, _("unknown parent 1 %s of %s") %
   185             if p2 not in nodes:
   208                         (short(p1), short(n)), f)
   186                 err(_("file %s:%s unknown parent 2 %s") %
   209                 if p2 not in nodes:
   187                         (f, short(n), short(p1)))
   210                     err(flr, _("unknown parent 2 %s of %s") %
       
   211                             (short(p2), short(p1)), f)
       
   212             except KeyboardInterrupt:
       
   213                 repo.ui.warn(_("interrupted"))
       
   214                 raise
       
   215             except Exception, inst:
       
   216                 err(flr, _("checking parents of %s: %s") % (short(n), inst), f)
   188             nodes[n] = 1
   217             nodes[n] = 1
   189 
   218 
   190             # check renames
   219             # check renames
   191             try:
   220             try:
   192                 rp = fl.renamed(n)
   221                 rp = fl.renamed(n)
   195                     rev = fl2.rev(rp[1])
   224                     rev = fl2.rev(rp[1])
   196             except KeyboardInterrupt:
   225             except KeyboardInterrupt:
   197                 repo.ui.warn(_("interrupted"))
   226                 repo.ui.warn(_("interrupted"))
   198                 raise
   227                 raise
   199             except Exception, inst:
   228             except Exception, inst:
   200                 err(_("checking rename on file %s %s: %s") % (f, short(n), inst))
   229                 err(flr, _("checking rename of %s: %s") %
       
   230                     (short(n), inst), f)
   201 
   231 
   202         # cross-check
   232         # cross-check
   203         for node in filenodes[f]:
   233         fns = [(repo.manifest.linkrev(filenodes[f][n]), n)
   204             err(_("node %s in manifests not in %s") % (hex(node), f))
   234                for n in filenodes[f]]
       
   235         fns.sort()
       
   236         for lr, node in fns:
       
   237             err(lr, _("%s in manifests not found") % short(node), f)
   205 
   238 
   206     repo.ui.status(_("%d files, %d changesets, %d total revisions\n") %
   239     repo.ui.status(_("%d files, %d changesets, %d total revisions\n") %
   207                    (files, changesets, revisions))
   240                    (files, changesets, revisions))
   208 
   241 
   209     if warnings[0]:
   242     if warnings[0]:
   210         repo.ui.warn(_("%d warnings encountered!\n") % warnings[0])
   243         repo.ui.warn(_("%d warnings encountered!\n") % warnings[0])
   211     if errors[0]:
   244     if errors[0]:
   212         repo.ui.warn(_("%d integrity errors encountered!\n") % errors[0])
   245         repo.ui.warn(_("%d integrity errors encountered!\n") % errors[0])
       
   246         if firstbad[0]:
       
   247             repo.ui.warn(_("(first damaged changeset appears to be %d)\n")
       
   248                          % firstbad[0])
   213         return 1
   249         return 1
   214 
   250