[PATCH V6] revset: support ranges in #generations relation
Anton Shestakov
av6 at dwimlabs.net
Fri Jan 18 09:56:33 UTC 2019
# HG changeset patch
# User Anton Shestakov <av6 at dwimlabs.net>
# Date 1547564229 -28800
# Tue Jan 15 22:57:09 2019 +0800
# Node ID 6069a3fcef9b0f9e80cd884c38f6a9e2a35e757a
# Parent 8aca89a694d4bd7d25877b3652fb83e187ea1802
revset: support ranges in #generations relation
diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -225,24 +225,99 @@ def notset(repo, subset, x, order):
def relationset(repo, subset, x, y, order):
raise error.ParseError(_("can't use a relation in this context"))
-def generationsrel(repo, subset, x, rel, n, order):
- # TODO: support range, rewrite tests, and drop startdepth argument
- # from ancestors() and descendants() predicates
- if n <= 0:
- n = -n
- return _ancestors(repo, subset, x, startdepth=n, stopdepth=n + 1)
- else:
- return _descendants(repo, subset, x, startdepth=n, stopdepth=n + 1)
+def _splitrange(a, b):
+ """ Split range with bounds a and b into two ranges at 0 and return two
+ lists of numbers for use as startdepth and stopdepth arguments of
+ _ancestors and _descendants.
+
+ If 0 is in the input range, it is included only once to avoid calling both
+ _ancestors and _descendants if possible.
+
+ >>> _splitrange(None, None) # [:]
+ ([1, None], [0, None])
+ >>> _splitrange(-10, None) # [-10:]
+ ([1, 11], [0, None])
+ >>> _splitrange(None, 10) # [:10]
+ ([1, None], [0, 11])
+ >>> _splitrange(-10, -5) # [-10:-5]
+ ([5, 11], [None, None])
+ >>> _splitrange(5, 10) # [5:10]
+ ([None, None], [5, 11])
+ >>> _splitrange(-10, 10) # [-10:10]
+ ([1, 11], [0, 11])
+ >>> _splitrange(-10, 0) # [-10:0]
+ ([0, 11], [None, None])
+ >>> _splitrange(0, 10) # [0:10]
+ ([None, None], [0, 11])
+ >>> _splitrange(0, 0) # [0:0]
+ ([None, None], [0, 1])
+ >>> _splitrange(1, -1) # [1:-1]
+ ([None, None], [None, None])
+ """
+ depths = ([None, None], [None, None])
+
+ if a is None or a < 0:
+ if b is None or b >= 0:
+ if b == 0:
+ depths[0][0] = 0
+ else:
+ depths[0][0] = 1
+ else:
+ depths[0][0] = -b
+ if a is None:
+ depths[0][1] = None
+ else:
+ depths[0][1] = -a + 1
+
+ if b is None or b > 0 or (a == 0 and b == 0):
+ if a is None or a < 0:
+ depths[1][0] = 0
+ else:
+ depths[1][0] = a
+ if b is None:
+ depths[1][1] = None
+ else:
+ depths[1][1] = b + 1
+
+ return depths
+
+def generationsrel(repo, subset, x, rel, a, b, order):
+ # TODO: rewrite tests, and drop startdepth argument from ancestors() and
+ # descendants() predicates
+ depths = _splitrange(a, b)
+ ancstart, ancstop = depths[0]
+ descstart, descstop = depths[1]
+
+ if ancstart is not None and descstart is not None:
+ return (_ancestors(repo, subset, x, False, ancstart, ancstop) +
+ _descendants(repo, subset, x, False, descstart, descstop))
+ elif ancstart is not None:
+ return _ancestors(repo, subset, x, False, ancstart, ancstop)
+ elif descstart is not None:
+ return _descendants(repo, subset, x, False, descstart, descstop)
+
+ return baseset()
def relsubscriptset(repo, subset, x, y, z, order):
# this is pretty basic implementation of 'x#y[z]' operator, still
# experimental so undocumented. see the wiki for further ideas.
# https://www.mercurial-scm.org/wiki/RevsetOperatorPlan
rel = getsymbol(y)
- n = getinteger(z, _("relation subscript must be an integer"))
+ try:
+ a, b = getrange(z, '')
+ except error.ParseError:
+ a = getinteger(z, _("relation subscript must be an integer"))
+ b = a
+ else:
+ def getbound(i):
+ if i is None:
+ return None
+ msg = _("relation subscript bounds must be integers")
+ return getinteger(i, msg)
+ a, b = [getbound(i) for i in (a, b)]
if rel in subscriptrelations:
- return subscriptrelations[rel](repo, subset, x, rel, n, order)
+ return subscriptrelations[rel](repo, subset, x, rel, a, b, order)
relnames = [r for r in subscriptrelations.keys() if len(r) > 1]
raise error.UnknownIdentifier(rel, relnames)
diff --git a/tests/test-doctest.py b/tests/test-doctest.py
--- a/tests/test-doctest.py
+++ b/tests/test-doctest.py
@@ -62,6 +62,7 @@ testmod('mercurial.parser')
testmod('mercurial.pycompat')
testmod('mercurial.revlog')
testmod('mercurial.revlogutils.deltas')
+testmod('mercurial.revset')
testmod('mercurial.revsetlang')
testmod('mercurial.smartset')
testmod('mercurial.store')
diff --git a/tests/test-revset.t b/tests/test-revset.t
--- a/tests/test-revset.t
+++ b/tests/test-revset.t
@@ -648,6 +648,9 @@ parse errors of relation, subscript and
$ hg debugrevspec '.#generations[1-2]'
hg: parse error: relation subscript must be an integer
[255]
+ $ hg debugrevspec '.#generations[foo:bar]'
+ hg: parse error: relation subscript bounds must be integers
+ [255]
suggested relations
@@ -1274,6 +1277,30 @@ test ancestors/descendants relation subs
$ log '.#g[(-1)]'
8
+ $ log '6#generations[0:1]'
+ 6
+ 7
+ $ log '6#generations[-1:1]'
+ 4
+ 5
+ 6
+ 7
+ $ log '6#generations[0:]'
+ 6
+ 7
+ $ log '5#generations[:0]'
+ 0
+ 1
+ 3
+ 5
+ $ log '3#generations[:]'
+ 0
+ 1
+ 3
+ 5
+ 6
+ 7
+
$ hg debugrevspec -p parsed 'roots(:)#g[2]'
* parsed:
(relsubscript
More information about the Mercurial-devel
mailing list