[PATCH 5 of 9 hglib] introduce a revset query builder utility
Idan Kamara
idankk86 at gmail.com
Thu Jul 28 14:58:58 CDT 2011
# 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)">
+ """
+ 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])
More information about the Mercurial-devel
mailing list