[PATCH 8 of 8 clfilter-part1] clfilter: introduce `filteredrevs` attribute on changelog

Idan Kamara idankk86 at gmail.com
Thu Sep 20 12:51:46 CDT 2012


On Thu, Sep 20, 2012 at 8:12 PM, <pierre-yves.david at logilab.fr> wrote:
>
> # HG changeset patch
> # User Pierre-Yves David <pierre-yves.david at logilab.fr>
> # Date 1348160567 -7200
> # Node ID 99ab3ca5b10c516485db9be9b8f5f6764ea7c7f7
> # Parent  0f55ba7803997843a1e047f9b2fc112e53cabfb3
> clfilter: introduce `filteredrevs` attribute on changelog

You've taken a slightly different approach on how to implement
this thing than I have here:
http://mercurial.markmail.org/thread/2fv3e2lgqohxle2g

What I liked about the wrapper classes is that it separates the logic
of the filtering from the base implementations of revlog/changelog.
As a result that means that if there aren't any filtered revisions then
everything is the same as before (although the call 'x in set' where set
is empty is probably negligible).

Any reason you think this is preferable?

>
> This changeset allows changelog object to be "filtered". You can assign a
> set of
> revision numbers to the `changelog.filteredrevs` attributes. The changelog
> will
> then pretends these revision does not exists in this repo.
>
> A few methods need to be altered to achieve this behavior:
>
> - tip
> - __iter_
> - irevs
> - hasnode
> - headrevs
>
> For consistency and to help debugging, the following methods are altered
> too.
> Tests tend to show it's not necessary to alter them but have them raise
> proper
> exception helps to detect bad acces to filtered revisions.
>
> - rev
> - node
> - linkrev
> - parentrevs
> - flags
>
> The following methods would also need alteration for consistency purpose
> but
> this is non-trivial and not done yet.
>
> - nodemap
> - strip
>
> The C version of headrevs is not run if there is any revision to filter.
> It'll
> need a proper rewrite later to restore performance.
>
> diff --git a/mercurial/changelog.py b/mercurial/changelog.py
> --- a/mercurial/changelog.py
> +++ b/mercurial/changelog.py
> @@ -7,12 +7,15 @@
>
>  from node import bin, hex, nullid
>  from i18n import _
>  import util, error, revlog, encoding
>
> +LookupError = error.LookupError
> +
>  _defaultextra = {'branch': 'default'}
>
> +
>  def _string_escape(text):
>      """
>      >>> d = {'nl': chr(10), 'bs': chr(92), 'cr': chr(13), 'nul': chr(0)}
>      >>> s = "ab%(nl)scd%(bs)s%(bs)sn%(nul)sab%(cr)scd%(bs)s%(nl)s" % d
>      >>> s
> @@ -118,10 +121,94 @@ class changelog(revlog.revlog):
>              self.version &= ~revlog.REVLOGGENERALDELTA
>              self._generaldelta = False
>          self._realopener = opener
>          self._delayed = False
>          self._divert = False
> +        self.filteredrevs = ()
> +
> +    def tip(self):
> +        """filtered version of revlog.tip"""
> +        for i in xrange(len(self) -1, -2, -1):
> +            if i not in self.filteredrevs:
> +                return self.node(i)
> +
> +    def __iter__(self):
> +        """filtered version of revlog.__iter__"""
> +        for i in xrange(len(self)):
> +            if i not in self.filteredrevs:
> +                yield i
> +
> +    def revs(self, start=0, stop=None):
> +        """filtered version of revlog.revs"""
> +        for i in super(changelog, self).revs(start, stop):
> +            if i not in self.filteredrevs:
> +                yield i
> +
> +    @util.propertycache
> +    def nodemap(self):
> +        # XXX need filtering too
> +        self.rev(self.node(0))
> +        return self._nodecache
> +
> +    def hasnode(self, node):
> +        """filtered version of revlog.hasnode"""
> +        try:
> +            i = self.rev(node)
> +            return i not in self.filteredrevs
> +        except KeyError:
> +            return False
> +
> +    def headrevs(self):
> +        if self.filteredrevs:
> +            # XXX we should fix and use the C version
> +            return self._headrevs()
> +        return super(changelog, self).headrevs()
> +
> +    # from there filtered version are not "necessary" but welcome for
> +    # consistency
> +    #
> +    # We should raise a recognisable exception to display useful message
> in the
> +    # ui
> +    #
> +    # class FilteredIndex(IndexError): pass
> +
> +    def strip(self, *args, **kwargs):
> +        # XXX make something better than assert
> +        # We can't expect proper strip behavior if we are filtered.
> +        assert not self.filteredrevs
> +        super(changelog, self).strip(*args, **kwargs)

Are you sure these errors you're raising below are correct? It seems
to me that you shouldn't filter out revisions when they're asked for
explicitly, but rather when one requests to know what is the set of
all revisions in the repository.

For instance, if the user types `hg log -r 0` and 0 happens to be filtered,
I think we should still display it rather than saying the revision doesn't
exist.

> +
> +    def rev(self, node):
> +        """filtered version of revlog.rev"""
> +        r = super(changelog, self).rev(node)
> +        if r in self.filteredrevs:
> +            raise LookupError(node, self.indexfile, _('no node'))
> +        return r
> +
> +    def node(self, rev):
> +        """filtered version of revlog.node"""
> +        if rev in self.filteredrevs:
> +            raise IndexError(rev)
> +        return super(changelog, self).node(rev)
> +
> +    def linkrev(self, rev):
> +        """filtered version of revlog.linkrev"""
> +        if rev in self.filteredrevs:
> +            raise IndexError(rev)
> +        return super(changelog, self).linkrev(rev)
> +
> +    def parentrevs(self, rev):
> +        """filtered version of revlog.parentrevs"""
> +        if rev in self.filteredrevs:
> +            raise IndexError(rev)
> +        return super(changelog, self).parentrevs(rev)
> +
> +    def flags(self, rev):
> +        """filtered version of revlog.flags"""
> +        if rev in self.filteredrevs:
> +            raise IndexError(rev)
> +        return super(changelog, self).flags(rev)
>
>      def delayupdate(self):
>          "delay visibility of index updates to other readers"
>          self._delayed = True
>          self._divert = (len(self) == 0)
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://selenic.com/pipermail/mercurial-devel/attachments/20120920/9a7f10e6/attachment.html>


More information about the Mercurial-devel mailing list