Mercurial > hg
comparison mercurial/phases.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | ab893a99b645 |
children | 687b865b95ad |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
121 util, | 121 util, |
122 ) | 122 ) |
123 | 123 |
124 _fphasesentry = struct.Struct('>i20s') | 124 _fphasesentry = struct.Struct('>i20s') |
125 | 125 |
126 INTERNAL_FLAG = 64 # Phases for mercurial internal usage only | 126 INTERNAL_FLAG = 64 # Phases for mercurial internal usage only |
127 HIDEABLE_FLAG = 32 # Phases that are hideable | 127 HIDEABLE_FLAG = 32 # Phases that are hideable |
128 | 128 |
129 # record phase index | 129 # record phase index |
130 public, draft, secret = range(3) | 130 public, draft, secret = range(3) |
131 internal = INTERNAL_FLAG | HIDEABLE_FLAG | 131 internal = INTERNAL_FLAG | HIDEABLE_FLAG |
132 archived = HIDEABLE_FLAG | 132 archived = HIDEABLE_FLAG |
133 allphases = range(internal + 1) | 133 allphases = range(internal + 1) |
134 trackedphases = allphases[1:] | 134 trackedphases = allphases[1:] |
135 # record phase names | 135 # record phase names |
136 cmdphasenames = ['public', 'draft', 'secret'] # known to `hg phase` command | 136 cmdphasenames = ['public', 'draft', 'secret'] # known to `hg phase` command |
137 phasenames = [None] * len(allphases) | 137 phasenames = [None] * len(allphases) |
138 phasenames[:len(cmdphasenames)] = cmdphasenames | 138 phasenames[: len(cmdphasenames)] = cmdphasenames |
139 phasenames[archived] = 'archived' | 139 phasenames[archived] = 'archived' |
140 phasenames[internal] = 'internal' | 140 phasenames[internal] = 'internal' |
141 # record phase property | 141 # record phase property |
142 mutablephases = tuple(allphases[1:]) | 142 mutablephases = tuple(allphases[1:]) |
143 remotehiddenphases = tuple(allphases[2:]) | 143 remotehiddenphases = tuple(allphases[2:]) |
144 localhiddenphases = tuple(p for p in allphases if p & HIDEABLE_FLAG) | 144 localhiddenphases = tuple(p for p in allphases if p & HIDEABLE_FLAG) |
145 | 145 |
146 | |
146 def supportinternal(repo): | 147 def supportinternal(repo): |
147 """True if the internal phase can be used on a repository""" | 148 """True if the internal phase can be used on a repository""" |
148 return 'internal-phase' in repo.requirements | 149 return 'internal-phase' in repo.requirements |
150 | |
149 | 151 |
150 def _readroots(repo, phasedefaults=None): | 152 def _readroots(repo, phasedefaults=None): |
151 """Read phase roots from disk | 153 """Read phase roots from disk |
152 | 154 |
153 phasedefaults is a list of fn(repo, roots) callable, which are | 155 phasedefaults is a list of fn(repo, roots) callable, which are |
176 for f in phasedefaults: | 178 for f in phasedefaults: |
177 roots = f(repo, roots) | 179 roots = f(repo, roots) |
178 dirty = True | 180 dirty = True |
179 return roots, dirty | 181 return roots, dirty |
180 | 182 |
183 | |
181 def binaryencode(phasemapping): | 184 def binaryencode(phasemapping): |
182 """encode a 'phase -> nodes' mapping into a binary stream | 185 """encode a 'phase -> nodes' mapping into a binary stream |
183 | 186 |
184 Since phases are integer the mapping is actually a python list: | 187 Since phases are integer the mapping is actually a python list: |
185 [[PUBLIC_HEADS], [DRAFTS_HEADS], [SECRET_HEADS]] | 188 [[PUBLIC_HEADS], [DRAFTS_HEADS], [SECRET_HEADS]] |
187 binarydata = [] | 190 binarydata = [] |
188 for phase, nodes in enumerate(phasemapping): | 191 for phase, nodes in enumerate(phasemapping): |
189 for head in nodes: | 192 for head in nodes: |
190 binarydata.append(_fphasesentry.pack(phase, head)) | 193 binarydata.append(_fphasesentry.pack(phase, head)) |
191 return ''.join(binarydata) | 194 return ''.join(binarydata) |
195 | |
192 | 196 |
193 def binarydecode(stream): | 197 def binarydecode(stream): |
194 """decode a binary stream into a 'phase -> nodes' mapping | 198 """decode a binary stream into a 'phase -> nodes' mapping |
195 | 199 |
196 Since phases are integer the mapping is actually a python list.""" | 200 Since phases are integer the mapping is actually a python list.""" |
204 break | 208 break |
205 phase, node = _fphasesentry.unpack(entry) | 209 phase, node = _fphasesentry.unpack(entry) |
206 headsbyphase[phase].append(node) | 210 headsbyphase[phase].append(node) |
207 return headsbyphase | 211 return headsbyphase |
208 | 212 |
213 | |
209 def _trackphasechange(data, rev, old, new): | 214 def _trackphasechange(data, rev, old, new): |
210 """add a phase move the <data> dictionnary | 215 """add a phase move the <data> dictionnary |
211 | 216 |
212 If data is None, nothing happens. | 217 If data is None, nothing happens. |
213 """ | 218 """ |
215 return | 220 return |
216 existing = data.get(rev) | 221 existing = data.get(rev) |
217 if existing is not None: | 222 if existing is not None: |
218 old = existing[0] | 223 old = existing[0] |
219 data[rev] = (old, new) | 224 data[rev] = (old, new) |
225 | |
220 | 226 |
221 class phasecache(object): | 227 class phasecache(object): |
222 def __init__(self, repo, phasedefaults, _load=True): | 228 def __init__(self, repo, phasedefaults, _load=True): |
223 if _load: | 229 if _load: |
224 # Cheap trick to allow shallow-copy without copy module | 230 # Cheap trick to allow shallow-copy without copy module |
228 self.filterunknown(repo) | 234 self.filterunknown(repo) |
229 self.opener = repo.svfs | 235 self.opener = repo.svfs |
230 | 236 |
231 def getrevset(self, repo, phases, subset=None): | 237 def getrevset(self, repo, phases, subset=None): |
232 """return a smartset for the given phases""" | 238 """return a smartset for the given phases""" |
233 self.loadphaserevs(repo) # ensure phase's sets are loaded | 239 self.loadphaserevs(repo) # ensure phase's sets are loaded |
234 phases = set(phases) | 240 phases = set(phases) |
235 if public not in phases: | 241 if public not in phases: |
236 # fast path: _phasesets contains the interesting sets, | 242 # fast path: _phasesets contains the interesting sets, |
237 # might only need a union and post-filtering. | 243 # might only need a union and post-filtering. |
238 if len(phases) == 1: | 244 if len(phases) == 1: |
272 ph._phasesets = self._phasesets | 278 ph._phasesets = self._phasesets |
273 return ph | 279 return ph |
274 | 280 |
275 def replace(self, phcache): | 281 def replace(self, phcache): |
276 """replace all values in 'self' with content of phcache""" | 282 """replace all values in 'self' with content of phcache""" |
277 for a in ('phaseroots', 'dirty', 'opener', '_loadedrevslen', | 283 for a in ( |
278 '_phasesets'): | 284 'phaseroots', |
285 'dirty', | |
286 'opener', | |
287 '_loadedrevslen', | |
288 '_phasesets', | |
289 ): | |
279 setattr(self, a, getattr(phcache, a)) | 290 setattr(self, a, getattr(phcache, a)) |
280 | 291 |
281 def _getphaserevsnative(self, repo): | 292 def _getphaserevsnative(self, repo): |
282 repo = repo.unfiltered() | 293 repo = repo.unfiltered() |
283 nativeroots = [] | 294 nativeroots = [] |
284 for phase in trackedphases: | 295 for phase in trackedphases: |
285 nativeroots.append(pycompat.maplist(repo.changelog.rev, | 296 nativeroots.append( |
286 self.phaseroots[phase])) | 297 pycompat.maplist(repo.changelog.rev, self.phaseroots[phase]) |
298 ) | |
287 return repo.changelog.computephases(nativeroots) | 299 return repo.changelog.computephases(nativeroots) |
288 | 300 |
289 def _computephaserevspure(self, repo): | 301 def _computephaserevspure(self, repo): |
290 repo = repo.unfiltered() | 302 repo = repo.unfiltered() |
291 cl = repo.changelog | 303 cl = repo.changelog |
385 else: | 397 else: |
386 phasetracking = tr.changes.get('phases') | 398 phasetracking = tr.changes.get('phases') |
387 | 399 |
388 repo = repo.unfiltered() | 400 repo = repo.unfiltered() |
389 | 401 |
390 changes = set() # set of revisions to be changed | 402 changes = set() # set of revisions to be changed |
391 delroots = [] # set of root deleted by this path | 403 delroots = [] # set of root deleted by this path |
392 for phase in pycompat.xrange(targetphase + 1, len(allphases)): | 404 for phase in pycompat.xrange(targetphase + 1, len(allphases)): |
393 # filter nodes that are not in a compatible phase already | 405 # filter nodes that are not in a compatible phase already |
394 nodes = [n for n in nodes | 406 nodes = [ |
395 if self.phase(repo, repo[n].rev()) >= phase] | 407 n for n in nodes if self.phase(repo, repo[n].rev()) >= phase |
408 ] | |
396 if not nodes: | 409 if not nodes: |
397 break # no roots to move anymore | 410 break # no roots to move anymore |
398 | 411 |
399 olds = self.phaseroots[phase] | 412 olds = self.phaseroots[phase] |
400 | 413 |
401 affected = repo.revs('%ln::%ln', olds, nodes) | 414 affected = repo.revs('%ln::%ln', olds, nodes) |
402 changes.update(affected) | 415 changes.update(affected) |
403 if dryrun: | 416 if dryrun: |
404 continue | 417 continue |
405 for r in affected: | 418 for r in affected: |
406 _trackphasechange(phasetracking, r, self.phase(repo, r), | 419 _trackphasechange( |
407 targetphase) | 420 phasetracking, r, self.phase(repo, r), targetphase |
408 | 421 ) |
409 roots = set(ctx.node() for ctx in repo.set( | 422 |
410 'roots((%ln::) - %ld)', olds, affected)) | 423 roots = set( |
424 ctx.node() | |
425 for ctx in repo.set('roots((%ln::) - %ld)', olds, affected) | |
426 ) | |
411 if olds != roots: | 427 if olds != roots: |
412 self._updateroots(phase, roots, tr) | 428 self._updateroots(phase, roots, tr) |
413 # some roots may need to be declared for lower phases | 429 # some roots may need to be declared for lower phases |
414 delroots.extend(olds - roots) | 430 delroots.extend(olds - roots) |
415 if not dryrun: | 431 if not dryrun: |
418 self._retractboundary(repo, tr, targetphase, delroots) | 434 self._retractboundary(repo, tr, targetphase, delroots) |
419 repo.invalidatevolatilesets() | 435 repo.invalidatevolatilesets() |
420 return changes | 436 return changes |
421 | 437 |
422 def retractboundary(self, repo, tr, targetphase, nodes): | 438 def retractboundary(self, repo, tr, targetphase, nodes): |
423 oldroots = self.phaseroots[:targetphase + 1] | 439 oldroots = self.phaseroots[: targetphase + 1] |
424 if tr is None: | 440 if tr is None: |
425 phasetracking = None | 441 phasetracking = None |
426 else: | 442 else: |
427 phasetracking = tr.changes.get('phases') | 443 phasetracking = tr.changes.get('phases') |
428 repo = repo.unfiltered() | 444 repo = repo.unfiltered() |
429 if (self._retractboundary(repo, tr, targetphase, nodes) | 445 if ( |
430 and phasetracking is not None): | 446 self._retractboundary(repo, tr, targetphase, nodes) |
447 and phasetracking is not None | |
448 ): | |
431 | 449 |
432 # find the affected revisions | 450 # find the affected revisions |
433 new = self.phaseroots[targetphase] | 451 new = self.phaseroots[targetphase] |
434 old = oldroots[targetphase] | 452 old = oldroots[targetphase] |
435 affected = set(repo.revs('(%ln::) - (%ln::)', new, old)) | 453 affected = set(repo.revs('(%ln::) - (%ln::)', new, old)) |
438 for phase in pycompat.xrange(targetphase, -1, -1): | 456 for phase in pycompat.xrange(targetphase, -1, -1): |
439 if phase: | 457 if phase: |
440 roots = oldroots[phase] | 458 roots = oldroots[phase] |
441 revs = set(repo.revs('%ln::%ld', roots, affected)) | 459 revs = set(repo.revs('%ln::%ld', roots, affected)) |
442 affected -= revs | 460 affected -= revs |
443 else: # public phase | 461 else: # public phase |
444 revs = affected | 462 revs = affected |
445 for r in revs: | 463 for r in revs: |
446 _trackphasechange(phasetracking, r, phase, targetphase) | 464 _trackphasechange(phasetracking, r, phase, targetphase) |
447 repo.invalidatevolatilesets() | 465 repo.invalidatevolatilesets() |
448 | 466 |
455 raise error.ProgrammingError(msg) | 473 raise error.ProgrammingError(msg) |
456 | 474 |
457 repo = repo.unfiltered() | 475 repo = repo.unfiltered() |
458 currentroots = self.phaseroots[targetphase] | 476 currentroots = self.phaseroots[targetphase] |
459 finalroots = oldroots = set(currentroots) | 477 finalroots = oldroots = set(currentroots) |
460 newroots = [n for n in nodes | 478 newroots = [ |
461 if self.phase(repo, repo[n].rev()) < targetphase] | 479 n for n in nodes if self.phase(repo, repo[n].rev()) < targetphase |
480 ] | |
462 if newroots: | 481 if newroots: |
463 | 482 |
464 if nullid in newroots: | 483 if nullid in newroots: |
465 raise error.Abort(_('cannot change null revision phase')) | 484 raise error.Abort(_('cannot change null revision phase')) |
466 currentroots = currentroots.copy() | 485 currentroots = currentroots.copy() |
467 currentroots.update(newroots) | 486 currentroots.update(newroots) |
468 | 487 |
469 # Only compute new roots for revs above the roots that are being | 488 # Only compute new roots for revs above the roots that are being |
470 # retracted. | 489 # retracted. |
471 minnewroot = min(repo[n].rev() for n in newroots) | 490 minnewroot = min(repo[n].rev() for n in newroots) |
472 aboveroots = [n for n in currentroots | 491 aboveroots = [ |
473 if repo[n].rev() >= minnewroot] | 492 n for n in currentroots if repo[n].rev() >= minnewroot |
493 ] | |
474 updatedroots = repo.set('roots(%ln::)', aboveroots) | 494 updatedroots = repo.set('roots(%ln::)', aboveroots) |
475 | 495 |
476 finalroots = set(n for n in currentroots if repo[n].rev() < | 496 finalroots = set( |
477 minnewroot) | 497 n for n in currentroots if repo[n].rev() < minnewroot |
498 ) | |
478 finalroots.update(ctx.node() for ctx in updatedroots) | 499 finalroots.update(ctx.node() for ctx in updatedroots) |
479 if finalroots != oldroots: | 500 if finalroots != oldroots: |
480 self._updateroots(targetphase, finalroots, tr) | 501 self._updateroots(targetphase, finalroots, tr) |
481 return True | 502 return True |
482 return False | 503 return False |
485 """remove unknown nodes from the phase boundary | 506 """remove unknown nodes from the phase boundary |
486 | 507 |
487 Nothing is lost as unknown nodes only hold data for their descendants. | 508 Nothing is lost as unknown nodes only hold data for their descendants. |
488 """ | 509 """ |
489 filtered = False | 510 filtered = False |
490 nodemap = repo.changelog.nodemap # to filter unknown nodes | 511 nodemap = repo.changelog.nodemap # to filter unknown nodes |
491 for phase, nodes in enumerate(self.phaseroots): | 512 for phase, nodes in enumerate(self.phaseroots): |
492 missing = sorted(node for node in nodes if node not in nodemap) | 513 missing = sorted(node for node in nodes if node not in nodemap) |
493 if missing: | 514 if missing: |
494 for mnode in missing: | 515 for mnode in missing: |
495 repo.ui.debug( | 516 repo.ui.debug( |
496 'removing unknown node %s from %i-phase boundary\n' | 517 'removing unknown node %s from %i-phase boundary\n' |
497 % (short(mnode), phase)) | 518 % (short(mnode), phase) |
519 ) | |
498 nodes.symmetric_difference_update(missing) | 520 nodes.symmetric_difference_update(missing) |
499 filtered = True | 521 filtered = True |
500 if filtered: | 522 if filtered: |
501 self.dirty = True | 523 self.dirty = True |
502 # filterunknown is called by repo.destroyed, we may have no changes in | 524 # filterunknown is called by repo.destroyed, we may have no changes in |
507 # anyway. If this change we should consider adding a dedicated | 529 # anyway. If this change we should consider adding a dedicated |
508 # "destroyed" function to phasecache or a proper cache key mechanism | 530 # "destroyed" function to phasecache or a proper cache key mechanism |
509 # (see branchmap one) | 531 # (see branchmap one) |
510 self.invalidate() | 532 self.invalidate() |
511 | 533 |
534 | |
512 def advanceboundary(repo, tr, targetphase, nodes, dryrun=None): | 535 def advanceboundary(repo, tr, targetphase, nodes, dryrun=None): |
513 """Add nodes to a phase changing other nodes phases if necessary. | 536 """Add nodes to a phase changing other nodes phases if necessary. |
514 | 537 |
515 This function move boundary *forward* this means that all nodes | 538 This function move boundary *forward* this means that all nodes |
516 are set in the target phase or kept in a *lower* phase. | 539 are set in the target phase or kept in a *lower* phase. |
520 If dryrun is True, no actions will be performed | 543 If dryrun is True, no actions will be performed |
521 | 544 |
522 Returns a set of revs whose phase is changed or should be changed | 545 Returns a set of revs whose phase is changed or should be changed |
523 """ | 546 """ |
524 phcache = repo._phasecache.copy() | 547 phcache = repo._phasecache.copy() |
525 changes = phcache.advanceboundary(repo, tr, targetphase, nodes, | 548 changes = phcache.advanceboundary( |
526 dryrun=dryrun) | 549 repo, tr, targetphase, nodes, dryrun=dryrun |
550 ) | |
527 if not dryrun: | 551 if not dryrun: |
528 repo._phasecache.replace(phcache) | 552 repo._phasecache.replace(phcache) |
529 return changes | 553 return changes |
554 | |
530 | 555 |
531 def retractboundary(repo, tr, targetphase, nodes): | 556 def retractboundary(repo, tr, targetphase, nodes): |
532 """Set nodes back to a phase changing other nodes phases if | 557 """Set nodes back to a phase changing other nodes phases if |
533 necessary. | 558 necessary. |
534 | 559 |
538 Simplify boundary to contains phase roots only.""" | 563 Simplify boundary to contains phase roots only.""" |
539 phcache = repo._phasecache.copy() | 564 phcache = repo._phasecache.copy() |
540 phcache.retractboundary(repo, tr, targetphase, nodes) | 565 phcache.retractboundary(repo, tr, targetphase, nodes) |
541 repo._phasecache.replace(phcache) | 566 repo._phasecache.replace(phcache) |
542 | 567 |
568 | |
543 def registernew(repo, tr, targetphase, nodes): | 569 def registernew(repo, tr, targetphase, nodes): |
544 """register a new revision and its phase | 570 """register a new revision and its phase |
545 | 571 |
546 Code adding revisions to the repository should use this function to | 572 Code adding revisions to the repository should use this function to |
547 set new changeset in their target phase (or higher). | 573 set new changeset in their target phase (or higher). |
548 """ | 574 """ |
549 phcache = repo._phasecache.copy() | 575 phcache = repo._phasecache.copy() |
550 phcache.registernew(repo, tr, targetphase, nodes) | 576 phcache.registernew(repo, tr, targetphase, nodes) |
551 repo._phasecache.replace(phcache) | 577 repo._phasecache.replace(phcache) |
578 | |
552 | 579 |
553 def listphases(repo): | 580 def listphases(repo): |
554 """List phases root for serialization over pushkey""" | 581 """List phases root for serialization over pushkey""" |
555 # Use ordered dictionary so behavior is deterministic. | 582 # Use ordered dictionary so behavior is deterministic. |
556 keys = util.sortdict() | 583 keys = util.sortdict() |
578 # The server can't handle it on it's own as it has no idea of | 605 # The server can't handle it on it's own as it has no idea of |
579 # client phase data. | 606 # client phase data. |
580 keys['publishing'] = 'True' | 607 keys['publishing'] = 'True' |
581 return keys | 608 return keys |
582 | 609 |
610 | |
583 def pushphase(repo, nhex, oldphasestr, newphasestr): | 611 def pushphase(repo, nhex, oldphasestr, newphasestr): |
584 """List phases root for serialization over pushkey""" | 612 """List phases root for serialization over pushkey""" |
585 repo = repo.unfiltered() | 613 repo = repo.unfiltered() |
586 with repo.lock(): | 614 with repo.lock(): |
587 currentphase = repo[nhex].phase() | 615 currentphase = repo[nhex].phase() |
588 newphase = abs(int(newphasestr)) # let's avoid negative index surprise | 616 newphase = abs(int(newphasestr)) # let's avoid negative index surprise |
589 oldphase = abs(int(oldphasestr)) # let's avoid negative index surprise | 617 oldphase = abs(int(oldphasestr)) # let's avoid negative index surprise |
590 if currentphase == oldphase and newphase < oldphase: | 618 if currentphase == oldphase and newphase < oldphase: |
591 with repo.transaction('pushkey-phase') as tr: | 619 with repo.transaction('pushkey-phase') as tr: |
592 advanceboundary(repo, tr, newphase, [bin(nhex)]) | 620 advanceboundary(repo, tr, newphase, [bin(nhex)]) |
593 return True | 621 return True |
594 elif currentphase == newphase: | 622 elif currentphase == newphase: |
595 # raced, but got correct result | 623 # raced, but got correct result |
596 return True | 624 return True |
597 else: | 625 else: |
598 return False | 626 return False |
599 | 627 |
628 | |
600 def subsetphaseheads(repo, subset): | 629 def subsetphaseheads(repo, subset): |
601 """Finds the phase heads for a subset of a history | 630 """Finds the phase heads for a subset of a history |
602 | 631 |
603 Returns a list indexed by phase number where each item is a list of phase | 632 Returns a list indexed by phase number where each item is a list of phase |
604 head nodes. | 633 head nodes. |
611 for phase in allphases[:secret]: | 640 for phase in allphases[:secret]: |
612 revset = "heads(%%ln & %s())" % phasenames[phase] | 641 revset = "heads(%%ln & %s())" % phasenames[phase] |
613 headsbyphase[phase] = [cl.node(r) for r in repo.revs(revset, subset)] | 642 headsbyphase[phase] = [cl.node(r) for r in repo.revs(revset, subset)] |
614 return headsbyphase | 643 return headsbyphase |
615 | 644 |
645 | |
616 def updatephases(repo, trgetter, headsbyphase): | 646 def updatephases(repo, trgetter, headsbyphase): |
617 """Updates the repo with the given phase heads""" | 647 """Updates the repo with the given phase heads""" |
618 # Now advance phase boundaries of all but secret phase | 648 # Now advance phase boundaries of all but secret phase |
619 # | 649 # |
620 # run the update (and fetch transaction) only if there are actually things | 650 # run the update (and fetch transaction) only if there are actually things |
624 revset = '%ln - _phase(%s)' | 654 revset = '%ln - _phase(%s)' |
625 heads = [c.node() for c in repo.set(revset, headsbyphase[phase], phase)] | 655 heads = [c.node() for c in repo.set(revset, headsbyphase[phase], phase)] |
626 if heads: | 656 if heads: |
627 advanceboundary(repo, trgetter(), phase, heads) | 657 advanceboundary(repo, trgetter(), phase, heads) |
628 | 658 |
659 | |
629 def analyzeremotephases(repo, subset, roots): | 660 def analyzeremotephases(repo, subset, roots): |
630 """Compute phases heads and root in a subset of node from root dict | 661 """Compute phases heads and root in a subset of node from root dict |
631 | 662 |
632 * subset is heads of the subset | 663 * subset is heads of the subset |
633 * roots is {<nodeid> => phase} mapping. key and value are string. | 664 * roots is {<nodeid> => phase} mapping. key and value are string. |
635 Accept unknown element input | 666 Accept unknown element input |
636 """ | 667 """ |
637 repo = repo.unfiltered() | 668 repo = repo.unfiltered() |
638 # build list from dictionary | 669 # build list from dictionary |
639 draftroots = [] | 670 draftroots = [] |
640 nodemap = repo.changelog.nodemap # to filter unknown nodes | 671 nodemap = repo.changelog.nodemap # to filter unknown nodes |
641 for nhex, phase in roots.iteritems(): | 672 for nhex, phase in roots.iteritems(): |
642 if nhex == 'publishing': # ignore data related to publish option | 673 if nhex == 'publishing': # ignore data related to publish option |
643 continue | 674 continue |
644 node = bin(nhex) | 675 node = bin(nhex) |
645 phase = int(phase) | 676 phase = int(phase) |
646 if phase == public: | 677 if phase == public: |
647 if node != nullid: | 678 if node != nullid: |
648 repo.ui.warn(_('ignoring inconsistent public root' | 679 repo.ui.warn( |
649 ' from remote: %s\n') % nhex) | 680 _('ignoring inconsistent public root' ' from remote: %s\n') |
681 % nhex | |
682 ) | |
650 elif phase == draft: | 683 elif phase == draft: |
651 if node in nodemap: | 684 if node in nodemap: |
652 draftroots.append(node) | 685 draftroots.append(node) |
653 else: | 686 else: |
654 repo.ui.warn(_('ignoring unexpected root from remote: %i %s\n') | 687 repo.ui.warn( |
655 % (phase, nhex)) | 688 _('ignoring unexpected root from remote: %i %s\n') |
689 % (phase, nhex) | |
690 ) | |
656 # compute heads | 691 # compute heads |
657 publicheads = newheads(repo, subset, draftroots) | 692 publicheads = newheads(repo, subset, draftroots) |
658 return publicheads, draftroots | 693 return publicheads, draftroots |
694 | |
659 | 695 |
660 class remotephasessummary(object): | 696 class remotephasessummary(object): |
661 """summarize phase information on the remote side | 697 """summarize phase information on the remote side |
662 | 698 |
663 :publishing: True is the remote is publishing | 699 :publishing: True is the remote is publishing |
675 ana = analyzeremotephases(repo, remotesubset, remoteroots) | 711 ana = analyzeremotephases(repo, remotesubset, remoteroots) |
676 self.publicheads, self.draftroots = ana | 712 self.publicheads, self.draftroots = ana |
677 # Get the list of all "heads" revs draft on remote | 713 # Get the list of all "heads" revs draft on remote |
678 dheads = unfi.set('heads(%ln::%ln)', self.draftroots, remotesubset) | 714 dheads = unfi.set('heads(%ln::%ln)', self.draftroots, remotesubset) |
679 self.draftheads = [c.node() for c in dheads] | 715 self.draftheads = [c.node() for c in dheads] |
716 | |
680 | 717 |
681 def newheads(repo, heads, roots): | 718 def newheads(repo, heads, roots): |
682 """compute new head of a subset minus another | 719 """compute new head of a subset minus another |
683 | 720 |
684 * `heads`: define the first subset | 721 * `heads`: define the first subset |
701 affected_zone = repo.revs("(%ld::%ld)", roots, new_heads) | 738 affected_zone = repo.revs("(%ld::%ld)", roots, new_heads) |
702 # heads in the area are no longer heads | 739 # heads in the area are no longer heads |
703 new_heads.difference_update(affected_zone) | 740 new_heads.difference_update(affected_zone) |
704 # revisions in the area have children outside of it, | 741 # revisions in the area have children outside of it, |
705 # They might be new heads | 742 # They might be new heads |
706 candidates = repo.revs("parents(%ld + (%ld and merge())) and not null", | 743 candidates = repo.revs( |
707 roots, affected_zone) | 744 "parents(%ld + (%ld and merge())) and not null", roots, affected_zone |
745 ) | |
708 candidates -= affected_zone | 746 candidates -= affected_zone |
709 if new_heads or candidates: | 747 if new_heads or candidates: |
710 # remove candidate that are ancestors of other heads | 748 # remove candidate that are ancestors of other heads |
711 new_heads.update(candidates) | 749 new_heads.update(candidates) |
712 prunestart = repo.revs("parents(%ld) and not null", new_heads) | 750 prunestart = repo.revs("parents(%ld) and not null", new_heads) |
713 pruned = dagop.reachableroots(repo, candidates, prunestart) | 751 pruned = dagop.reachableroots(repo, candidates, prunestart) |
714 new_heads.difference_update(pruned) | 752 new_heads.difference_update(pruned) |
715 | 753 |
716 return pycompat.maplist(cl.node, sorted(new_heads)) | 754 return pycompat.maplist(cl.node, sorted(new_heads)) |
755 | |
717 | 756 |
718 def newcommitphase(ui): | 757 def newcommitphase(ui): |
719 """helper to get the target phase of new commit | 758 """helper to get the target phase of new commit |
720 | 759 |
721 Handle all possible values for the phases.new-commit options. | 760 Handle all possible values for the phases.new-commit options. |
729 return int(v) | 768 return int(v) |
730 except ValueError: | 769 except ValueError: |
731 msg = _("phases.new-commit: not a valid phase name ('%s')") | 770 msg = _("phases.new-commit: not a valid phase name ('%s')") |
732 raise error.ConfigError(msg % v) | 771 raise error.ConfigError(msg % v) |
733 | 772 |
773 | |
734 def hassecret(repo): | 774 def hassecret(repo): |
735 """utility function that check if a repo have any secret changeset.""" | 775 """utility function that check if a repo have any secret changeset.""" |
736 return bool(repo._phasecache.phaseroots[2]) | 776 return bool(repo._phasecache.phaseroots[2]) |
777 | |
737 | 778 |
738 def preparehookargs(node, old, new): | 779 def preparehookargs(node, old, new): |
739 if old is None: | 780 if old is None: |
740 old = '' | 781 old = '' |
741 else: | 782 else: |
742 old = phasenames[old] | 783 old = phasenames[old] |
743 return {'node': node, | 784 return {'node': node, 'oldphase': old, 'phase': phasenames[new]} |
744 'oldphase': old, | |
745 'phase': phasenames[new]} |