Show More
@@ -75,27 +75,49 b' def _walkrevtree(pfunc, revs, startdepth' | |||
|
75 | 75 | if prev != node.nullrev: |
|
76 | 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 | 79 | if followfirst: |
|
80 | 80 | cut = 1 |
|
81 | 81 | else: |
|
82 | 82 | cut = None |
|
83 | 83 | cl = repo.changelog |
|
84 | def pfunc(rev): | |
|
84 | def plainpfunc(rev): | |
|
85 | 85 | try: |
|
86 | 86 | return cl.parentrevs(rev)[:cut] |
|
87 | 87 | except error.WdirUnsupported: |
|
88 | 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 | 94 | return _walkrevtree(pfunc, revs, startdepth, stopdepth, reverse=True) |
|
90 | 95 | |
|
91 |
def revancestors(repo, revs, followfirst, startdepth=None, |
|
|
96 | def revancestors(repo, revs, followfirst=False, startdepth=None, | |
|
97 | stopdepth=None, cutfunc=None): | |
|
92 | 98 | """Like revlog.ancestors(), but supports additional options, includes |
|
93 | 99 | the given revs themselves, and returns a smartset |
|
94 | 100 | |
|
95 | 101 | Scan ends at the stopdepth (exlusive) if specified. Revisions found |
|
96 | 102 | earlier than the startdepth are omitted. |
|
103 | ||
|
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 | |
|
97 | 118 | """ |
|
98 |
gen = _genrevancestors(repo, revs, followfirst, startdepth, stopdepth |
|
|
119 | gen = _genrevancestors(repo, revs, followfirst, startdepth, stopdepth, | |
|
120 | cutfunc) | |
|
99 | 121 | return generatorset(gen, iterasc=False) |
|
100 | 122 | |
|
101 | 123 | def _genrevdescendants(repo, revs, followfirst): |
@@ -1577,6 +1577,37 b' def _notpublic(repo, subset, x):' | |||
|
1577 | 1577 | getargs(x, 0, 0, "_notpublic takes no arguments") |
|
1578 | 1578 | return _phase(repo, subset, phases.draft, phases.secret) |
|
1579 | 1579 | |
|
1580 | # for internal use | |
|
1581 | @predicate('_phaseandancestors(phasename, set)', safe=True) | |
|
1582 | def _phaseandancestors(repo, subset, x): | |
|
1583 | # equivalent to (phasename() & ancestors(set)) but more efficient | |
|
1584 | # phasename could be one of 'draft', 'secret', or '_notpublic' | |
|
1585 | args = getargs(x, 2, 2, "_phaseandancestors requires two arguments") | |
|
1586 | phasename = getsymbol(args[0]) | |
|
1587 | s = getset(repo, fullreposet(repo), args[1]) | |
|
1588 | ||
|
1589 | draft = phases.draft | |
|
1590 | secret = phases.secret | |
|
1591 | phasenamemap = { | |
|
1592 | '_notpublic': draft, | |
|
1593 | 'draft': draft, # follow secret's ancestors | |
|
1594 | 'secret': secret, | |
|
1595 | } | |
|
1596 | if phasename not in phasenamemap: | |
|
1597 | raise error.ParseError('%r is not a valid phasename' % phasename) | |
|
1598 | ||
|
1599 | minimalphase = phasenamemap[phasename] | |
|
1600 | getphase = repo._phasecache.phase | |
|
1601 | ||
|
1602 | def cutfunc(rev): | |
|
1603 | return getphase(repo, rev) < minimalphase | |
|
1604 | ||
|
1605 | revs = dagop.revancestors(repo, s, cutfunc=cutfunc) | |
|
1606 | ||
|
1607 | if phasename == 'draft': # need to remove secret changesets | |
|
1608 | revs = revs.filter(lambda r: getphase(repo, r) == draft) | |
|
1609 | return subset & revs | |
|
1610 | ||
|
1580 | 1611 | @predicate('public()', safe=True) |
|
1581 | 1612 | def public(repo, subset, x): |
|
1582 | 1613 | """Changeset in public phase.""" |
@@ -369,6 +369,11 b' def _optimize(x, small):' | |||
|
369 | 369 | wb, tb = _optimize(x[2], True) |
|
370 | 370 | w = min(wa, wb) |
|
371 | 371 | |
|
372 | # (draft/secret/_notpublic() & ::x) have a fast path | |
|
373 | m = _match('_() & ancestors(_)', ('and', ta, tb)) | |
|
374 | if m and getsymbol(m[1]) in {'draft', 'secret', '_notpublic'}: | |
|
375 | return w, _build('_phaseandancestors(_, _)', m[1], m[2]) | |
|
376 | ||
|
372 | 377 | # (::x and not ::y)/(not ::y and ::x) have a fast path |
|
373 | 378 | m = _matchonly(ta, tb) or _matchonly(tb, ta) |
|
374 | 379 | if m: |
@@ -4321,3 +4321,147 b' Test obsstore related revsets' | |||
|
4321 | 4321 | |
|
4322 | 4322 | $ hg log -r 'successors(B+A)-contentdivergent()-obsolete()' -T '{desc}\n' |
|
4323 | 4323 | Z |
|
4324 | ||
|
4325 | Test `draft() & ::x` optimization | |
|
4326 | ||
|
4327 | $ hg init $TESTTMP/repo2 | |
|
4328 | $ cd $TESTTMP/repo2 | |
|
4329 | $ hg debugdrawdag <<'EOS' | |
|
4330 | > P5 S1 | |
|
4331 | > | | | |
|
4332 | > S2 | D3 | |
|
4333 | > \|/ | |
|
4334 | > P4 | |
|
4335 | > | | |
|
4336 | > P3 D2 | |
|
4337 | > | | | |
|
4338 | > P2 D1 | |
|
4339 | > |/ | |
|
4340 | > P1 | |
|
4341 | > | | |
|
4342 | > P0 | |
|
4343 | > EOS | |
|
4344 | $ hg phase --public -r P5 | |
|
4345 | $ hg phase --force --secret -r S1+S2 | |
|
4346 | $ hg log -G -T '{rev} {desc} {phase}' -r 'sort(all(), topo, topo.firstbranch=P5)' | |
|
4347 | o 8 P5 public | |
|
4348 | | | |
|
4349 | | o 10 S1 secret | |
|
4350 | | | | |
|
4351 | | o 7 D3 draft | |
|
4352 | |/ | |
|
4353 | | o 9 S2 secret | |
|
4354 | |/ | |
|
4355 | o 6 P4 public | |
|
4356 | | | |
|
4357 | o 5 P3 public | |
|
4358 | | | |
|
4359 | o 3 P2 public | |
|
4360 | | | |
|
4361 | | o 4 D2 draft | |
|
4362 | | | | |
|
4363 | | o 2 D1 draft | |
|
4364 | |/ | |
|
4365 | o 1 P1 public | |
|
4366 | | | |
|
4367 | o 0 P0 public | |
|
4368 | ||
|
4369 | $ hg debugrevspec --verify -p analyzed -p optimized 'draft() & ::(((S1+D1+P5)-D3)+S2)' | |
|
4370 | * analyzed: | |
|
4371 | (and | |
|
4372 | (func | |
|
4373 | ('symbol', 'draft') | |
|
4374 | None) | |
|
4375 | (func | |
|
4376 | ('symbol', 'ancestors') | |
|
4377 | (or | |
|
4378 | (list | |
|
4379 | (and | |
|
4380 | (or | |
|
4381 | (list | |
|
4382 | ('symbol', 'S1') | |
|
4383 | ('symbol', 'D1') | |
|
4384 | ('symbol', 'P5'))) | |
|
4385 | (not | |
|
4386 | ('symbol', 'D3'))) | |
|
4387 | ('symbol', 'S2'))))) | |
|
4388 | * optimized: | |
|
4389 | (func | |
|
4390 | ('symbol', '_phaseandancestors') | |
|
4391 | (list | |
|
4392 | ('symbol', 'draft') | |
|
4393 | (or | |
|
4394 | (list | |
|
4395 | (difference | |
|
4396 | (func | |
|
4397 | ('symbol', '_list') | |
|
4398 | ('string', 'S1\x00D1\x00P5')) | |
|
4399 | ('symbol', 'D3')) | |
|
4400 | ('symbol', 'S2'))))) | |
|
4401 | $ hg debugrevspec --verify -p analyzed -p optimized 'secret() & ::9' | |
|
4402 | * analyzed: | |
|
4403 | (and | |
|
4404 | (func | |
|
4405 | ('symbol', 'secret') | |
|
4406 | None) | |
|
4407 | (func | |
|
4408 | ('symbol', 'ancestors') | |
|
4409 | ('symbol', '9'))) | |
|
4410 | * optimized: | |
|
4411 | (func | |
|
4412 | ('symbol', '_phaseandancestors') | |
|
4413 | (list | |
|
4414 | ('symbol', 'secret') | |
|
4415 | ('symbol', '9'))) | |
|
4416 | $ hg debugrevspec --verify -p analyzed -p optimized '7 & ( (not public()) & ::(tag()) )' | |
|
4417 | * analyzed: | |
|
4418 | (and | |
|
4419 | ('symbol', '7') | |
|
4420 | (and | |
|
4421 | (not | |
|
4422 | (func | |
|
4423 | ('symbol', 'public') | |
|
4424 | None)) | |
|
4425 | (func | |
|
4426 | ('symbol', 'ancestors') | |
|
4427 | (func | |
|
4428 | ('symbol', 'tag') | |
|
4429 | None)))) | |
|
4430 | * optimized: | |
|
4431 | (and | |
|
4432 | ('symbol', '7') | |
|
4433 | (func | |
|
4434 | ('symbol', '_phaseandancestors') | |
|
4435 | (list | |
|
4436 | ('symbol', '_notpublic') | |
|
4437 | (func | |
|
4438 | ('symbol', 'tag') | |
|
4439 | None)))) | |
|
4440 | $ hg debugrevspec --verify -p optimized '(not public()) & ancestors(S1+D2+P5, 1)' | |
|
4441 | * optimized: | |
|
4442 | (and | |
|
4443 | (func | |
|
4444 | ('symbol', '_notpublic') | |
|
4445 | None) | |
|
4446 | (func | |
|
4447 | ('symbol', 'ancestors') | |
|
4448 | (list | |
|
4449 | (func | |
|
4450 | ('symbol', '_list') | |
|
4451 | ('string', 'S1\x00D2\x00P5')) | |
|
4452 | ('symbol', '1')))) | |
|
4453 | $ hg debugrevspec --verify -p optimized '(not public()) & ancestors(S1+D2+P5, depth=1)' | |
|
4454 | * optimized: | |
|
4455 | (and | |
|
4456 | (func | |
|
4457 | ('symbol', '_notpublic') | |
|
4458 | None) | |
|
4459 | (func | |
|
4460 | ('symbol', 'ancestors') | |
|
4461 | (list | |
|
4462 | (func | |
|
4463 | ('symbol', '_list') | |
|
4464 | ('string', 'S1\x00D2\x00P5')) | |
|
4465 | (keyvalue | |
|
4466 | ('symbol', 'depth') | |
|
4467 | ('symbol', '1'))))) |
General Comments 0
You need to be logged in to leave comments.
Login now