Mercurial > public > mercurial-scm > hg
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, |