73 if foundnew and pdepth < stopdepth: |
73 if foundnew and pdepth < stopdepth: |
74 for prev in pfunc(currev): |
74 for prev in pfunc(currev): |
75 if prev != node.nullrev: |
75 if prev != node.nullrev: |
76 heapq.heappush(pendingheap, (heapsign * prev, pdepth)) |
76 heapq.heappush(pendingheap, (heapsign * prev, pdepth)) |
77 |
77 |
78 def _genrevancestors(repo, revs, followfirst, startdepth, stopdepth): |
78 def _genrevancestors(repo, revs, followfirst, startdepth, stopdepth, cutfunc): |
79 if followfirst: |
79 if followfirst: |
80 cut = 1 |
80 cut = 1 |
81 else: |
81 else: |
82 cut = None |
82 cut = None |
83 cl = repo.changelog |
83 cl = repo.changelog |
84 def pfunc(rev): |
84 def plainpfunc(rev): |
85 try: |
85 try: |
86 return cl.parentrevs(rev)[:cut] |
86 return cl.parentrevs(rev)[:cut] |
87 except error.WdirUnsupported: |
87 except error.WdirUnsupported: |
88 return (pctx.rev() for pctx in repo[rev].parents()[:cut]) |
88 return (pctx.rev() for pctx in repo[rev].parents()[:cut]) |
|
89 if cutfunc is None: |
|
90 pfunc = plainpfunc |
|
91 else: |
|
92 pfunc = lambda rev: [r for r in plainpfunc(rev) if not cutfunc(r)] |
|
93 revs = revs.filter(lambda rev: not cutfunc(rev)) |
89 return _walkrevtree(pfunc, revs, startdepth, stopdepth, reverse=True) |
94 return _walkrevtree(pfunc, revs, startdepth, stopdepth, reverse=True) |
90 |
95 |
91 def revancestors(repo, revs, followfirst, startdepth=None, stopdepth=None): |
96 def revancestors(repo, revs, followfirst=False, startdepth=None, |
|
97 stopdepth=None, cutfunc=None): |
92 """Like revlog.ancestors(), but supports additional options, includes |
98 """Like revlog.ancestors(), but supports additional options, includes |
93 the given revs themselves, and returns a smartset |
99 the given revs themselves, and returns a smartset |
94 |
100 |
95 Scan ends at the stopdepth (exlusive) if specified. Revisions found |
101 Scan ends at the stopdepth (exlusive) if specified. Revisions found |
96 earlier than the startdepth are omitted. |
102 earlier than the startdepth are omitted. |
97 """ |
103 |
98 gen = _genrevancestors(repo, revs, followfirst, startdepth, stopdepth) |
104 If cutfunc is provided, it will be used to cut the traversal of the DAG. |
|
105 When cutfunc(X) returns True, the DAG traversal stops - revision X and |
|
106 X's ancestors in the traversal path will be skipped. This could be an |
|
107 optimization sometimes. |
|
108 |
|
109 Note: if Y is an ancestor of X, cutfunc(X) returning True does not |
|
110 necessarily mean Y will also be cut. Usually cutfunc(Y) also wants to |
|
111 return True in this case. For example, |
|
112 |
|
113 D # revancestors(repo, D, cutfunc=lambda rev: rev == B) |
|
114 |\ # will include "A", because the path D -> C -> A was not cut. |
|
115 B C # If "B" gets cut, "A" might want to be cut too. |
|
116 |/ |
|
117 A |
|
118 """ |
|
119 gen = _genrevancestors(repo, revs, followfirst, startdepth, stopdepth, |
|
120 cutfunc) |
99 return generatorset(gen, iterasc=False) |
121 return generatorset(gen, iterasc=False) |
100 |
122 |
101 def _genrevdescendants(repo, revs, followfirst): |
123 def _genrevdescendants(repo, revs, followfirst): |
102 if followfirst: |
124 if followfirst: |
103 cut = 1 |
125 cut = 1 |