[PATCH 2 of 5 filtering part 2 V2] clfilter: add actual repo filtering mechanism
pierre-yves.david at logilab.fr
pierre-yves.david at logilab.fr
Mon Dec 10 11:30:22 CST 2012
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at ens-lyon.org>
# Date 1355157839 -3600
# Node ID 5a3d1c83343b403cf1e1393cdf2dde4f8512309b
# Parent 9280d7beadd6f38c8623ea3137f2028c57cc349c
clfilter: add actual repo filtering mechanism
We add a `filtered` method on repo. This method return instance of `repoproxy`
that behave exactly as the original repository but with a filtered changelog
attribute. Filter are identified by a "name". Planed filter are `unserved`,
`hidden` and `mutable`. See the `repoproxier` docstring for details.
Mechanism to compute filtered revision are also installed. 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
@@ -13,10 +13,11 @@ import scmutil, util, extensions, hook,
import match as matchmod
import merge as mergemod
import tags as tagsmod
from lock import release
import weakref, errno, os, time, inspect
+import copy
propertycache = util.propertycache
filecache = scmutil.filecache
class repofilecache(filecache):
"""All filecache usage on repo are done for logic that should be unfiltered
@@ -55,10 +56,73 @@ def unfilteredmethod(orig):
"""decorate method that always need to be run on unfiltered version"""
def wrapper(repo, *args, **kwargs):
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 repoproxy(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."""
+
+ def __init__(self, repo, filtername):
+ object.__setattr__(self, '_unfilteredrepo', repo)
+ object.__setattr__(self, 'filtername', filtername)
+
+ # not a cacheproperty on purpose we shall implement a proper cache later
+ @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` attribut is initialiazed during __init__. But
+ # __getattr__ won't be called as it also exists on the class. We need
+ # explicit 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']))
class localpeer(peer.peerrepository):
'''peer for a local repo; reflects only the most recent API'''
@@ -301,10 +365,18 @@ class localrepository(object):
"""Return unfiltered version of the repository
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(repoproxy, self.unfiltered().__class__):
+ pass
+ return proxycls(self, name)
+
@repofilecache('bookmarks')
def _bookmarks(self):
return bookmarks.bmstore(self)
@repofilecache('bookmarks.current')
More information about the Mercurial-devel
mailing list