[PATCH 5 of 9 hglib] introduce a revset query builder utility

Kevin Bullock kbullock+mercurial at ringworld.org
Fri Jul 29 10:55:41 CDT 2011


On 28 Jul 2011, at 2:58 PM, Idan Kamara wrote:

> # HG changeset patch
> # User Idan Kamara <idankk86 at gmail.com>
> # Date 1311450939 -10800
> # Node ID 1a84d5a142ffe6e40f96cb96f4beb9a346d4fa78
> # Parent  6b7230607731fd92604e77408bd3dd08cf96c916
> introduce a revset query builder utility
> 
> diff -r 6b7230607731 -r 1a84d5a142ff hglib/revset.py
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/hglib/revset.py	Sat Jul 23 22:55:39 2011 +0300
> @@ -0,0 +1,139 @@
> +import hglib
> +
> +def quote(x):
> +    if isinstance(x, (int, revset, hglib.changeset)):
> +        return str(x)
> +    elif isinstance(x, str):
> +        return repr(x)
> +    else:
> +        raise TypeError()
> +
> +def raw(s):
> +    return revset(s)
> +
> +def all():
> +    return revset('all()')
> +
> +def branch(x):
> +    """
> +    >>> branch('foo')
> +    <revset "branch('foo')">
> +    >>> branch('"foo"')
> +    <revset 'branch(\\'"foo"\\')'>
> +    >>> import hglib
> +    >>> branch(hglib.changeset(0, 'abcd', 0, 0, 0, 0))
> +    <revset 'branch(abcd)'>
> +    """
> +    return revset('branch(%s)' % quote(x))
> +
> +def revrange(x=None, y=None):
> +    """
> +    >>> revrange(0, raw('tip'))
> +    <revset '0:tip'>
> +    >>> revrange(raw('tip'), 0)
> +    <revset 'tip:0'>
> +    """
> +    if x is None and y is None:
> +        raise ValueError('must provide at least x or y')
> +    if x and not isinstance(x, (int, revset, hglib.changeset)):
> +        raise TypeError()
> +    if y and not isinstance(y, (int, revset, hglib.changeset)):
> +        raise TypeError()
> +
> +    if y is None:
> +        return revset('%s:' % x)
> +    if x is None:
> +        return revset(':%s' % y)
> +    return revset('%s:%s' % (x, y))
> +
> +def last(n, x=None):
> +    """
> +    >>> last(1)
> +    <revset 'last(all(), 1)'>
> +    >>> last(1, all())
> +    <revset 'last(all(), 1)'>
> +    >>> last(1, branch('default'))
> +    <revset "last(branch('default'), 1)">
> +    """

I don't think switching the order of arguments is a good idea here. The convenience of revset.last(1) without specifying a set would be outweighed by the confusion caused by passing the arguments in the wrong place.

pacem in terris / mir / shanti / salaam / heiwa
Kevin R. Bullock

> +    if x is None:
> +        x = all()
> +    elif not isinstance(x, (int, revset, hglib.changeset)):
> +        raise TypeError()
> +
> +    return revset('last(%s, %d)' % (x, n))
> +
> +def merge():
> +    return revset('merge()')
> +
> +def keyword(s):
> +    """
> +    >>> keyword('a b')
> +    <revset "keyword('a b')">
> +    """
> +    return revset('keyword(%r)' % s)
> +
> +def dagrange(x=None, y=None):
> +    """
> +    >>> dagrange(raw('a'))
> +    <revset 'a::'>
> +    >>> dagrange(y=raw('a'))
> +    <revset '::a'>
> +    >>> dagrange(raw(repr('a b')), raw('c'))
> +    <revset "'a b'::c">
> +    """
> +    if not x and not y:
> +        raise ValueError('must provide at least x or y')
> +    if x and not isinstance(x, (int, revset, hglib.changeset)):
> +        raise TypeError()
> +    if y and not isinstance(y, (int, revset, hglib.changeset)):
> +        raise TypeError()
> +
> +    if not y:
> +        return revset('%s::' % x)
> +    if not x:
> +        return revset('::%s' % y)
> +    return revset('%s::%s' % (x, y))
> +
> +class revset(object):
> +    def __init__(self, s):
> +        self.s = s
> +
> +    def __str__(self):
> +        return self.s
> +
> +    def __repr__(self):
> +        return "<revset %r>" % str(self)
> +
> +    def __xor__(self, n):
> +        """
> +        >>> raw('foo')^2
> +        <revset 'foo^2'>
> +        """
> +        if not isinstance(n, int):
> +            return NotImplemented
> +
> +        return revset('%s^%d' % (self, n))
> +
> +    def __invert__(self):
> +        """
> +        >>> ~branch('foo')
> +        <revset "not branch('foo')">
> +        >>> branch('foo') & ~branch('foo')
> +        <revset "(branch('foo') and not branch('foo'))">
> +        """
> +        return revset('not %s' % self)
> +
> +    def __and__(self, other):
> +        """
> +        >>> branch('foo') & (branch('bar') & branch('foobar'))
> +        <revset "(branch('foo') and (branch('bar') and branch('foobar')))">
> +        >>> (branch('foo') & branch('bar')) & branch('foobar')
> +        <revset "((branch('foo') and branch('bar')) and branch('foobar'))">
> +        """
> +        return revset('(%s and %s)' % (self.s, other.s))
> +
> +    def __or__(self, other):
> +        return revset('(%s or %s)' % (self.s, other.s))
> +
> +    def __sub__(self, other):
> +        return revset('(%s - %s)' % (self.s, other.s))
> diff -r 6b7230607731 -r 1a84d5a142ff tests/test-revset.py
> --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
> +++ b/tests/test-revset.py	Sat Jul 23 22:55:39 2011 +0300
> @@ -0,0 +1,59 @@
> +import common
> +from hglib import hglib, error, revset as rs
> +
> +class test_revset(common.basetest):
> +    def test_log(self):
> +        """emulate various options to log using revsets"""
> +        self.append('a', 'a')
> +        rev0 = self.client.commit('first', addremove=True)
> +        self.append('a', 'a')
> +        rev1 = self.client.commit('second')
> +        self.client.branch('foo')
> +        self.append('a', 'a')
> +        rev2 = self.client.commit('third')
> +
> +        # -b/--branch
> +        self.assertEquals(self.client.log(rs.branch('default')), [rev0, rev1])
> +        self.assertEquals(self.client.log(rs.branch('foo')), [rev2])
> +
> +        # log -b default -b foo
> +        r = rs.branch('default') | rs.branch('foo')
> +        self.assertEquals(self.client.log(r), [rev0, rev1, rev2])
> +
> +        # log -b default -l 1
> +        r = rs.last(1, rs.branch('default'))
> +        self.assertEquals(self.client.log(r), [rev1])
> +
> +        # log -b default -b foo -l 1
> +        r = rs.last(1, rs.branch('default') | rs.branch('foo'))
> +        self.assertEquals(self.client.log(r), [rev2])
> +
> +        # -M/--no-merges
> +        r = ~rs.merge()
> +        self.assertEquals(self.client.log(r), [rev0, rev1, rev2])
> +
> +        # -m/--only-merges
> +        r = rs.merge()
> +        self.assertEquals(self.client.log(r), [])
> +
> +        # -k/--keyword
> +        r = rs.keyword('a')
> +        self.assertEquals(self.client.log(r), [rev0, rev1, rev2])
> +
> +    def test_quoting(self):
> +        s = "spaces and 'q'uotes"
> +        self.client.branch(s)
> +        self.append('a', 'a')
> +        rev0 = self.client.commit('first', addremove=True)
> +        self.assertEquals(rev0.branch, s)
> +        self.assertEquals(self.client.log(rs.branch(s)), [rev0])
> +
> +        self.client.branch('default')
> +        self.append('a', 'a')
> +        rev1 = self.client.commit('second')
> +
> +        r = rs.revrange(0, rs.branch(s))
> +        self.assertEquals(self.client.log(r), [rev0])
> +
> +        r = rs.revrange(0, rs.branch(s) | rs.branch(s))
> +        self.assertEquals(self.client.log(r), [rev0])
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel



More information about the Mercurial-devel mailing list