mercurial/verify.py
changeset 27447 d1b91c10ce70
parent 27446 6b2c1a1871a6
child 27448 f4f2179077cb
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