mercurial/verify.py
changeset 41864 7eaf4b1ac2a3
parent 41863 9534f3cb6b6c
child 41865 5df8475c5343
equal deleted inserted replaced
41863:9534f3cb6b6c 41864:7eaf4b1ac2a3
    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.
   367                 lr = None
   367                 lr = None
   368 
   368 
   369             try:
   369             try:
   370                 fl = repo.file(f)
   370                 fl = repo.file(f)
   371             except error.StorageError as e:
   371             except error.StorageError as e:
   372                 self.err(lr, _("broken revlog! (%s)") % e, f)
   372                 self._err(lr, _("broken revlog! (%s)") % e, f)
   373                 continue
   373                 continue
   374 
   374 
   375             for ff in fl.files():
   375             for ff in fl.files():
   376                 try:
   376                 try:
   377                     storefiles.remove(ff)
   377                     storefiles.remove(ff)
   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)