##// END OF EJS Templates
revset: add depth limit to ancestors()...
Yuya Nishihara -
r33002:272a44ca default
parent child Browse files
Show More
@@ -20,11 +20,19 b' from . import ('
20 baseset = smartset.baseset
20 baseset = smartset.baseset
21 generatorset = smartset.generatorset
21 generatorset = smartset.generatorset
22
22
23 def _genrevancestors(repo, revs, followfirst):
23 # possible maximum depth between null and wdir()
24 _maxlogdepth = 0x80000000
25
26 def _genrevancestors(repo, revs, followfirst, stopdepth):
24 if followfirst:
27 if followfirst:
25 cut = 1
28 cut = 1
26 else:
29 else:
27 cut = None
30 cut = None
31 if stopdepth is None:
32 stopdepth = _maxlogdepth
33 if stopdepth <= 0:
34 return
35
28 cl = repo.changelog
36 cl = repo.changelog
29
37
30 # load input revs lazily to heap so earlier revisions can be yielded
38 # load input revs lazily to heap so earlier revisions can be yielded
@@ -45,10 +53,12 b' def _genrevancestors(repo, revs, followf'
45 inputrev = next(irevs, None)
53 inputrev = next(irevs, None)
46 if inputrev is not None:
54 if inputrev is not None:
47 heapq.heappush(pendingheap, (-inputrev, 0))
55 heapq.heappush(pendingheap, (-inputrev, 0))
48 if currev != lastrev:
56 foundnew = (currev != lastrev)
57 if foundnew:
49 lastrev = currev
58 lastrev = currev
50 yield currev
59 yield currev
51 pdepth = curdepth + 1
60 pdepth = curdepth + 1
61 if foundnew and pdepth < stopdepth:
52 try:
62 try:
53 for prev in cl.parentrevs(currev)[:cut]:
63 for prev in cl.parentrevs(currev)[:cut]:
54 if prev != node.nullrev:
64 if prev != node.nullrev:
@@ -58,9 +68,13 b' def _genrevancestors(repo, revs, followf'
58 if pctx.rev() != node.nullrev:
68 if pctx.rev() != node.nullrev:
59 heapq.heappush(pendingheap, (-pctx.rev(), pdepth))
69 heapq.heappush(pendingheap, (-pctx.rev(), pdepth))
60
70
61 def revancestors(repo, revs, followfirst):
71 def revancestors(repo, revs, followfirst, stopdepth=None):
62 """Like revlog.ancestors(), but supports followfirst."""
72 """Like revlog.ancestors(), but supports additional options, includes
63 gen = _genrevancestors(repo, revs, followfirst)
73 the given revs themselves, and returns a smartset
74
75 Scan ends at the stopdepth (exlusive) if specified.
76 """
77 gen = _genrevancestors(repo, revs, followfirst, stopdepth)
64 return generatorset(gen, iterasc=False)
78 return generatorset(gen, iterasc=False)
65
79
66 def revdescendants(repo, revs, followfirst):
80 def revdescendants(repo, revs, followfirst):
@@ -238,23 +238,33 b' def ancestor(repo, subset, x):'
238 return baseset([anc.rev()])
238 return baseset([anc.rev()])
239 return baseset()
239 return baseset()
240
240
241 def _ancestors(repo, subset, x, followfirst=False):
241 def _ancestors(repo, subset, x, followfirst=False, stopdepth=None):
242 heads = getset(repo, fullreposet(repo), x)
242 heads = getset(repo, fullreposet(repo), x)
243 if not heads:
243 if not heads:
244 return baseset()
244 return baseset()
245 s = dagop.revancestors(repo, heads, followfirst)
245 s = dagop.revancestors(repo, heads, followfirst, stopdepth)
246 return subset & s
246 return subset & s
247
247
248 @predicate('ancestors(set)', safe=True)
248 @predicate('ancestors(set[, depth])', safe=True)
249 def ancestors(repo, subset, x):
249 def ancestors(repo, subset, x):
250 """Changesets that are ancestors of changesets in set, including the
250 """Changesets that are ancestors of changesets in set, including the
251 given changesets themselves.
251 given changesets themselves.
252
253 If depth is specified, the result only includes changesets up to
254 the specified generation.
252 """
255 """
253 args = getargsdict(x, 'ancestors', 'set')
256 args = getargsdict(x, 'ancestors', 'set depth')
254 if 'set' not in args:
257 if 'set' not in args:
255 # i18n: "ancestors" is a keyword
258 # i18n: "ancestors" is a keyword
256 raise error.ParseError(_('ancestors takes at least 1 argument'))
259 raise error.ParseError(_('ancestors takes at least 1 argument'))
257 return _ancestors(repo, subset, args['set'])
260 stopdepth = None
261 if 'depth' in args:
262 # i18n: "ancestors" is a keyword
263 n = getinteger(args['depth'], _("ancestors expects an integer depth"))
264 if n < 0:
265 raise error.ParseError(_("negative depth"))
266 stopdepth = n + 1
267 return _ancestors(repo, subset, args['set'], stopdepth=stopdepth)
258
268
259 @predicate('_firstancestors', safe=True)
269 @predicate('_firstancestors', safe=True)
260 def _firstancestors(repo, subset, x):
270 def _firstancestors(repo, subset, x):
@@ -842,6 +842,20 b' ancestor can accept 0 or more arguments'
842
842
843 test ancestors
843 test ancestors
844
844
845 $ hg log -G -T '{rev}\n' --config experimental.graphshorten=True
846 @ 9
847 o 8
848 | o 7
849 | o 6
850 |/|
851 | o 5
852 o | 4
853 | o 3
854 o | 2
855 |/
856 o 1
857 o 0
858
845 $ log 'ancestors(5)'
859 $ log 'ancestors(5)'
846 0
860 0
847 1
861 1
@@ -855,6 +869,51 b' test ancestors'
855 2
869 2
856 3
870 3
857
871
872 test ancestors with depth limit
873
874 (depth=0 selects the node itself)
875
876 $ log 'reverse(ancestors(9, depth=0))'
877 9
878
879 (interleaved: '4' would be missing if heap queue were higher depth first)
880
881 $ log 'reverse(ancestors(8:9, depth=1))'
882 9
883 8
884 4
885
886 (interleaved: '2' would be missing if heap queue were higher depth first)
887
888 $ log 'reverse(ancestors(7+8, depth=2))'
889 8
890 7
891 6
892 5
893 4
894 2
895
896 (walk example above by separate queries)
897
898 $ log 'reverse(ancestors(8, depth=2)) + reverse(ancestors(7, depth=2))'
899 8
900 4
901 2
902 7
903 6
904 5
905
906 test bad arguments passed to ancestors()
907
908 $ log 'ancestors(., depth=-1)'
909 hg: parse error: negative depth
910 [255]
911 $ log 'ancestors(., depth=foo)'
912 hg: parse error: ancestors expects an integer depth
913 [255]
914
915 test author
916
858 $ log 'author(bob)'
917 $ log 'author(bob)'
859 2
918 2
860 $ log 'author("re:bob|test")'
919 $ log 'author("re:bob|test")'
@@ -2996,8 +3055,11 b' optimization to only() works only if anc'
2996 ('symbol', '1'))
3055 ('symbol', '1'))
2997 any)
3056 any)
2998 define)
3057 define)
2999 hg: parse error: ancestors takes at most 1 positional arguments
3058 0
3000 [255]
3059 1
3060 3
3061 5
3062 6
3001 $ hg debugrevspec -p optimized 'ancestors(6, 1) - ancestors(4)'
3063 $ hg debugrevspec -p optimized 'ancestors(6, 1) - ancestors(4)'
3002 * optimized:
3064 * optimized:
3003 (difference
3065 (difference
@@ -3012,8 +3074,8 b' optimization to only() works only if anc'
3012 ('symbol', '4')
3074 ('symbol', '4')
3013 any)
3075 any)
3014 define)
3076 define)
3015 hg: parse error: ancestors takes at most 1 positional arguments
3077 5
3016 [255]
3078 6
3017
3079
3018 optimization disabled if keyword arguments passed (because we're too lazy
3080 optimization disabled if keyword arguments passed (because we're too lazy
3019 to support it)
3081 to support it)
General Comments 0
You need to be logged in to leave comments. Login now