[PATCH 20 of 27 clfilter V2] clfilter: add actual repo filtering mechanism

Pierre-Yves David pierre-yves.david at ens-lyon.org
Mon Oct 8 16:38:11 CDT 2012


# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at ens-lyon.org>
# Date 1349719836 -7200
# Node ID d0ef65c1a9eb2569ba3333ee88edea6cb2bfafaf
# Parent  73f596129126bb5a6ffdde2394720d0ea5aae798
clfilter: add actual repo filtering mechanism

We add a `filtered` method on repo. This method return instance for
`repoproxier` that behave exactly as the original repository but with a filtered
changelog class. Filter are identified by a "name". Planed filter are "unserved"
and "hidden".

Mecanism to compute filtered revision are also installed.

The `repoproxier` docstring for details.

Some cache will be installed in later commit.

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -15,6 +15,7 @@
 import tags as tagsmod
 from lock import release
 import weakref, errno, os, time, inspect
+import copy
 propertycache = util.propertycache
 filecache = scmutil.filecache
 
@@ -56,6 +57,71 @@
         return orig(repo.unfiltered(), *args, **kwargs)
     return wrapper
 
+# function to compute filtered set
+computefiltered = {}
+
+def _filteredrevs(repo, filtername):
+    """returns set of filtered revision for this filter name"""
+    return computefiltered[filtername](repo.unfiltered())
+
+class repoproxier(object):
+    """Changelog filterered localrepo proxy object
+
+    This object act is a proxy for attribute operation. setattr is done on the
+    initial repo, getattr is get from the parent (unless defined on proxy) and
+    delattr operate on proxied repo.
+
+    The changelog attribute is overridden to return a copy of the original
+    changelog but with some revision filtered.
+
+    You have to mix this class with the actual localrepo subclass to be able to
+    use the very same logic than the proxied repo. See `filtered` method of
+    local repo for details.
+
+    This class is meant to be mixed with locarepo subclass"""
+
+    def __init__(self, repo, filtername):
+        object.__setattr__(self, '_unfilteredrepo', repo)
+        object.__setattr__(self, 'filtername', filtername)
+
+    # not a cacheproperty on purpose
+    @property
+    def changelog(self):
+        """return a filtered version of the changeset
+
+        this changelog must not be used for writing"""
+        # some cache may be implemented later
+        cl = copy.copy(self._unfilteredrepo.changelog)
+        cl.filteredrevs = _filteredrevs(self._unfilteredrepo, self.filtername)
+        return cl
+
+    def unfiltered(self):
+        """Return an unfiltered version of a repo"""
+        return self._unfilteredrepo
+
+    def filtered(self, name):
+        """Return a filtered version of a repository"""
+        if name == self.filtername:
+            return self
+        return self.unfiltered().filtered(name)
+
+    # everything access are forwarded to the proxied repo
+    def __getattr__(self, attr):
+        return getattr(self._unfilteredrepo, attr)
+
+    def __setattr__(self, attr, value):
+        return setattr(self._unfilteredrepo, attr, value)
+
+    def __delattr__(self, attr):
+        return delattr(self._unfilteredrepo, attr)
+
+    # The `requirement` but is initialiazed during __init__. But __getattr__
+    # won't be called as it also exists on the class. We need explicite
+    # forwarding to main repo here
+    @property
+    def requirements(self):
+        return self._unfilteredrepo.requirements
+
 MODERNCAPS = set(('lookup', 'branchmap', 'pushkey', 'known', 'getbundle'))
 LEGACYCAPS = MODERNCAPS.union(set(['changegroupsubset']))
 
@@ -302,6 +368,14 @@
         Intended to be ovewritten by filtered repo."""
         return self
 
+    def filtered(self, name):
+        """Return a filtered version of a repository"""
+        # build a new class with the mixin and the current class
+        # (possibily subclass of the repo)
+        class proxycls(repoproxier, self.unfiltered().__class__):
+            pass
+        return proxycls(self, name)
+
     @repofilecache('bookmarks')
     def _bookmarks(self):
         return bookmarks.read(self)


More information about the Mercurial-devel mailing list