flagutil.py
192 lines
| 7.3 KiB
| text/x-python
|
PythonLexer
r42954 | # flagutils.py - code to deal with revlog flags and their processors | |||
# | ||||
# Copyright 2016 Remi Chaintron <remi@fb.com> | ||||
# Copyright 2016-2019 Pierre-Yves David <pierre-yves.david@ens-lyon.org> | ||||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | ||||
from __future__ import absolute_import | ||||
r42957 | from ..i18n import _ | |||
r42954 | from .constants import ( | |||
REVIDX_DEFAULT_FLAGS, | ||||
REVIDX_ELLIPSIS, | ||||
REVIDX_EXTSTORED, | ||||
REVIDX_FLAGS_ORDER, | ||||
REVIDX_ISCENSORED, | ||||
REVIDX_RAWTEXT_CHANGING_FLAGS, | ||||
r43305 | REVIDX_SIDEDATA, | |||
r42954 | ) | |||
Augie Fackler
|
r43346 | from .. import error, util | ||
r42956 | ||||
r42954 | # blanked usage of all the name to prevent pyflakes constraints | |||
# We need these name available in the module for extensions. | ||||
REVIDX_ISCENSORED | ||||
REVIDX_ELLIPSIS | ||||
REVIDX_EXTSTORED | ||||
r43305 | REVIDX_SIDEDATA | |||
r42954 | REVIDX_DEFAULT_FLAGS | |||
REVIDX_FLAGS_ORDER | ||||
REVIDX_RAWTEXT_CHANGING_FLAGS | ||||
r42956 | REVIDX_KNOWN_FLAGS = util.bitsfrom(REVIDX_FLAGS_ORDER) | |||
r42955 | # Store flag processors (cf. 'addflagprocessor()' to register) | |||
flagprocessors = { | ||||
REVIDX_ISCENSORED: None, | ||||
} | ||||
r42954 | ||||
Augie Fackler
|
r43346 | |||
r42958 | def addflagprocessor(flag, processor): | |||
"""Register a flag processor on a revision data flag. | ||||
Invariant: | ||||
- Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER, | ||||
and REVIDX_RAWTEXT_CHANGING_FLAGS if they can alter rawtext. | ||||
- Only one flag processor can be registered on a specific flag. | ||||
- flagprocessors must be 3-tuples of functions (read, write, raw) with the | ||||
following signatures: | ||||
- (read) f(self, rawtext) -> text, bool | ||||
- (write) f(self, text) -> rawtext, bool | ||||
- (raw) f(self, rawtext) -> bool | ||||
"text" is presented to the user. "rawtext" is stored in revlog data, not | ||||
directly visible to the user. | ||||
The boolean returned by these transforms is used to determine whether | ||||
the returned text can be used for hash integrity checking. For example, | ||||
if "write" returns False, then "text" is used to generate hash. If | ||||
"write" returns True, that basically means "rawtext" returned by "write" | ||||
should be used to generate hash. Usually, "write" and "read" return | ||||
different booleans. And "raw" returns a same boolean as "write". | ||||
Note: The 'raw' transform is used for changegroup generation and in some | ||||
debug commands. In this case the transform only indicates whether the | ||||
contents can be used for hash integrity checks. | ||||
""" | ||||
insertflagprocessor(flag, processor, flagprocessors) | ||||
Augie Fackler
|
r43346 | |||
r42957 | def insertflagprocessor(flag, processor, flagprocessors): | |||
if not flag & REVIDX_KNOWN_FLAGS: | ||||
Augie Fackler
|
r43347 | msg = _(b"cannot register processor on unknown flag '%#x'.") % flag | ||
r42957 | raise error.ProgrammingError(msg) | |||
if flag not in REVIDX_FLAGS_ORDER: | ||||
Augie Fackler
|
r43347 | msg = _(b"flag '%#x' undefined in REVIDX_FLAGS_ORDER.") % flag | ||
r42957 | raise error.ProgrammingError(msg) | |||
if flag in flagprocessors: | ||||
Augie Fackler
|
r43347 | msg = _(b"cannot register multiple processors on flag '%#x'.") % flag | ||
r42957 | raise error.Abort(msg) | |||
flagprocessors[flag] = processor | ||||
r43140 | ||||
Augie Fackler
|
r43346 | |||
r43260 | def processflagswrite(revlog, text, flags, sidedata): | |||
"""Inspect revision data flags and applies write transformations defined | ||||
by registered flag processors. | ||||
``text`` - the revision data to process | ||||
``flags`` - the revision flags | ||||
This method processes the flags in the order (or reverse order if | ||||
``operation`` is 'write') defined by REVIDX_FLAGS_ORDER, applying the | ||||
flag processors registered for present flags. The order of flags defined | ||||
in REVIDX_FLAGS_ORDER needs to be stable to allow non-commutativity. | ||||
Returns a 2-tuple of ``(text, validatehash)`` where ``text`` is the | ||||
processed text and ``validatehash`` is a bool indicating whether the | ||||
returned text should be checked for hash integrity. | ||||
""" | ||||
Augie Fackler
|
r43347 | return _processflagsfunc(revlog, text, flags, b'write', sidedata=sidedata)[ | ||
Augie Fackler
|
r43346 | :2 | ||
] | ||||
r43260 | ||||
r43261 | def processflagsread(revlog, text, flags): | |||
"""Inspect revision data flags and applies read transformations defined | ||||
by registered flag processors. | ||||
``text`` - the revision data to process | ||||
``flags`` - the revision flags | ||||
``raw`` - an optional argument describing if the raw transform should be | ||||
applied. | ||||
This method processes the flags in the order (or reverse order if | ||||
``operation`` is 'write') defined by REVIDX_FLAGS_ORDER, applying the | ||||
flag processors registered for present flags. The order of flags defined | ||||
in REVIDX_FLAGS_ORDER needs to be stable to allow non-commutativity. | ||||
Returns a 2-tuple of ``(text, validatehash)`` where ``text`` is the | ||||
processed text and ``validatehash`` is a bool indicating whether the | ||||
returned text should be checked for hash integrity. | ||||
""" | ||||
Augie Fackler
|
r43347 | return _processflagsfunc(revlog, text, flags, b'read') | ||
r43261 | ||||
Augie Fackler
|
r43346 | |||
r43262 | def processflagsraw(revlog, text, flags): | |||
"""Inspect revision data flags to check is the content hash should be | ||||
validated. | ||||
``text`` - the revision data to process | ||||
``flags`` - the revision flags | ||||
This method processes the flags in the order (or reverse order if | ||||
``operation`` is 'write') defined by REVIDX_FLAGS_ORDER, applying the | ||||
flag processors registered for present flags. The order of flags defined | ||||
in REVIDX_FLAGS_ORDER needs to be stable to allow non-commutativity. | ||||
Returns a 2-tuple of ``(text, validatehash)`` where ``text`` is the | ||||
processed text and ``validatehash`` is a bool indicating whether the | ||||
returned text should be checked for hash integrity. | ||||
""" | ||||
Augie Fackler
|
r43347 | return _processflagsfunc(revlog, text, flags, b'raw')[1] | ||
r43262 | ||||
Augie Fackler
|
r43346 | |||
r43259 | def _processflagsfunc(revlog, text, flags, operation, sidedata=None): | |||
"""internal function to process flag on a revlog | ||||
r43144 | ||||
r43259 | This function is private to this module, code should never needs to call it | |||
directly.""" | ||||
# fast path: no flag processors will run | ||||
if flags == 0: | ||||
return text, True, {} | ||||
Augie Fackler
|
r43347 | if operation not in (b'read', b'write', b'raw'): | ||
raise error.ProgrammingError(_(b"invalid '%s' operation") % operation) | ||||
r43259 | # Check all flags are known. | |||
if flags & ~REVIDX_KNOWN_FLAGS: | ||||
Augie Fackler
|
r43346 | raise revlog._flagserrorclass( | ||
Augie Fackler
|
r43347 | _(b"incompatible revision flag '%#x'") | ||
Augie Fackler
|
r43346 | % (flags & ~REVIDX_KNOWN_FLAGS) | ||
) | ||||
r43259 | validatehash = True | |||
# Depending on the operation (read or write), the order might be | ||||
# reversed due to non-commutative transforms. | ||||
orderedflags = REVIDX_FLAGS_ORDER | ||||
Augie Fackler
|
r43347 | if operation == b'write': | ||
r43259 | orderedflags = reversed(orderedflags) | |||
r43140 | ||||
r43259 | outsidedata = {} | |||
for flag in orderedflags: | ||||
# If a flagprocessor has been registered for a known flag, apply the | ||||
# related operation transform and update result tuple. | ||||
if flag & flags: | ||||
vhash = True | ||||
r43140 | ||||
r43259 | if flag not in revlog._flagprocessors: | |||
Augie Fackler
|
r43347 | message = _(b"missing processor for flag '%#x'") % flag | ||
r43259 | raise revlog._flagserrorclass(message) | |||
r43140 | ||||
r43259 | processor = revlog._flagprocessors[flag] | |||
if processor is not None: | ||||
readtransform, writetransform, rawtransform = processor | ||||
r43140 | ||||
Augie Fackler
|
r43347 | if operation == b'raw': | ||
r43259 | vhash = rawtransform(revlog, text) | |||
Augie Fackler
|
r43347 | elif operation == b'read': | ||
r43259 | text, vhash, s = readtransform(revlog, text) | |||
outsidedata.update(s) | ||||
Augie Fackler
|
r43346 | else: # write operation | ||
r43259 | text, vhash = writetransform(revlog, text, sidedata) | |||
validatehash = validatehash and vhash | ||||
r43140 | ||||
r43259 | return text, validatehash, outsidedata | |||