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) |
|