contrib/dirstatenonnormalcheck.py
changeset 48061 060cd909439f
parent 48060 a660d8a53267
child 48062 46d1b75648f4
equal deleted inserted replaced
48060:a660d8a53267 48061:060cd909439f
     1 # dirstatenonnormalcheck.py - extension to check the consistency of the
       
     2 # dirstate's non-normal map
       
     3 #
       
     4 # For most operations on dirstate, this extensions checks that the nonnormalset
       
     5 # contains the right entries.
       
     6 # It compares the nonnormal file to a nonnormalset built from the map of all
       
     7 # the files in the dirstate to check that they contain the same files.
       
     8 
       
     9 from __future__ import absolute_import
       
    10 
       
    11 from mercurial import (
       
    12     dirstate,
       
    13     extensions,
       
    14     pycompat,
       
    15 )
       
    16 
       
    17 
       
    18 def nonnormalentries(dmap):
       
    19     """Compute nonnormal entries from dirstate's dmap"""
       
    20     res = set()
       
    21     for f, e in dmap.iteritems():
       
    22         if e.state != b'n' or e.mtime == -1:
       
    23             res.add(f)
       
    24     return res
       
    25 
       
    26 
       
    27 INCONSISTENCY_MESSAGE = b"""%s call to %s
       
    28   inconsistency in nonnormalset
       
    29   result from dirstatemap: %s
       
    30   expected nonnormalset:   %s
       
    31 """
       
    32 
       
    33 
       
    34 def checkconsistency(ui, orig, dmap, _nonnormalset, label):
       
    35     """Compute nonnormalset from dmap, check that it matches _nonnormalset"""
       
    36     nonnormalcomputedmap = nonnormalentries(dmap)
       
    37     if _nonnormalset != nonnormalcomputedmap:
       
    38         b_orig = pycompat.sysbytes(repr(orig))
       
    39         b_nonnormal = pycompat.sysbytes(repr(_nonnormalset))
       
    40         b_nonnormalcomputed = pycompat.sysbytes(repr(nonnormalcomputedmap))
       
    41         msg = INCONSISTENCY_MESSAGE % (
       
    42             label,
       
    43             b_orig,
       
    44             b_nonnormal,
       
    45             b_nonnormalcomputed,
       
    46         )
       
    47         ui.develwarn(msg, config=b'dirstate')
       
    48 
       
    49 
       
    50 def _checkdirstate(orig, self, *args, **kwargs):
       
    51     """Check nonnormal set consistency before and after the call to orig"""
       
    52     checkconsistency(
       
    53         self._ui, orig, self._map, self._map.nonnormalset, b"before"
       
    54     )
       
    55     r = orig(self, *args, **kwargs)
       
    56     checkconsistency(
       
    57         self._ui, orig, self._map, self._map.nonnormalset, b"after"
       
    58     )
       
    59     return r
       
    60 
       
    61 
       
    62 def extsetup(ui):
       
    63     """Wrap functions modifying dirstate to check nonnormalset consistency"""
       
    64     dirstatecl = dirstate.dirstate
       
    65     devel = ui.configbool(b'devel', b'all-warnings')
       
    66     paranoid = ui.configbool(b'experimental', b'nonnormalparanoidcheck')
       
    67     if devel:
       
    68         extensions.wrapfunction(dirstatecl, '_writedirstate', _checkdirstate)
       
    69         if paranoid:
       
    70             # We don't do all these checks when paranoid is disable as it would
       
    71             # make the extension run very slowly on large repos
       
    72             extensions.wrapfunction(dirstatecl, 'write', _checkdirstate)
       
    73             extensions.wrapfunction(dirstatecl, 'set_tracked', _checkdirstate)
       
    74             extensions.wrapfunction(dirstatecl, 'set_untracked', _checkdirstate)
       
    75             extensions.wrapfunction(
       
    76                 dirstatecl, 'set_possibly_dirty', _checkdirstate
       
    77             )
       
    78             extensions.wrapfunction(
       
    79                 dirstatecl, 'update_file_p1', _checkdirstate
       
    80             )
       
    81             extensions.wrapfunction(dirstatecl, 'update_file', _checkdirstate)