--- a/mercurial/revset.py Wed Apr 11 11:22:40 2012 +0200
+++ b/mercurial/revset.py Wed Apr 11 11:25:34 2012 +0200
@@ -13,6 +13,39 @@
from i18n import _
import encoding
+def _revancestors(repo, revs, followfirst):
+ """Like revlog.ancestors(), but supports followfirst."""
+ cut = followfirst and 1 or None
+ cl = repo.changelog
+ visit = list(revs)
+ seen = set([nodemod.nullrev])
+ while visit:
+ for parent in cl.parentrevs(visit.pop(0))[:cut]:
+ if parent not in seen:
+ visit.append(parent)
+ seen.add(parent)
+ yield parent
+
+def _revdescendants(repo, revs, followfirst):
+ """Like revlog.descendants() but supports followfirst."""
+ cut = followfirst and 1 or None
+ cl = repo.changelog
+ first = min(revs)
+ if first == nodemod.nullrev:
+ # Are there nodes with a null first parent and a non-null
+ # second one? Maybe. Do we care? Probably not.
+ for i in cl:
+ yield i
+ return
+
+ seen = set(revs)
+ for i in xrange(first + 1, len(cl)):
+ for x in cl.parentrevs(i)[:cut]:
+ if x != nodemod.nullrev and x in seen:
+ seen.add(i)
+ yield i
+ break
+
elements = {
"(": (20, ("group", 1, ")"), ("func", 1, ")")),
"~": (18, None, ("ancestor", 18)),
@@ -203,15 +236,23 @@
return [r for r in an if r in subset]
+def _ancestors(repo, subset, x, followfirst=False):
+ args = getset(repo, range(len(repo)), x)
+ if not args:
+ return []
+ s = set(_revancestors(repo, args, followfirst)) | set(args)
+ return [r for r in subset if r in s]
+
def ancestors(repo, subset, x):
"""``ancestors(set)``
Changesets that are ancestors of a changeset in set.
"""
- args = getset(repo, range(len(repo)), x)
- if not args:
- return []
- s = set(repo.changelog.ancestors(*args)) | set(args)
- return [r for r in subset if r in s]
+ return _ancestors(repo, subset, x)
+
+def _firstancestors(repo, subset, x):
+ # ``_firstancestors(set)``
+ # Like ``ancestors(set)`` but follows only the first parents.
+ return _ancestors(repo, subset, x, followfirst=True)
def ancestorspec(repo, subset, x, n):
"""``set~n``
@@ -395,15 +436,23 @@
l.append(r)
return l
+def _descendants(repo, subset, x, followfirst=False):
+ args = getset(repo, range(len(repo)), x)
+ if not args:
+ return []
+ s = set(_revdescendants(repo, args, followfirst)) | set(args)
+ return [r for r in subset if r in s]
+
def descendants(repo, subset, x):
"""``descendants(set)``
Changesets which are descendants of changesets in set.
"""
- args = getset(repo, range(len(repo)), x)
- if not args:
- return []
- s = set(repo.changelog.descendants(*args)) | set(args)
- return [r for r in subset if r in s]
+ return _descendants(repo, subset, x)
+
+def _firstdescendants(repo, subset, x):
+ # ``_firstdescendants(set)``
+ # Like ``descendants(set)`` but follows only the first parents.
+ return _descendants(repo, subset, x, followfirst=True)
def draft(repo, subset, x):
"""``draft()``
@@ -454,16 +503,7 @@
else:
return []
else:
- cut = followfirst and 1 or None
- cl = repo.changelog
- s = set()
- visit = [c.rev()]
- while visit:
- for prev in cl.parentrevs(visit.pop(0))[:cut]:
- if prev not in s and prev != nodemod.nullrev:
- visit.append(prev)
- s.add(prev)
- s.add(c.rev())
+ s = set(_revancestors(repo, [c.rev()], followfirst)) | set([c.rev()])
return [r for r in subset if r in s]
@@ -1055,6 +1095,7 @@
"all": getall,
"ancestor": ancestor,
"ancestors": ancestors,
+ "_firstancestors": _firstancestors,
"author": author,
"bisect": bisect,
"bisected": bisected,
@@ -1066,6 +1107,7 @@
"date": date,
"desc": desc,
"descendants": descendants,
+ "_firstdescendants": _firstdescendants,
"draft": draft,
"file": hasfile,
"filelog": filelog,