<div dir="ltr">On Thu, Sep 20, 2012 at 8:12 PM, <<a href="mailto:pierre-yves.david@logilab.fr">pierre-yves.david@logilab.fr</a>> wrote:<br>><br>> # HG changeset patch<br>> # User Pierre-Yves David <<a href="mailto:pierre-yves.david@logilab.fr">pierre-yves.david@logilab.fr</a>><br>
> # Date 1348160567 -7200<br>> # Node ID 99ab3ca5b10c516485db9be9b8f5f6764ea7c7f7<br>> # Parent  0f55ba7803997843a1e047f9b2fc112e53cabfb3<br>> clfilter: introduce `filteredrevs` attribute on changelog<div><br>
</div><div>You've taken a slightly different approach on how to implement</div><div>this thing than I have here: <a href="http://mercurial.markmail.org/thread/2fv3e2lgqohxle2g">http://mercurial.markmail.org/thread/2fv3e2lgqohxle2g</a></div>
<div><br></div><div>What I liked about the wrapper classes is that it separates the logic</div><div>of the filtering from the base implementations of revlog/changelog.</div><div>As a result that means that if there aren't any filtered revisions then</div>
<div>everything is the same as before (although the call 'x in set' where set</div><div>is empty is probably negligible).</div><div><br></div><div>Any reason you think this is preferable?</div><div><br></div><div>
><br>> This changeset allows changelog object to be "filtered". You can assign a<br>> set of<br>> revision numbers to the `changelog.filteredrevs` attributes. The changelog<br>> will<br>> then pretends these revision does not exists in this repo.<br>
><br>> A few methods need to be altered to achieve this behavior:<br>><br>> - tip<br>> - __iter_<br>> - irevs<br>> - hasnode<br>> - headrevs<br>><br>> For consistency and to help debugging, the following methods are altered<br>
> too.<br>> Tests tend to show it's not necessary to alter them but have them raise<br>> proper<br>> exception helps to detect bad acces to filtered revisions.<br>><br>> - rev<br>> - node<br>> - linkrev<br>
> - parentrevs<br>> - flags<br>><br>> The following methods would also need alteration for consistency purpose<br>> but<br>> this is non-trivial and not done yet.<br>><br>> - nodemap<br>> - strip<br>
><br>> The C version of headrevs is not run if there is any revision to filter.<br>> It'll<br>> need a proper rewrite later to restore performance.<br>><br>> diff --git a/mercurial/changelog.py b/mercurial/changelog.py<br>
> --- a/mercurial/changelog.py<br>> +++ b/mercurial/changelog.py<br>> @@ -7,12 +7,15 @@<br>><br>>  from node import bin, hex, nullid<br>>  from i18n import _<br>>  import util, error, revlog, encoding<br>
><br>> +LookupError = error.LookupError<br>> +<br>>  _defaultextra = {'branch': 'default'}<br>><br>> +<br>>  def _string_escape(text):<br>>      """<br>>      >>> d = {'nl': chr(10), 'bs': chr(92), 'cr': chr(13), 'nul': chr(0)}<br>
>      >>> s = "ab%(nl)scd%(bs)s%(bs)sn%(nul)sab%(cr)scd%(bs)s%(nl)s" % d<br>>      >>> s<br>> @@ -118,10 +121,94 @@ class changelog(revlog.revlog):<br>>              self.version &= ~revlog.REVLOGGENERALDELTA<br>
>              self._generaldelta = False<br>>          self._realopener = opener<br>>          self._delayed = False<br>>          self._divert = False<br>> +        self.filteredrevs = ()<br>> +<br>> +    def tip(self):<br>
> +        """filtered version of revlog.tip"""<br>> +        for i in xrange(len(self) -1, -2, -1):<br>> +            if i not in self.filteredrevs:<br>> +                return self.node(i)<br>
> +<br>> +    def __iter__(self):<br>> +        """filtered version of revlog.__iter__"""<br>> +        for i in xrange(len(self)):<br>> +            if i not in self.filteredrevs:<br>
> +                yield i<br>> +<br>> +    def revs(self, start=0, stop=None):<br>> +        """filtered version of revlog.revs"""<br>> +        for i in super(changelog, self).revs(start, stop):<br>
> +            if i not in self.filteredrevs:<br>> +                yield i<br>> +<br>> +    @util.propertycache<br>> +    def nodemap(self):<br>> +        # XXX need filtering too<br>> +        self.rev(self.node(0))<br>
> +        return self._nodecache<br>> +<br>> +    def hasnode(self, node):<br>> +        """filtered version of revlog.hasnode"""<br>> +        try:<br>> +            i = self.rev(node)<br>
> +            return i not in self.filteredrevs<br>> +        except KeyError:<br>> +            return False<br>> +<br>> +    def headrevs(self):<br>> +        if self.filteredrevs:<br>> +            # XXX we should fix and use the C version<br>
> +            return self._headrevs()<br>> +        return super(changelog, self).headrevs()<br>> +<br>> +    # from there filtered version are not "necessary" but welcome for<br>> +    # consistency<br>
> +    #<br>> +    # We should raise a recognisable exception to display useful message<br>> in the<br>> +    # ui<br>> +    #<br>> +    # class FilteredIndex(IndexError): pass<br>> +<br>> +    def strip(self, *args, **kwargs):<br>
> +        # XXX make something better than assert<br>> +        # We can't expect proper strip behavior if we are filtered.<br>> +        assert not self.filteredrevs<br>> +        super(changelog, self).strip(*args, **kwargs)</div>
<div><br></div><div>Are you sure these errors you're raising below are correct? It seems</div><div>to me that you shouldn't filter out revisions when they're asked for</div><div>explicitly, but rather when one requests to know what is the set of</div>
<div>all revisions in the repository.</div><div><br></div><div>For instance, if the user types `hg log -r 0` and 0 happens to be filtered,</div><div>I think we should still display it rather than saying the revision doesn't</div>
<div>exist.</div><div><br></div><div>> +<br>> +    def rev(self, node):<br>> +        """filtered version of revlog.rev"""<br>> +        r = super(changelog, self).rev(node)<br>> +        if r in self.filteredrevs:<br>
> +            raise LookupError(node, self.indexfile, _('no node'))<br>> +        return r<br>> +<br>> +    def node(self, rev):<br>> +        """filtered version of revlog.node"""<br>
> +        if rev in self.filteredrevs:<br>> +            raise IndexError(rev)<br>> +        return super(changelog, self).node(rev)<br>> +<br>> +    def linkrev(self, rev):<br>> +        """filtered version of revlog.linkrev"""<br>
> +        if rev in self.filteredrevs:<br>> +            raise IndexError(rev)<br>> +        return super(changelog, self).linkrev(rev)<br>> +<br>> +    def parentrevs(self, rev):<br>> +        """filtered version of revlog.parentrevs"""<br>
> +        if rev in self.filteredrevs:<br>> +            raise IndexError(rev)<br>> +        return super(changelog, self).parentrevs(rev)<br>> +<br>> +    def flags(self, rev):<br>> +        """filtered version of revlog.flags"""<br>
> +        if rev in self.filteredrevs:<br>> +            raise IndexError(rev)<br>> +        return super(changelog, self).flags(rev)</div><div>><br>>      def delayupdate(self):<br>>          "delay visibility of index updates to other readers"<br>
>          self._delayed = True<br>>          self._divert = (len(self) == 0)<br>> _______________________________________________<br>> Mercurial-devel mailing list<br>> <a href="mailto:Mercurial-devel@selenic.com">Mercurial-devel@selenic.com</a><br>
> <a href="http://selenic.com/mailman/listinfo/mercurial-devel">http://selenic.com/mailman/listinfo/mercurial-devel</a><br><br></div></div>