Mercurial > hg
comparison mercurial/phases.py @ 46644:77e129be10de
typing: add some type annotations to mercurial/phases.py
Some of these were helpful in typing other modules, and then I typed the
easy-ish ones. Black forces the long `Phasedefaults` definition to be wrapped,
which pytype seems OK with (as shown with `reveal_type()`), but it does seem to
confuse PyCharm a bit.
Differential Revision: https://phab.mercurial-scm.org/D10126
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Sat, 06 Mar 2021 18:51:33 -0500 |
parents | 5d65e04b6a80 |
children | d55b71393907 |
comparison
equal
deleted
inserted
replaced
46643:eef13b940887 | 46644:77e129be10de |
---|---|
125 smartset, | 125 smartset, |
126 txnutil, | 126 txnutil, |
127 util, | 127 util, |
128 ) | 128 ) |
129 | 129 |
130 if pycompat.TYPE_CHECKING: | |
131 from typing import ( | |
132 Any, | |
133 Callable, | |
134 Dict, | |
135 Iterable, | |
136 List, | |
137 Optional, | |
138 Set, | |
139 Tuple, | |
140 ) | |
141 from . import ( | |
142 localrepo, | |
143 ui as uimod, | |
144 ) | |
145 | |
146 Phaseroots = Dict[int, Set[bytes]] | |
147 Phasedefaults = List[ | |
148 Callable[[localrepo.localrepository, Phaseroots], Phaseroots] | |
149 ] | |
150 | |
151 | |
130 _fphasesentry = struct.Struct(b'>i20s') | 152 _fphasesentry = struct.Struct(b'>i20s') |
131 | 153 |
132 # record phase index | 154 # record phase index |
133 public, draft, secret = range(3) | 155 public, draft, secret = range(3) # type: int |
134 archived = 32 # non-continuous for compatibility | 156 archived = 32 # non-continuous for compatibility |
135 internal = 96 # non-continuous for compatibility | 157 internal = 96 # non-continuous for compatibility |
136 allphases = (public, draft, secret, archived, internal) | 158 allphases = (public, draft, secret, archived, internal) |
137 trackedphases = (draft, secret, archived, internal) | 159 trackedphases = (draft, secret, archived, internal) |
138 # record phase names | 160 # record phase names |
152 remotehiddenphases = (secret, archived, internal) | 174 remotehiddenphases = (secret, archived, internal) |
153 localhiddenphases = (internal, archived) | 175 localhiddenphases = (internal, archived) |
154 | 176 |
155 | 177 |
156 def supportinternal(repo): | 178 def supportinternal(repo): |
179 # type: (localrepo.localrepository) -> bool | |
157 """True if the internal phase can be used on a repository""" | 180 """True if the internal phase can be used on a repository""" |
158 return requirements.INTERNAL_PHASE_REQUIREMENT in repo.requirements | 181 return requirements.INTERNAL_PHASE_REQUIREMENT in repo.requirements |
159 | 182 |
160 | 183 |
161 def _readroots(repo, phasedefaults=None): | 184 def _readroots(repo, phasedefaults=None): |
185 # type: (localrepo.localrepository, Optional[Phasedefaults]) -> Tuple[Phaseroots, bool] | |
162 """Read phase roots from disk | 186 """Read phase roots from disk |
163 | 187 |
164 phasedefaults is a list of fn(repo, roots) callable, which are | 188 phasedefaults is a list of fn(repo, roots) callable, which are |
165 executed if the phase roots file does not exist. When phases are | 189 executed if the phase roots file does not exist. When phases are |
166 being initialized on an existing repository, this could be used to | 190 being initialized on an existing repository, this could be used to |
189 dirty = True | 213 dirty = True |
190 return roots, dirty | 214 return roots, dirty |
191 | 215 |
192 | 216 |
193 def binaryencode(phasemapping): | 217 def binaryencode(phasemapping): |
218 # type: (Dict[int, List[bytes]]) -> bytes | |
194 """encode a 'phase -> nodes' mapping into a binary stream | 219 """encode a 'phase -> nodes' mapping into a binary stream |
195 | 220 |
196 The revision lists are encoded as (phase, root) pairs. | 221 The revision lists are encoded as (phase, root) pairs. |
197 """ | 222 """ |
198 binarydata = [] | 223 binarydata = [] |
201 binarydata.append(_fphasesentry.pack(phase, head)) | 226 binarydata.append(_fphasesentry.pack(phase, head)) |
202 return b''.join(binarydata) | 227 return b''.join(binarydata) |
203 | 228 |
204 | 229 |
205 def binarydecode(stream): | 230 def binarydecode(stream): |
231 # type: (...) -> Dict[int, List[bytes]] | |
206 """decode a binary stream into a 'phase -> nodes' mapping | 232 """decode a binary stream into a 'phase -> nodes' mapping |
207 | 233 |
208 The (phase, root) pairs are turned back into a dictionary with | 234 The (phase, root) pairs are turned back into a dictionary with |
209 the phase as index and the aggregated roots of that phase as value.""" | 235 the phase as index and the aggregated roots of that phase as value.""" |
210 headsbyphase = {i: [] for i in allphases} | 236 headsbyphase = {i: [] for i in allphases} |
319 data.insert(low + 1, (pycompat.xrange(rev, rev + 1), t)) | 345 data.insert(low + 1, (pycompat.xrange(rev, rev + 1), t)) |
320 | 346 |
321 | 347 |
322 class phasecache(object): | 348 class phasecache(object): |
323 def __init__(self, repo, phasedefaults, _load=True): | 349 def __init__(self, repo, phasedefaults, _load=True): |
350 # type: (localrepo.localrepository, Optional[Phasedefaults], bool) -> None | |
324 if _load: | 351 if _load: |
325 # Cheap trick to allow shallow-copy without copy module | 352 # Cheap trick to allow shallow-copy without copy module |
326 self.phaseroots, self.dirty = _readroots(repo, phasedefaults) | 353 self.phaseroots, self.dirty = _readroots(repo, phasedefaults) |
327 self._loadedrevslen = 0 | 354 self._loadedrevslen = 0 |
328 self._phasesets = None | 355 self._phasesets = None |
329 self.filterunknown(repo) | 356 self.filterunknown(repo) |
330 self.opener = repo.svfs | 357 self.opener = repo.svfs |
331 | 358 |
332 def hasnonpublicphases(self, repo): | 359 def hasnonpublicphases(self, repo): |
360 # type: (localrepo.localrepository) -> bool | |
333 """detect if there are revisions with non-public phase""" | 361 """detect if there are revisions with non-public phase""" |
334 repo = repo.unfiltered() | 362 repo = repo.unfiltered() |
335 cl = repo.changelog | 363 cl = repo.changelog |
336 if len(cl) >= self._loadedrevslen: | 364 if len(cl) >= self._loadedrevslen: |
337 self.invalidate() | 365 self.invalidate() |
341 for phase, revs in pycompat.iteritems(self.phaseroots) | 369 for phase, revs in pycompat.iteritems(self.phaseroots) |
342 if phase != public | 370 if phase != public |
343 ) | 371 ) |
344 | 372 |
345 def nonpublicphaseroots(self, repo): | 373 def nonpublicphaseroots(self, repo): |
374 # type: (localrepo.localrepository) -> Set[bytes] | |
346 """returns the roots of all non-public phases | 375 """returns the roots of all non-public phases |
347 | 376 |
348 The roots are not minimized, so if the secret revisions are | 377 The roots are not minimized, so if the secret revisions are |
349 descendants of draft revisions, their roots will still be present. | 378 descendants of draft revisions, their roots will still be present. |
350 """ | 379 """ |
360 if phase != public | 389 if phase != public |
361 ] | 390 ] |
362 ) | 391 ) |
363 | 392 |
364 def getrevset(self, repo, phases, subset=None): | 393 def getrevset(self, repo, phases, subset=None): |
394 # type: (localrepo.localrepository, Iterable[int], Optional[Any]) -> Any | |
395 # TODO: finish typing this | |
365 """return a smartset for the given phases""" | 396 """return a smartset for the given phases""" |
366 self.loadphaserevs(repo) # ensure phase's sets are loaded | 397 self.loadphaserevs(repo) # ensure phase's sets are loaded |
367 phases = set(phases) | 398 phases = set(phases) |
368 publicphase = public in phases | 399 publicphase = public in phases |
369 | 400 |
455 lowerroots.update(ps) | 486 lowerroots.update(ps) |
456 self._phasesets[phase] = ps | 487 self._phasesets[phase] = ps |
457 self._loadedrevslen = len(cl) | 488 self._loadedrevslen = len(cl) |
458 | 489 |
459 def loadphaserevs(self, repo): | 490 def loadphaserevs(self, repo): |
491 # type: (localrepo.localrepository) -> None | |
460 """ensure phase information is loaded in the object""" | 492 """ensure phase information is loaded in the object""" |
461 if self._phasesets is None: | 493 if self._phasesets is None: |
462 try: | 494 try: |
463 res = self._getphaserevsnative(repo) | 495 res = self._getphaserevsnative(repo) |
464 self._loadedrevslen, self._phasesets = res | 496 self._loadedrevslen, self._phasesets = res |
468 def invalidate(self): | 500 def invalidate(self): |
469 self._loadedrevslen = 0 | 501 self._loadedrevslen = 0 |
470 self._phasesets = None | 502 self._phasesets = None |
471 | 503 |
472 def phase(self, repo, rev): | 504 def phase(self, repo, rev): |
505 # type: (localrepo.localrepository, int) -> int | |
473 # We need a repo argument here to be able to build _phasesets | 506 # We need a repo argument here to be able to build _phasesets |
474 # if necessary. The repository instance is not stored in | 507 # if necessary. The repository instance is not stored in |
475 # phasecache to avoid reference cycles. The changelog instance | 508 # phasecache to avoid reference cycles. The changelog instance |
476 # is not stored because it is a filecache() property and can | 509 # is not stored because it is a filecache() property and can |
477 # be replaced without us being notified. | 510 # be replaced without us being notified. |
650 ) | 683 ) |
651 return True | 684 return True |
652 return False | 685 return False |
653 | 686 |
654 def filterunknown(self, repo): | 687 def filterunknown(self, repo): |
688 # type: (localrepo.localrepository) -> None | |
655 """remove unknown nodes from the phase boundary | 689 """remove unknown nodes from the phase boundary |
656 | 690 |
657 Nothing is lost as unknown nodes only hold data for their descendants. | 691 Nothing is lost as unknown nodes only hold data for their descendants. |
658 """ | 692 """ |
659 filtered = False | 693 filtered = False |
727 phcache.registernew(repo, tr, targetphase, revs) | 761 phcache.registernew(repo, tr, targetphase, revs) |
728 repo._phasecache.replace(phcache) | 762 repo._phasecache.replace(phcache) |
729 | 763 |
730 | 764 |
731 def listphases(repo): | 765 def listphases(repo): |
766 # type: (localrepo.localrepository) -> Dict[bytes, bytes] | |
732 """List phases root for serialization over pushkey""" | 767 """List phases root for serialization over pushkey""" |
733 # Use ordered dictionary so behavior is deterministic. | 768 # Use ordered dictionary so behavior is deterministic. |
734 keys = util.sortdict() | 769 keys = util.sortdict() |
735 value = b'%i' % draft | 770 value = b'%i' % draft |
736 cl = repo.unfiltered().changelog | 771 cl = repo.unfiltered().changelog |
758 keys[b'publishing'] = b'True' | 793 keys[b'publishing'] = b'True' |
759 return keys | 794 return keys |
760 | 795 |
761 | 796 |
762 def pushphase(repo, nhex, oldphasestr, newphasestr): | 797 def pushphase(repo, nhex, oldphasestr, newphasestr): |
798 # type: (localrepo.localrepository, bytes, bytes, bytes) -> bool | |
763 """List phases root for serialization over pushkey""" | 799 """List phases root for serialization over pushkey""" |
764 repo = repo.unfiltered() | 800 repo = repo.unfiltered() |
765 with repo.lock(): | 801 with repo.lock(): |
766 currentphase = repo[nhex].phase() | 802 currentphase = repo[nhex].phase() |
767 newphase = abs(int(newphasestr)) # let's avoid negative index surprise | 803 newphase = abs(int(newphasestr)) # let's avoid negative index surprise |
907 | 943 |
908 return pycompat.maplist(cl.node, sorted(new_heads)) | 944 return pycompat.maplist(cl.node, sorted(new_heads)) |
909 | 945 |
910 | 946 |
911 def newcommitphase(ui): | 947 def newcommitphase(ui): |
948 # type: (uimod.ui) -> int | |
912 """helper to get the target phase of new commit | 949 """helper to get the target phase of new commit |
913 | 950 |
914 Handle all possible values for the phases.new-commit options. | 951 Handle all possible values for the phases.new-commit options. |
915 | 952 |
916 """ | 953 """ |
922 _(b"phases.new-commit: not a valid phase name ('%s')") % v | 959 _(b"phases.new-commit: not a valid phase name ('%s')") % v |
923 ) | 960 ) |
924 | 961 |
925 | 962 |
926 def hassecret(repo): | 963 def hassecret(repo): |
964 # type: (localrepo.localrepository) -> bool | |
927 """utility function that check if a repo have any secret changeset.""" | 965 """utility function that check if a repo have any secret changeset.""" |
928 return bool(repo._phasecache.phaseroots[secret]) | 966 return bool(repo._phasecache.phaseroots[secret]) |
929 | 967 |
930 | 968 |
931 def preparehookargs(node, old, new): | 969 def preparehookargs(node, old, new): |
970 # type: (bytes, Optional[int], Optional[int]) -> Dict[bytes, bytes] | |
932 if old is None: | 971 if old is None: |
933 old = b'' | 972 old = b'' |
934 else: | 973 else: |
935 old = phasenames[old] | 974 old = phasenames[old] |
936 return {b'node': node, b'oldphase': old, b'phase': phasenames[new]} | 975 return {b'node': node, b'oldphase': old, b'phase': phasenames[new]} |