Show More
@@ -1,199 +1,199 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 self._processflagsfunc(text, flags, 'read') | |
122 |
|
122 | |||
123 | def _processflagswrite(self, text, flags): |
|
123 | def _processflagswrite(self, text, flags): | |
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 self._processflagsfunc(text, flags, 'write') | |
140 |
|
140 | |||
141 | def _processflagsraw(self, text, flags): |
|
141 | def _processflagsraw(self, text, flags): | |
142 | """Inspect revision data flags to check is the content hash should be |
|
142 | """Inspect revision data flags to check is the content hash should be | |
143 | validated. |
|
143 | validated. | |
144 |
|
144 | |||
145 | ``text`` - the revision data to process |
|
145 | ``text`` - the revision data to process | |
146 | ``flags`` - the revision flags |
|
146 | ``flags`` - the revision flags | |
147 |
|
147 | |||
148 | This method processes the flags in the order (or reverse order if |
|
148 | This method processes the flags in the order (or reverse order if | |
149 | ``operation`` is 'write') defined by REVIDX_FLAGS_ORDER, applying the |
|
149 | ``operation`` is 'write') defined by REVIDX_FLAGS_ORDER, applying the | |
150 | flag processors registered for present flags. The order of flags defined |
|
150 | flag processors registered for present flags. The order of flags defined | |
151 | in REVIDX_FLAGS_ORDER needs to be stable to allow non-commutativity. |
|
151 | in REVIDX_FLAGS_ORDER needs to be stable to allow non-commutativity. | |
152 |
|
152 | |||
153 | Returns a 2-tuple of ``(text, validatehash)`` where ``text`` is the |
|
153 | Returns a 2-tuple of ``(text, validatehash)`` where ``text`` is the | |
154 | processed text and ``validatehash`` is a bool indicating whether the |
|
154 | processed text and ``validatehash`` is a bool indicating whether the | |
155 | returned text should be checked for hash integrity. |
|
155 | returned text should be checked for hash integrity. | |
156 | """ |
|
156 | """ | |
157 |
return self._processflagsfunc(text, flags, 'r |
|
157 | return self._processflagsfunc(text, flags, 'raw')[1] | |
158 |
|
158 | |||
159 |
def _processflagsfunc(self, text, flags, operation |
|
159 | def _processflagsfunc(self, text, flags, operation): | |
160 | # fast path: no flag processors will run |
|
160 | # fast path: no flag processors will run | |
161 | if flags == 0: |
|
161 | if flags == 0: | |
162 | return text, True |
|
162 | return text, True | |
163 |
if not |
|
163 | if operation not in ('read', 'write', 'raw'): | |
164 | raise error.ProgrammingError(_("invalid '%s' operation") % |
|
164 | raise error.ProgrammingError(_("invalid '%s' operation") % | |
165 | operation) |
|
165 | operation) | |
166 | # Check all flags are known. |
|
166 | # Check all flags are known. | |
167 | if flags & ~REVIDX_KNOWN_FLAGS: |
|
167 | if flags & ~REVIDX_KNOWN_FLAGS: | |
168 | raise self._flagserrorclass(_("incompatible revision flag '%#x'") % |
|
168 | raise self._flagserrorclass(_("incompatible revision flag '%#x'") % | |
169 | (flags & ~REVIDX_KNOWN_FLAGS)) |
|
169 | (flags & ~REVIDX_KNOWN_FLAGS)) | |
170 | validatehash = True |
|
170 | validatehash = True | |
171 | # Depending on the operation (read or write), the order might be |
|
171 | # Depending on the operation (read or write), the order might be | |
172 | # reversed due to non-commutative transforms. |
|
172 | # reversed due to non-commutative transforms. | |
173 | orderedflags = REVIDX_FLAGS_ORDER |
|
173 | orderedflags = REVIDX_FLAGS_ORDER | |
174 | if operation == 'write': |
|
174 | if operation == 'write': | |
175 | orderedflags = reversed(orderedflags) |
|
175 | orderedflags = reversed(orderedflags) | |
176 |
|
176 | |||
177 | for flag in orderedflags: |
|
177 | for flag in orderedflags: | |
178 | # If a flagprocessor has been registered for a known flag, apply the |
|
178 | # If a flagprocessor has been registered for a known flag, apply the | |
179 | # related operation transform and update result tuple. |
|
179 | # related operation transform and update result tuple. | |
180 | if flag & flags: |
|
180 | if flag & flags: | |
181 | vhash = True |
|
181 | vhash = True | |
182 |
|
182 | |||
183 | if flag not in self._flagprocessors: |
|
183 | if flag not in self._flagprocessors: | |
184 | message = _("missing processor for flag '%#x'") % (flag) |
|
184 | message = _("missing processor for flag '%#x'") % (flag) | |
185 | raise self._flagserrorclass(message) |
|
185 | raise self._flagserrorclass(message) | |
186 |
|
186 | |||
187 | processor = self._flagprocessors[flag] |
|
187 | processor = self._flagprocessors[flag] | |
188 | if processor is not None: |
|
188 | if processor is not None: | |
189 | readtransform, writetransform, rawtransform = processor |
|
189 | readtransform, writetransform, rawtransform = processor | |
190 |
|
190 | |||
191 | if raw: |
|
191 | if operation == 'raw': | |
192 | vhash = rawtransform(self, text) |
|
192 | vhash = rawtransform(self, text) | |
193 | elif operation == 'read': |
|
193 | elif operation == 'read': | |
194 | text, vhash = readtransform(self, text) |
|
194 | text, vhash = readtransform(self, text) | |
195 | else: # write operation |
|
195 | else: # write operation | |
196 | text, vhash = writetransform(self, text) |
|
196 | text, vhash = writetransform(self, text) | |
197 | validatehash = validatehash and vhash |
|
197 | validatehash = validatehash and vhash | |
198 |
|
198 | |||
199 | return text, validatehash |
|
199 | return text, validatehash |
General Comments 0
You need to be logged in to leave comments.
Login now