[PATCH 3 of 4 V2] changelog: prefilter in headrevs()

Georges Racinet georges.racinet at octobus.net
Wed Feb 13 06:47:56 EST 2019


# HG changeset patch
# User Georges Racinet <georges.racinet at octobus.net>
# Date 1547815081 -3600
#      Fri Jan 18 13:38:01 2019 +0100
# Node ID eae29e210636ee44851e0caa385097a090c60af8
# Parent  956c5b54b4ce3e8decf5243a7f73c6f9a06f1229
# EXP-Topic revset.predicates
changelog: prefilter in headrevs()

In case where headrevs() is called on some revisions, we perform
the check that aren't filtered in advance, and switch revlog to
use its unchecked form.

This allows to work with alternative implementations that don't have knowledge
of the filtering system, such as the Rust one.

diff -r 956c5b54b4ce -r eae29e210636 mercurial/changelog.py
--- a/mercurial/changelog.py	Thu Jan 10 18:25:18 2019 +0100
+++ b/mercurial/changelog.py	Fri Jan 18 13:38:01 2019 +0100
@@ -22,6 +22,7 @@
     error,
     pycompat,
     revlog,
+    util,
 )
 from .utils import (
     dateutil,
@@ -350,6 +351,40 @@
     def reachableroots(self, minroot, heads, roots, includepath=False):
         return self.index.reachableroots2(minroot, heads, roots, includepath)
 
+    def _checknofilteredgenrevs(self, revs):
+        """rewrap 'revs' generator to include check for filtered revisions
+
+        This does not consume the incoming generator.
+        """
+        filteredrevs = self.filteredrevs
+        for r in revs:
+            if r in filteredrevs:
+                raise error.FilteredIndexError(r)
+            yield r
+
+    def _checknofilteredinrevs(self, revs):
+        """raise the appropriate error if 'revs' contains a filtered revision
+
+        This returns a version of 'revs' to be used by the caller, that works
+        for all cases, including lazy ones
+        """
+        safehasattr = util.safehasattr
+        if safehasattr(revs, '__next__'):
+            # Note that inspect.isgenerator() is not true for iterators,
+            # and that calling even implicitely iter() on a iterator does not
+            # clone it
+            return self._checknofilteredgenrevs(revs)
+
+        filteredrevs = self.filteredrevs
+        if safehasattr(revs, 'first'):  # smartset
+            offenders = revs & filteredrevs
+        else:
+            offenders = filteredrevs.intersection(revs)
+
+        for rev in offenders:
+            raise error.FilteredIndexError(rev)
+        return revs
+
     def headrevs(self, revs=None):
         if revs is None and self.filteredrevs:
             try:
@@ -359,6 +394,8 @@
             except AttributeError:
                 return self._headrevs()
 
+        if self.filteredrevs:
+            revs = self._checknofilteredinrevs(revs)
         return super(changelog, self).headrevs(revs)
 
     def strip(self, *args, **kwargs):
diff -r 956c5b54b4ce -r eae29e210636 mercurial/revlog.py
--- a/mercurial/revlog.py	Thu Jan 10 18:25:18 2019 +0100
+++ b/mercurial/revlog.py	Fri Jan 18 13:38:01 2019 +0100
@@ -1121,7 +1121,7 @@
                 return self.index.headrevs()
             except AttributeError:
                 return self._headrevs()
-        return dagop.headrevs(revs, self.parentrevs)
+        return dagop.headrevs(revs, self._uncheckedparentrevs)
 
     def computephases(self, roots):
         return self.index.computephasesmapsets(roots)


More information about the Mercurial-devel mailing list