168 Return (roots, dirty) where dirty is true if roots differ from |
168 Return (roots, dirty) where dirty is true if roots differ from |
169 what is being stored. |
169 what is being stored. |
170 """ |
170 """ |
171 repo = repo.unfiltered() |
171 repo = repo.unfiltered() |
172 dirty = False |
172 dirty = False |
173 roots = [set() for i in range(max(allphases) + 1)] |
173 roots = {i: set() for i in allphases} |
174 try: |
174 try: |
175 f, pending = txnutil.trypending(repo.root, repo.svfs, b'phaseroots') |
175 f, pending = txnutil.trypending(repo.root, repo.svfs, b'phaseroots') |
176 try: |
176 try: |
177 for line in f: |
177 for line in f: |
178 phase, nh = line.split() |
178 phase, nh = line.split() |
331 repo = repo.unfiltered() |
331 repo = repo.unfiltered() |
332 cl = repo.changelog |
332 cl = repo.changelog |
333 if len(cl) >= self._loadedrevslen: |
333 if len(cl) >= self._loadedrevslen: |
334 self.invalidate() |
334 self.invalidate() |
335 self.loadphaserevs(repo) |
335 self.loadphaserevs(repo) |
336 return any(self.phaseroots[1:]) |
336 return any( |
|
337 revs |
|
338 for phase, revs in pycompat.iteritems(self.phaseroots) |
|
339 if phase != public |
|
340 ) |
337 |
341 |
338 def nonpublicphaseroots(self, repo): |
342 def nonpublicphaseroots(self, repo): |
339 """returns the roots of all non-public phases |
343 """returns the roots of all non-public phases |
340 |
344 |
341 The roots are not minimized, so if the secret revisions are |
345 The roots are not minimized, so if the secret revisions are |
344 repo = repo.unfiltered() |
348 repo = repo.unfiltered() |
345 cl = repo.changelog |
349 cl = repo.changelog |
346 if len(cl) >= self._loadedrevslen: |
350 if len(cl) >= self._loadedrevslen: |
347 self.invalidate() |
351 self.invalidate() |
348 self.loadphaserevs(repo) |
352 self.loadphaserevs(repo) |
349 return set().union(*[roots for roots in self.phaseroots[1:] if roots]) |
353 return set().union( |
|
354 *[ |
|
355 revs |
|
356 for phase, revs in pycompat.iteritems(self.phaseroots) |
|
357 if phase != public |
|
358 ] |
|
359 ) |
350 |
360 |
351 def getrevset(self, repo, phases, subset=None): |
361 def getrevset(self, repo, phases, subset=None): |
352 """return a smartset for the given phases""" |
362 """return a smartset for the given phases""" |
353 self.loadphaserevs(repo) # ensure phase's sets are loaded |
363 self.loadphaserevs(repo) # ensure phase's sets are loaded |
354 phases = set(phases) |
364 phases = set(phases) |
403 |
413 |
404 def copy(self): |
414 def copy(self): |
405 # Shallow copy meant to ensure isolation in |
415 # Shallow copy meant to ensure isolation in |
406 # advance/retractboundary(), nothing more. |
416 # advance/retractboundary(), nothing more. |
407 ph = self.__class__(None, None, _load=False) |
417 ph = self.__class__(None, None, _load=False) |
408 ph.phaseroots = self.phaseroots[:] |
418 ph.phaseroots = self.phaseroots.copy() |
409 ph.dirty = self.dirty |
419 ph.dirty = self.dirty |
410 ph.opener = self.opener |
420 ph.opener = self.opener |
411 ph._loadedrevslen = self._loadedrevslen |
421 ph._loadedrevslen = self._loadedrevslen |
412 ph._phasesets = self._phasesets |
422 ph._phasesets = self._phasesets |
413 return ph |
423 return ph |
423 ): |
433 ): |
424 setattr(self, a, getattr(phcache, a)) |
434 setattr(self, a, getattr(phcache, a)) |
425 |
435 |
426 def _getphaserevsnative(self, repo): |
436 def _getphaserevsnative(self, repo): |
427 repo = repo.unfiltered() |
437 repo = repo.unfiltered() |
428 nativeroots = [] |
438 return repo.changelog.computephases(self.phaseroots) |
429 for phase in trackedphases: |
|
430 nativeroots.append( |
|
431 pycompat.maplist(repo.changelog.rev, self.phaseroots[phase]) |
|
432 ) |
|
433 revslen, phasesets = repo.changelog.computephases(nativeroots) |
|
434 phasesets2 = [set() for phase in range(max(allphases) + 1)] |
|
435 for phase, phaseset in zip(allphases, phasesets): |
|
436 phasesets2[phase] = phaseset |
|
437 return revslen, phasesets2 |
|
438 |
439 |
439 def _computephaserevspure(self, repo): |
440 def _computephaserevspure(self, repo): |
440 repo = repo.unfiltered() |
441 repo = repo.unfiltered() |
441 cl = repo.changelog |
442 cl = repo.changelog |
442 self._phasesets = [set() for phase in range(max(allphases) + 1)] |
443 self._phasesets = {phase: set() for phase in allphases} |
443 lowerroots = set() |
444 lowerroots = set() |
444 for phase in reversed(trackedphases): |
445 for phase in reversed(trackedphases): |
445 roots = pycompat.maplist(cl.rev, self.phaseroots[phase]) |
446 roots = pycompat.maplist(cl.rev, self.phaseroots[phase]) |
446 if roots: |
447 if roots: |
447 ps = set(cl.descendants(roots)) |
448 ps = set(cl.descendants(roots)) |
491 self._write(f) |
492 self._write(f) |
492 finally: |
493 finally: |
493 f.close() |
494 f.close() |
494 |
495 |
495 def _write(self, fp): |
496 def _write(self, fp): |
496 for phase, roots in enumerate(self.phaseroots): |
497 for phase, roots in pycompat.iteritems(self.phaseroots): |
497 for h in sorted(roots): |
498 for h in sorted(roots): |
498 fp.write(b'%i %s\n' % (phase, hex(h))) |
499 fp.write(b'%i %s\n' % (phase, hex(h))) |
499 self.dirty = False |
500 self.dirty = False |
500 |
501 |
501 def _updateroots(self, phase, newroots, tr): |
502 def _updateroots(self, phase, newroots, tr): |
573 self._retractboundary(repo, tr, targetphase, delroots) |
574 self._retractboundary(repo, tr, targetphase, delroots) |
574 repo.invalidatevolatilesets() |
575 repo.invalidatevolatilesets() |
575 return changes |
576 return changes |
576 |
577 |
577 def retractboundary(self, repo, tr, targetphase, nodes): |
578 def retractboundary(self, repo, tr, targetphase, nodes): |
578 oldroots = self.phaseroots[: targetphase + 1] |
579 oldroots = { |
|
580 phase: revs |
|
581 for phase, revs in pycompat.iteritems(self.phaseroots) |
|
582 if phase <= targetphase |
|
583 } |
579 if tr is None: |
584 if tr is None: |
580 phasetracking = None |
585 phasetracking = None |
581 else: |
586 else: |
582 phasetracking = tr.changes.get(b'phases') |
587 phasetracking = tr.changes.get(b'phases') |
583 repo = repo.unfiltered() |
588 repo = repo.unfiltered() |
592 affected = set(repo.revs(b'(%ln::) - (%ln::)', new, old)) |
597 affected = set(repo.revs(b'(%ln::) - (%ln::)', new, old)) |
593 |
598 |
594 # find the phase of the affected revision |
599 # find the phase of the affected revision |
595 for phase in pycompat.xrange(targetphase, -1, -1): |
600 for phase in pycompat.xrange(targetphase, -1, -1): |
596 if phase: |
601 if phase: |
597 roots = oldroots[phase] |
602 roots = oldroots.get(phase, []) |
598 revs = set(repo.revs(b'%ln::%ld', roots, affected)) |
603 revs = set(repo.revs(b'%ln::%ld', roots, affected)) |
599 affected -= revs |
604 affected -= revs |
600 else: # public phase |
605 else: # public phase |
601 revs = affected |
606 revs = affected |
602 for r in sorted(revs): |
607 for r in sorted(revs): |
646 |
651 |
647 Nothing is lost as unknown nodes only hold data for their descendants. |
652 Nothing is lost as unknown nodes only hold data for their descendants. |
648 """ |
653 """ |
649 filtered = False |
654 filtered = False |
650 has_node = repo.changelog.index.has_node # to filter unknown nodes |
655 has_node = repo.changelog.index.has_node # to filter unknown nodes |
651 for phase, nodes in enumerate(self.phaseroots): |
656 for phase, nodes in pycompat.iteritems(self.phaseroots): |
652 missing = sorted(node for node in nodes if not has_node(node)) |
657 missing = sorted(node for node in nodes if not has_node(node)) |
653 if missing: |
658 if missing: |
654 for mnode in missing: |
659 for mnode in missing: |
655 repo.ui.debug( |
660 repo.ui.debug( |
656 b'removing unknown node %s from %i-phase boundary\n' |
661 b'removing unknown node %s from %i-phase boundary\n' |