##// END OF EJS Templates
flagprocessors: make `_processflagsfunc` a module level function...
marmoute -
r43259:50d9de61 default
parent child Browse files
Show More
@@ -1,202 +1,206 b''
1 # flagutils.py - code to deal with revlog flags and their processors
1 # flagutils.py - code to deal with revlog flags and their processors
2 #
2 #
3 # Copyright 2016 Remi Chaintron <remi@fb.com>
3 # Copyright 2016 Remi Chaintron <remi@fb.com>
4 # Copyright 2016-2019 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
4 # Copyright 2016-2019 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from __future__ import absolute_import
9 from __future__ import absolute_import
10
10
11 from ..i18n import _
11 from ..i18n import _
12
12
13 from .constants import (
13 from .constants import (
14 REVIDX_DEFAULT_FLAGS,
14 REVIDX_DEFAULT_FLAGS,
15 REVIDX_ELLIPSIS,
15 REVIDX_ELLIPSIS,
16 REVIDX_EXTSTORED,
16 REVIDX_EXTSTORED,
17 REVIDX_FLAGS_ORDER,
17 REVIDX_FLAGS_ORDER,
18 REVIDX_ISCENSORED,
18 REVIDX_ISCENSORED,
19 REVIDX_RAWTEXT_CHANGING_FLAGS,
19 REVIDX_RAWTEXT_CHANGING_FLAGS,
20 )
20 )
21
21
22 from .. import (
22 from .. import (
23 error,
23 error,
24 util
24 util
25 )
25 )
26
26
27 # blanked usage of all the name to prevent pyflakes constraints
27 # blanked usage of all the name to prevent pyflakes constraints
28 # We need these name available in the module for extensions.
28 # We need these name available in the module for extensions.
29 REVIDX_ISCENSORED
29 REVIDX_ISCENSORED
30 REVIDX_ELLIPSIS
30 REVIDX_ELLIPSIS
31 REVIDX_EXTSTORED
31 REVIDX_EXTSTORED
32 REVIDX_DEFAULT_FLAGS
32 REVIDX_DEFAULT_FLAGS
33 REVIDX_FLAGS_ORDER
33 REVIDX_FLAGS_ORDER
34 REVIDX_RAWTEXT_CHANGING_FLAGS
34 REVIDX_RAWTEXT_CHANGING_FLAGS
35
35
36 REVIDX_KNOWN_FLAGS = util.bitsfrom(REVIDX_FLAGS_ORDER)
36 REVIDX_KNOWN_FLAGS = util.bitsfrom(REVIDX_FLAGS_ORDER)
37
37
38 # Store flag processors (cf. 'addflagprocessor()' to register)
38 # Store flag processors (cf. 'addflagprocessor()' to register)
39 flagprocessors = {
39 flagprocessors = {
40 REVIDX_ISCENSORED: None,
40 REVIDX_ISCENSORED: None,
41 }
41 }
42
42
43 def addflagprocessor(flag, processor):
43 def addflagprocessor(flag, processor):
44 """Register a flag processor on a revision data flag.
44 """Register a flag processor on a revision data flag.
45
45
46 Invariant:
46 Invariant:
47 - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER,
47 - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER,
48 and REVIDX_RAWTEXT_CHANGING_FLAGS if they can alter rawtext.
48 and REVIDX_RAWTEXT_CHANGING_FLAGS if they can alter rawtext.
49 - Only one flag processor can be registered on a specific flag.
49 - Only one flag processor can be registered on a specific flag.
50 - flagprocessors must be 3-tuples of functions (read, write, raw) with the
50 - flagprocessors must be 3-tuples of functions (read, write, raw) with the
51 following signatures:
51 following signatures:
52 - (read) f(self, rawtext) -> text, bool
52 - (read) f(self, rawtext) -> text, bool
53 - (write) f(self, text) -> rawtext, bool
53 - (write) f(self, text) -> rawtext, bool
54 - (raw) f(self, rawtext) -> bool
54 - (raw) f(self, rawtext) -> bool
55 "text" is presented to the user. "rawtext" is stored in revlog data, not
55 "text" is presented to the user. "rawtext" is stored in revlog data, not
56 directly visible to the user.
56 directly visible to the user.
57 The boolean returned by these transforms is used to determine whether
57 The boolean returned by these transforms is used to determine whether
58 the returned text can be used for hash integrity checking. For example,
58 the returned text can be used for hash integrity checking. For example,
59 if "write" returns False, then "text" is used to generate hash. If
59 if "write" returns False, then "text" is used to generate hash. If
60 "write" returns True, that basically means "rawtext" returned by "write"
60 "write" returns True, that basically means "rawtext" returned by "write"
61 should be used to generate hash. Usually, "write" and "read" return
61 should be used to generate hash. Usually, "write" and "read" return
62 different booleans. And "raw" returns a same boolean as "write".
62 different booleans. And "raw" returns a same boolean as "write".
63
63
64 Note: The 'raw' transform is used for changegroup generation and in some
64 Note: The 'raw' transform is used for changegroup generation and in some
65 debug commands. In this case the transform only indicates whether the
65 debug commands. In this case the transform only indicates whether the
66 contents can be used for hash integrity checks.
66 contents can be used for hash integrity checks.
67 """
67 """
68 insertflagprocessor(flag, processor, flagprocessors)
68 insertflagprocessor(flag, processor, flagprocessors)
69
69
70 def insertflagprocessor(flag, processor, flagprocessors):
70 def insertflagprocessor(flag, processor, flagprocessors):
71 if not flag & REVIDX_KNOWN_FLAGS:
71 if not flag & REVIDX_KNOWN_FLAGS:
72 msg = _("cannot register processor on unknown flag '%#x'.") % (flag)
72 msg = _("cannot register processor on unknown flag '%#x'.") % (flag)
73 raise error.ProgrammingError(msg)
73 raise error.ProgrammingError(msg)
74 if flag not in REVIDX_FLAGS_ORDER:
74 if flag not in REVIDX_FLAGS_ORDER:
75 msg = _("flag '%#x' undefined in REVIDX_FLAGS_ORDER.") % (flag)
75 msg = _("flag '%#x' undefined in REVIDX_FLAGS_ORDER.") % (flag)
76 raise error.ProgrammingError(msg)
76 raise error.ProgrammingError(msg)
77 if flag in flagprocessors:
77 if flag in flagprocessors:
78 msg = _("cannot register multiple processors on flag '%#x'.") % (flag)
78 msg = _("cannot register multiple processors on flag '%#x'.") % (flag)
79 raise error.Abort(msg)
79 raise error.Abort(msg)
80 flagprocessors[flag] = processor
80 flagprocessors[flag] = processor
81
81
82 class flagprocessorsmixin(object):
82 class flagprocessorsmixin(object):
83 """basic mixin to support revlog flag processing
83 """basic mixin to support revlog flag processing
84
84
85 Make sure the `_flagprocessors` attribute is set at ``__init__`` time.
85 Make sure the `_flagprocessors` attribute is set at ``__init__`` time.
86
86
87 See the documentation of the ``_processflags`` method for details.
87 See the documentation of the ``_processflags`` method for details.
88 """
88 """
89
89
90 _flagserrorclass = error.RevlogError
90 _flagserrorclass = error.RevlogError
91
91
92 def _processflags(self, text, flags, operation, raw=False):
92 def _processflags(self, text, flags, operation, raw=False):
93 """deprecated entry point to access flag processors"""
93 """deprecated entry point to access flag processors"""
94 msg = ('_processflag(...) use the specialized variant')
94 msg = ('_processflag(...) use the specialized variant')
95 util.nouideprecwarn(msg, '5.2', stacklevel=2)
95 util.nouideprecwarn(msg, '5.2', stacklevel=2)
96 if raw:
96 if raw:
97 return text, self._processflagsraw(text, flags)
97 return text, self._processflagsraw(text, flags)
98 elif operation == 'read':
98 elif operation == 'read':
99 return self._processflagsread(text, flags)
99 return self._processflagsread(text, flags)
100 else: # write operation
100 else: # write operation
101 return self._processflagswrite(text, flags)
101 return self._processflagswrite(text, flags)
102
102
103 def _processflagsread(self, text, flags):
103 def _processflagsread(self, text, flags):
104 """Inspect revision data flags and applies read transformations defined
104 """Inspect revision data flags and applies read transformations defined
105 by registered flag processors.
105 by registered flag processors.
106
106
107 ``text`` - the revision data to process
107 ``text`` - the revision data to process
108 ``flags`` - the revision flags
108 ``flags`` - the revision flags
109 ``raw`` - an optional argument describing if the raw transform should be
109 ``raw`` - an optional argument describing if the raw transform should be
110 applied.
110 applied.
111
111
112 This method processes the flags in the order (or reverse order if
112 This method processes the flags in the order (or reverse order if
113 ``operation`` is 'write') defined by REVIDX_FLAGS_ORDER, applying the
113 ``operation`` is 'write') defined by REVIDX_FLAGS_ORDER, applying the
114 flag processors registered for present flags. The order of flags defined
114 flag processors registered for present flags. The order of flags defined
115 in REVIDX_FLAGS_ORDER needs to be stable to allow non-commutativity.
115 in REVIDX_FLAGS_ORDER needs to be stable to allow non-commutativity.
116
116
117 Returns a 2-tuple of ``(text, validatehash)`` where ``text`` is the
117 Returns a 2-tuple of ``(text, validatehash)`` where ``text`` is the
118 processed text and ``validatehash`` is a bool indicating whether the
118 processed text and ``validatehash`` is a bool indicating whether the
119 returned text should be checked for hash integrity.
119 returned text should be checked for hash integrity.
120 """
120 """
121 return self._processflagsfunc(text, flags, 'read')
121 return _processflagsfunc(self, text, flags, 'read')
122
122
123 def _processflagswrite(self, text, flags, sidedata):
123 def _processflagswrite(self, text, flags, sidedata):
124 """Inspect revision data flags and applies write transformations defined
124 """Inspect revision data flags and applies write transformations defined
125 by registered flag processors.
125 by registered flag processors.
126
126
127 ``text`` - the revision data to process
127 ``text`` - the revision data to process
128 ``flags`` - the revision flags
128 ``flags`` - the revision flags
129
129
130 This method processes the flags in the order (or reverse order if
130 This method processes the flags in the order (or reverse order if
131 ``operation`` is 'write') defined by REVIDX_FLAGS_ORDER, applying the
131 ``operation`` is 'write') defined by REVIDX_FLAGS_ORDER, applying the
132 flag processors registered for present flags. The order of flags defined
132 flag processors registered for present flags. The order of flags defined
133 in REVIDX_FLAGS_ORDER needs to be stable to allow non-commutativity.
133 in REVIDX_FLAGS_ORDER needs to be stable to allow non-commutativity.
134
134
135 Returns a 2-tuple of ``(text, validatehash)`` where ``text`` is the
135 Returns a 2-tuple of ``(text, validatehash)`` where ``text`` is the
136 processed text and ``validatehash`` is a bool indicating whether the
136 processed text and ``validatehash`` is a bool indicating whether the
137 returned text should be checked for hash integrity.
137 returned text should be checked for hash integrity.
138 """
138 """
139 return self._processflagsfunc(text, flags, 'write',
139 return _processflagsfunc(self, text, flags, 'write',
140 sidedata=sidedata)[:2]
140 sidedata=sidedata)[:2]
141
141
142 def _processflagsraw(self, text, flags):
142 def _processflagsraw(self, text, flags):
143 """Inspect revision data flags to check is the content hash should be
143 """Inspect revision data flags to check is the content hash should be
144 validated.
144 validated.
145
145
146 ``text`` - the revision data to process
146 ``text`` - the revision data to process
147 ``flags`` - the revision flags
147 ``flags`` - the revision flags
148
148
149 This method processes the flags in the order (or reverse order if
149 This method processes the flags in the order (or reverse order if
150 ``operation`` is 'write') defined by REVIDX_FLAGS_ORDER, applying the
150 ``operation`` is 'write') defined by REVIDX_FLAGS_ORDER, applying the
151 flag processors registered for present flags. The order of flags defined
151 flag processors registered for present flags. The order of flags defined
152 in REVIDX_FLAGS_ORDER needs to be stable to allow non-commutativity.
152 in REVIDX_FLAGS_ORDER needs to be stable to allow non-commutativity.
153
153
154 Returns a 2-tuple of ``(text, validatehash)`` where ``text`` is the
154 Returns a 2-tuple of ``(text, validatehash)`` where ``text`` is the
155 processed text and ``validatehash`` is a bool indicating whether the
155 processed text and ``validatehash`` is a bool indicating whether the
156 returned text should be checked for hash integrity.
156 returned text should be checked for hash integrity.
157 """
157 """
158 return self._processflagsfunc(text, flags, 'raw')[1]
158 return _processflagsfunc(self, text, flags, 'raw')[1]
159
160 def _processflagsfunc(revlog, text, flags, operation, sidedata=None):
161 """internal function to process flag on a revlog
159
162
160 def _processflagsfunc(self, text, flags, operation, sidedata=None):
163 This function is private to this module, code should never needs to call it
161 # fast path: no flag processors will run
164 directly."""
162 if flags == 0:
165 # fast path: no flag processors will run
163 return text, True, {}
166 if flags == 0:
164 if operation not in ('read', 'write', 'raw'):
167 return text, True, {}
165 raise error.ProgrammingError(_("invalid '%s' operation") %
168 if operation not in ('read', 'write', 'raw'):
166 operation)
169 raise error.ProgrammingError(_("invalid '%s' operation") %
167 # Check all flags are known.
170 operation)
168 if flags & ~REVIDX_KNOWN_FLAGS:
171 # Check all flags are known.
169 raise self._flagserrorclass(_("incompatible revision flag '%#x'") %
172 if flags & ~REVIDX_KNOWN_FLAGS:
170 (flags & ~REVIDX_KNOWN_FLAGS))
173 raise revlog._flagserrorclass(_("incompatible revision flag '%#x'") %
171 validatehash = True
174 (flags & ~REVIDX_KNOWN_FLAGS))
172 # Depending on the operation (read or write), the order might be
175 validatehash = True
173 # reversed due to non-commutative transforms.
176 # Depending on the operation (read or write), the order might be
174 orderedflags = REVIDX_FLAGS_ORDER
177 # reversed due to non-commutative transforms.
175 if operation == 'write':
178 orderedflags = REVIDX_FLAGS_ORDER
176 orderedflags = reversed(orderedflags)
179 if operation == 'write':
180 orderedflags = reversed(orderedflags)
177
181
178 outsidedata = {}
182 outsidedata = {}
179 for flag in orderedflags:
183 for flag in orderedflags:
180 # If a flagprocessor has been registered for a known flag, apply the
184 # If a flagprocessor has been registered for a known flag, apply the
181 # related operation transform and update result tuple.
185 # related operation transform and update result tuple.
182 if flag & flags:
186 if flag & flags:
183 vhash = True
187 vhash = True
184
188
185 if flag not in self._flagprocessors:
189 if flag not in revlog._flagprocessors:
186 message = _("missing processor for flag '%#x'") % (flag)
190 message = _("missing processor for flag '%#x'") % (flag)
187 raise self._flagserrorclass(message)
191 raise revlog._flagserrorclass(message)
188
192
189 processor = self._flagprocessors[flag]
193 processor = revlog._flagprocessors[flag]
190 if processor is not None:
194 if processor is not None:
191 readtransform, writetransform, rawtransform = processor
195 readtransform, writetransform, rawtransform = processor
192
196
193 if operation == 'raw':
197 if operation == 'raw':
194 vhash = rawtransform(self, text)
198 vhash = rawtransform(revlog, text)
195 elif operation == 'read':
199 elif operation == 'read':
196 text, vhash, s = readtransform(self, text)
200 text, vhash, s = readtransform(revlog, text)
197 outsidedata.update(s)
201 outsidedata.update(s)
198 else: # write operation
202 else: # write operation
199 text, vhash = writetransform(self, text, sidedata)
203 text, vhash = writetransform(revlog, text, sidedata)
200 validatehash = validatehash and vhash
204 validatehash = validatehash and vhash
201
205
202 return text, validatehash, outsidedata
206 return text, validatehash, outsidedata
General Comments 0
You need to be logged in to leave comments. Login now