# HG changeset patch
# User Remi Chaintron <r...@fb.com>
# Date 1482596881 18000
#      Sat Dec 24 11:28:01 2016 -0500
# Node ID c94d2907a470ca03b4a4a8da514b66d2f8952bce
# Parent  b1d220e584e6fc861a40a5aeefa0c3b19ae09126
revlog: processflags()

diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py
--- a/mercurial/bundlerepo.py
+++ b/mercurial/bundlerepo.py
@@ -148,7 +148,9 @@
             delta = self._chunk(chain.pop())
             text = mdiff.patches(text, [delta])
 
-        self.checkhash(text, node, rev=rev)
+        text, validatehash = self.processflags(text, self.flags(rev), raw=raw)
+        if validatehash is True:
+            self.checkhash(text, node, rev=rev)
         self._cache = (node, rev, text)
         return text
 
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -56,6 +56,10 @@
 REVIDX_ISCENSORED = (1 << 15) # revision has censor metadata, must be verified
 REVIDX_DEFAULT_FLAGS = 0
 REVIDX_KNOWN_FLAGS = REVIDX_ISCENSORED
+# stable order in which flags need to be processed and their transforms applied
+REVIDX_FLAGS_ORDER = [
+    REVIDX_ISCENSORED,
+]
 
 # max size of revlog with inline data
 _maxinline = 131072
@@ -65,6 +69,33 @@
 LookupError = error.LookupError
 CensoredNodeError = error.CensoredNodeError
 
+# 'flagtransform' namedtuple type for extensions to use to register transforms
+# on revlog flags.
+# - The apply transform will be used as a default behavior.
+# - The applyraw transform will be used for changegroup generation and debug
+# methods.
+flagtransform = collections.namedtuple('flagtransform', ['apply', 'applyraw'])
+# Store flag transforms (cf. 'addflagtransform()' to register)
+_flagtransforms = { }
+
+def addflagtransform(flag, transform):
+    """Register transforms on revision data flags.
+
+    Invariant:
+    - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER.
+    - Only one transform can be registered on a specific flag.
+    - the transform must be of type 'flagtransform'
+    """
+    if not flag & REVIDX_KNOWN_FLAGS:
+        raise error.Abort(_("cannot register transform on unknown flag."))
+    if not flag in REVIDX_FLAGS_ORDER:
+        raise error.Abort(_("flag need to be defined in REVIDX_FLAGS_ORDER."))
+    if _flagtransforms.get(flag, None) is not None:
+        raise error.Abort(_("cannot register multiple transforms on flag."))
+    if not isinstance(transform, flagtransform):
+        raise error.Abort(_("invalid transform type."))
+    _flagtransforms[flag] = transform
+
 def getoffset(q):
     return int(q >> 16)
 
@@ -1248,7 +1279,11 @@
             bins = bins[1:]
 
         text = mdiff.patches(text, bins)
-        self.checkhash(text, node, rev=rev)
+
+        text, validatehash = self.processflags(text, self.flags(rev), raw=raw)
+        if validatehash:
+            self.checkhash(text, node, rev=rev)
+
         self._cache = (node, rev, text)
         return text
 
@@ -1260,6 +1295,56 @@
         """
         return hash(text, p1, p2)
 
+    def processflags(self, text, flags, raw=False, reverse=False):
+        """Process revision flags and apply registered transforms.
+
+        ``text`` - the revision data to process
+        ``flags`` - the revision flags
+        ``raw`` - an optional argument describing if the raw transform should 
be
+        applied.
+        ``reverse`` - an optional argument describing whether the flags should
+        be processed in order or reverse order.
+
+        This method processes the flags in the order (or reverse order if
+        ``reverse`` is False) defined by REVIDX_FLAGS_ORDER, applying the
+        transforms registered for present flags. The order of flags defined in
+        REVIDX_FLAGS_ORDER needs to be stable for non-commutative
+        operations.
+
+        If a ``flagtransform`` namedtuple has been registered on a flag, the
+        ``raw`` argument is used to determine which transform apply. If ``raw``
+        is True, the ``applyraw`` field is used, ``apply`` if not (default).
+        If the ``raw`` argument is set, it indicates we are currently 
processing
+        flags in the context of changegroup generation or debug commands.
+
+        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.
+        """
+        # Check all flags are known.
+        if flags & ~REVIDX_KNOWN_FLAGS:
+            raise RevlogError(_('incompatible revision flag %x') %
+                              (flags & ~REVIDX_KNOWN_FLAGS))
+        validatehash = True
+        # Depending on the operation (read or write), the order might be
+        # reversed due to non-commutative transforms.
+        orderedflags = REVIDX_FLAGS_ORDER
+        if reverse:
+            orderedflags = reversed(orderedflags)
+
+        for flag in orderedflags:
+            # If a transform has been registered for a known flag, apply and
+            # update result tuple.
+            if flag & flags:
+                transform = _flagtransforms.get(flag, None)
+                if transform is not None:
+                    apply, applyraw = transform
+                    f = apply
+                    if raw:
+                        f = applyraw
+                    text, validatehash = f(self, text)
+        return text, validatehash
+
     def checkhash(self, text, node, p1=None, p2=None, rev=None):
         """Check node hash integrity.
 
@@ -1447,7 +1532,11 @@
                 btext[0] = mdiff.patch(basetext, delta)
 
             try:
-                self.checkhash(btext[0], node, p1=p1, p2=p2)
+                btext[0], validatehash = self.processflags(btext[0], flags,
+                                                           raw=raw,
+                                                           reverse=True)
+                if validatehash is True:
+                    self.checkhash(btext[0], node, p1=p1, p2=p2)
                 if flags & REVIDX_ISCENSORED:
                     raise RevlogError(_('node %s is not censored') % node)
             except CensoredNodeError:
_______________________________________________
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

Reply via email to