comparison mercurial/revset.py @ 16409:2cbd7dd0cc1f

graphlog: fix --follow-first --rev combinations This solves a similar problem than the previous --follow/--rev patch. This time we need changelog.ancestors()/descendants() filtering on first parent. Duplicating the code looked better than introducing keyword arguments. Besides, the ancestors() version was already implemented in follow() revset.
author Patrick Mezard <patrick@mezard.eu>
date Wed, 11 Apr 2012 11:25:34 +0200
parents 1fb2f1400ea8
children 4c2edcd84175
comparison
equal deleted inserted replaced
16408:d74099ac2ac1 16409:2cbd7dd0cc1f
10 import node as nodemod 10 import node as nodemod
11 import bookmarks as bookmarksmod 11 import bookmarks as bookmarksmod
12 import match as matchmod 12 import match as matchmod
13 from i18n import _ 13 from i18n import _
14 import encoding 14 import encoding
15
16 def _revancestors(repo, revs, followfirst):
17 """Like revlog.ancestors(), but supports followfirst."""
18 cut = followfirst and 1 or None
19 cl = repo.changelog
20 visit = list(revs)
21 seen = set([nodemod.nullrev])
22 while visit:
23 for parent in cl.parentrevs(visit.pop(0))[:cut]:
24 if parent not in seen:
25 visit.append(parent)
26 seen.add(parent)
27 yield parent
28
29 def _revdescendants(repo, revs, followfirst):
30 """Like revlog.descendants() but supports followfirst."""
31 cut = followfirst and 1 or None
32 cl = repo.changelog
33 first = min(revs)
34 if first == nodemod.nullrev:
35 # Are there nodes with a null first parent and a non-null
36 # second one? Maybe. Do we care? Probably not.
37 for i in cl:
38 yield i
39 return
40
41 seen = set(revs)
42 for i in xrange(first + 1, len(cl)):
43 for x in cl.parentrevs(i)[:cut]:
44 if x != nodemod.nullrev and x in seen:
45 seen.add(i)
46 yield i
47 break
15 48
16 elements = { 49 elements = {
17 "(": (20, ("group", 1, ")"), ("func", 1, ")")), 50 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
18 "~": (18, None, ("ancestor", 18)), 51 "~": (18, None, ("ancestor", 18)),
19 "^": (18, None, ("parent", 18), ("parentpost", 18)), 52 "^": (18, None, ("parent", 18), ("parentpost", 18)),
201 raise error.ParseError(_("ancestor arguments must be single revisions")) 234 raise error.ParseError(_("ancestor arguments must be single revisions"))
202 an = [repo[a[0]].ancestor(repo[b[0]]).rev()] 235 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
203 236
204 return [r for r in an if r in subset] 237 return [r for r in an if r in subset]
205 238
239 def _ancestors(repo, subset, x, followfirst=False):
240 args = getset(repo, range(len(repo)), x)
241 if not args:
242 return []
243 s = set(_revancestors(repo, args, followfirst)) | set(args)
244 return [r for r in subset if r in s]
245
206 def ancestors(repo, subset, x): 246 def ancestors(repo, subset, x):
207 """``ancestors(set)`` 247 """``ancestors(set)``
208 Changesets that are ancestors of a changeset in set. 248 Changesets that are ancestors of a changeset in set.
209 """ 249 """
210 args = getset(repo, range(len(repo)), x) 250 return _ancestors(repo, subset, x)
211 if not args: 251
212 return [] 252 def _firstancestors(repo, subset, x):
213 s = set(repo.changelog.ancestors(*args)) | set(args) 253 # ``_firstancestors(set)``
214 return [r for r in subset if r in s] 254 # Like ``ancestors(set)`` but follows only the first parents.
255 return _ancestors(repo, subset, x, followfirst=True)
215 256
216 def ancestorspec(repo, subset, x, n): 257 def ancestorspec(repo, subset, x, n):
217 """``set~n`` 258 """``set~n``
218 Changesets that are the Nth ancestor (first parents only) of a changeset in set. 259 Changesets that are the Nth ancestor (first parents only) of a changeset in set.
219 """ 260 """
393 c = repo[r] 434 c = repo[r]
394 if ds in encoding.lower(c.description()): 435 if ds in encoding.lower(c.description()):
395 l.append(r) 436 l.append(r)
396 return l 437 return l
397 438
439 def _descendants(repo, subset, x, followfirst=False):
440 args = getset(repo, range(len(repo)), x)
441 if not args:
442 return []
443 s = set(_revdescendants(repo, args, followfirst)) | set(args)
444 return [r for r in subset if r in s]
445
398 def descendants(repo, subset, x): 446 def descendants(repo, subset, x):
399 """``descendants(set)`` 447 """``descendants(set)``
400 Changesets which are descendants of changesets in set. 448 Changesets which are descendants of changesets in set.
401 """ 449 """
402 args = getset(repo, range(len(repo)), x) 450 return _descendants(repo, subset, x)
403 if not args: 451
404 return [] 452 def _firstdescendants(repo, subset, x):
405 s = set(repo.changelog.descendants(*args)) | set(args) 453 # ``_firstdescendants(set)``
406 return [r for r in subset if r in s] 454 # Like ``descendants(set)`` but follows only the first parents.
455 return _descendants(repo, subset, x, followfirst=True)
407 456
408 def draft(repo, subset, x): 457 def draft(repo, subset, x):
409 """``draft()`` 458 """``draft()``
410 Changeset in draft phase.""" 459 Changeset in draft phase."""
411 getargs(x, 0, 0, _("draft takes no arguments")) 460 getargs(x, 0, 0, _("draft takes no arguments"))
452 # include the revision responsible for the most recent version 501 # include the revision responsible for the most recent version
453 s.add(cx.linkrev()) 502 s.add(cx.linkrev())
454 else: 503 else:
455 return [] 504 return []
456 else: 505 else:
457 cut = followfirst and 1 or None 506 s = set(_revancestors(repo, [c.rev()], followfirst)) | set([c.rev()])
458 cl = repo.changelog
459 s = set()
460 visit = [c.rev()]
461 while visit:
462 for prev in cl.parentrevs(visit.pop(0))[:cut]:
463 if prev not in s and prev != nodemod.nullrev:
464 visit.append(prev)
465 s.add(prev)
466 s.add(c.rev())
467 507
468 return [r for r in subset if r in s] 508 return [r for r in subset if r in s]
469 509
470 def follow(repo, subset, x): 510 def follow(repo, subset, x):
471 """``follow([file])`` 511 """``follow([file])``
1053 symbols = { 1093 symbols = {
1054 "adds": adds, 1094 "adds": adds,
1055 "all": getall, 1095 "all": getall,
1056 "ancestor": ancestor, 1096 "ancestor": ancestor,
1057 "ancestors": ancestors, 1097 "ancestors": ancestors,
1098 "_firstancestors": _firstancestors,
1058 "author": author, 1099 "author": author,
1059 "bisect": bisect, 1100 "bisect": bisect,
1060 "bisected": bisected, 1101 "bisected": bisected,
1061 "bookmark": bookmark, 1102 "bookmark": bookmark,
1062 "branch": branch, 1103 "branch": branch,
1064 "closed": closed, 1105 "closed": closed,
1065 "contains": contains, 1106 "contains": contains,
1066 "date": date, 1107 "date": date,
1067 "desc": desc, 1108 "desc": desc,
1068 "descendants": descendants, 1109 "descendants": descendants,
1110 "_firstdescendants": _firstdescendants,
1069 "draft": draft, 1111 "draft": draft,
1070 "file": hasfile, 1112 "file": hasfile,
1071 "filelog": filelog, 1113 "filelog": filelog,
1072 "first": first, 1114 "first": first,
1073 "follow": follow, 1115 "follow": follow,