365 # Cheap trick to allow shallow-copy without copy module |
366 # Cheap trick to allow shallow-copy without copy module |
366 self._phaseroots, self.dirty = _readroots(repo, phasedefaults) |
367 self._phaseroots, self.dirty = _readroots(repo, phasedefaults) |
367 self._loadedrevslen = 0 |
368 self._loadedrevslen = 0 |
368 self._phasesets = None |
369 self._phasesets = None |
369 self.filterunknown(repo) |
370 self.filterunknown(repo) |
370 self.opener = repo.svfs |
|
371 |
371 |
372 def hasnonpublicphases(self, repo: "localrepo.localrepository") -> bool: |
372 def hasnonpublicphases(self, repo: "localrepo.localrepository") -> bool: |
373 """detect if there are revisions with non-public phase""" |
373 """detect if there are revisions with non-public phase""" |
374 repo = repo.unfiltered() |
374 repo = repo.unfiltered() |
375 cl = repo.changelog |
375 cl = repo.changelog |
464 # Shallow copy meant to ensure isolation in |
464 # Shallow copy meant to ensure isolation in |
465 # advance/retractboundary(), nothing more. |
465 # advance/retractboundary(), nothing more. |
466 ph = self.__class__(None, None, _load=False) |
466 ph = self.__class__(None, None, _load=False) |
467 ph._phaseroots = self._phaseroots.copy() |
467 ph._phaseroots = self._phaseroots.copy() |
468 ph.dirty = self.dirty |
468 ph.dirty = self.dirty |
469 ph.opener = self.opener |
|
470 ph._loadedrevslen = self._loadedrevslen |
469 ph._loadedrevslen = self._loadedrevslen |
471 ph._phasesets = self._phasesets |
470 ph._phasesets = self._phasesets |
472 return ph |
471 return ph |
473 |
472 |
474 def replace(self, phcache): |
473 def replace(self, phcache): |
475 """replace all values in 'self' with content of phcache""" |
474 """replace all values in 'self' with content of phcache""" |
476 for a in ( |
475 for a in ( |
477 '_phaseroots', |
476 '_phaseroots', |
478 'dirty', |
477 'dirty', |
479 'opener', |
|
480 '_loadedrevslen', |
478 '_loadedrevslen', |
481 '_phasesets', |
479 '_phasesets', |
482 ): |
480 ): |
483 setattr(self, a, getattr(phcache, a)) |
481 setattr(self, a, getattr(phcache, a)) |
484 |
482 |
531 for phase in trackedphases: |
529 for phase in trackedphases: |
532 if rev in self._phasesets[phase]: |
530 if rev in self._phasesets[phase]: |
533 return phase |
531 return phase |
534 return public |
532 return public |
535 |
533 |
536 def write(self): |
534 def write(self, repo): |
537 if not self.dirty: |
535 if not self.dirty: |
538 return |
536 return |
539 f = self.opener(b'phaseroots', b'w', atomictemp=True, checkambig=True) |
537 f = repo.svfs(b'phaseroots', b'w', atomictemp=True, checkambig=True) |
540 try: |
538 try: |
541 self._write(f) |
539 self._write(repo.unfiltered(), f) |
542 finally: |
540 finally: |
543 f.close() |
541 f.close() |
544 |
542 |
545 def _write(self, fp): |
543 def _write(self, repo, fp): |
|
544 assert repo.filtername is None |
546 for phase, roots in self._phaseroots.items(): |
545 for phase, roots in self._phaseroots.items(): |
547 for h in sorted(roots): |
546 for h in sorted(roots): |
548 fp.write(b'%i %s\n' % (phase, hex(h))) |
547 fp.write(b'%i %s\n' % (phase, hex(h))) |
549 self.dirty = False |
548 self.dirty = False |
550 |
549 |
551 def _updateroots(self, phase, newroots, tr): |
550 def _updateroots(self, repo, phase, newroots, tr): |
552 self._phaseroots[phase] = newroots |
551 self._phaseroots[phase] = newroots |
553 self.invalidate() |
552 self.invalidate() |
554 self.dirty = True |
553 self.dirty = True |
555 |
554 |
556 tr.addfilegenerator(b'phase', (b'phaseroots',), self._write) |
555 assert repo.filtername is None |
|
556 wrepo = weakref.ref(repo) |
|
557 |
|
558 def tr_write(fp): |
|
559 repo = wrepo() |
|
560 assert repo is not None |
|
561 self._write(repo, fp) |
|
562 |
|
563 tr.addfilegenerator(b'phase', (b'phaseroots',), tr_write) |
557 tr.hookargs[b'phases_moved'] = b'1' |
564 tr.hookargs[b'phases_moved'] = b'1' |
558 |
565 |
559 def registernew(self, repo, tr, targetphase, revs): |
566 def registernew(self, repo, tr, targetphase, revs): |
560 repo = repo.unfiltered() |
567 repo = repo.unfiltered() |
561 self._retractboundary(repo, tr, targetphase, [], revs=revs) |
568 self._retractboundary(repo, tr, targetphase, [], revs=revs) |
612 roots = { |
619 roots = { |
613 ctx.node() |
620 ctx.node() |
614 for ctx in repo.set(b'roots((%ln::) - %ld)', olds, affected) |
621 for ctx in repo.set(b'roots((%ln::) - %ld)', olds, affected) |
615 } |
622 } |
616 if olds != roots: |
623 if olds != roots: |
617 self._updateroots(phase, roots, tr) |
624 self._updateroots(repo, phase, roots, tr) |
618 # some roots may need to be declared for lower phases |
625 # some roots may need to be declared for lower phases |
619 delroots.extend(olds - roots) |
626 delroots.extend(olds - roots) |
620 if not dryrun: |
627 if not dryrun: |
621 # declare deleted root in the target phase |
628 # declare deleted root in the target phase |
622 if targetphase != 0: |
629 if targetphase != 0: |
715 assert repo.filtername is None |
725 assert repo.filtername is None |
716 to_rev = repo.changelog.index.rev |
726 to_rev = repo.changelog.index.rev |
717 for targetphase, nodes in list(self._phaseroots.items()): |
727 for targetphase, nodes in list(self._phaseroots.items()): |
718 filtered = {n for n in nodes if to_rev(n) >= strip_rev} |
728 filtered = {n for n in nodes if to_rev(n) >= strip_rev} |
719 if filtered: |
729 if filtered: |
720 self._updateroots(targetphase, nodes - filtered, tr) |
730 self._updateroots(repo, targetphase, nodes - filtered, tr) |
721 self.invalidate() |
731 self.invalidate() |
722 |
732 |
723 def filterunknown(self, repo: "localrepo.localrepository") -> None: |
733 def filterunknown(self, repo: "localrepo.localrepository") -> None: |
724 """remove unknown nodes from the phase boundary |
734 """remove unknown nodes from the phase boundary |
725 |
735 |