##// END OF EJS Templates
typing: add type annotations to the dirstate classes...
Matt Harbison -
r52822:93d872a0 default
parent child Browse files
Show More
@@ -3,6 +3,16 from __future__ import annotations
3 import contextlib
3 import contextlib
4 import os
4 import os
5
5
6 from typing import (
7 Any,
8 Dict,
9 Iterable,
10 Iterator,
11 List,
12 Optional,
13 Tuple,
14 )
15
6 from mercurial.node import sha1nodeconstants
16 from mercurial.node import sha1nodeconstants
7 from mercurial import (
17 from mercurial import (
8 dirstatemap,
18 dirstatemap,
@@ -96,7 +106,7 class gitdirstate(intdirstate.idirstate)
96 )
106 )
97 return self._map
107 return self._map
98
108
99 def p1(self):
109 def p1(self) -> bytes:
100 try:
110 try:
101 return self.git.head.peel().id.raw
111 return self.git.head.peel().id.raw
102 except pygit2.GitError:
112 except pygit2.GitError:
@@ -104,11 +114,11 class gitdirstate(intdirstate.idirstate)
104 # empty repository.
114 # empty repository.
105 return sha1nodeconstants.nullid
115 return sha1nodeconstants.nullid
106
116
107 def p2(self):
117 def p2(self) -> bytes:
108 # TODO: MERGE_HEAD? something like that, right?
118 # TODO: MERGE_HEAD? something like that, right?
109 return sha1nodeconstants.nullid
119 return sha1nodeconstants.nullid
110
120
111 def setparents(self, p1, p2=None):
121 def setparents(self, p1: bytes, p2: Optional[bytes] = None):
112 if p2 is None:
122 if p2 is None:
113 p2 = sha1nodeconstants.nullid
123 p2 = sha1nodeconstants.nullid
114 assert p2 == sha1nodeconstants.nullid, b'TODO merging support'
124 assert p2 == sha1nodeconstants.nullid, b'TODO merging support'
@@ -120,17 +130,17 class gitdirstate(intdirstate.idirstate)
120 os.path.join(self._root, b'.git', b'index')
130 os.path.join(self._root, b'.git', b'index')
121 )
131 )
122
132
123 def branch(self):
133 def branch(self) -> bytes:
124 return b'default'
134 return b'default'
125
135
126 def parents(self):
136 def parents(self) -> List[bytes]:
127 # TODO how on earth do we find p2 if a merge is in flight?
137 # TODO how on earth do we find p2 if a merge is in flight?
128 return [self.p1(), sha1nodeconstants.nullid]
138 return [self.p1(), sha1nodeconstants.nullid]
129
139
130 def __iter__(self):
140 def __iter__(self) -> Iterator[bytes]:
131 return (pycompat.fsencode(f.path) for f in self.git.index)
141 return (pycompat.fsencode(f.path) for f in self.git.index)
132
142
133 def items(self):
143 def items(self) -> Iterator[Tuple[bytes, intdirstate.DirstateItemT]]:
134 for ie in self.git.index:
144 for ie in self.git.index:
135 yield ie.path, None # value should be a DirstateItem
145 yield ie.path, None # value should be a DirstateItem
136
146
@@ -144,14 +154,21 class gitdirstate(intdirstate.idirstate)
144 return b'?'
154 return b'?'
145 return _STATUS_MAP[gs]
155 return _STATUS_MAP[gs]
146
156
147 def __contains__(self, filename):
157 def __contains__(self, filename: Any) -> bool:
148 try:
158 try:
149 gs = self.git.status_file(filename)
159 gs = self.git.status_file(filename)
150 return _STATUS_MAP[gs] != b'?'
160 return _STATUS_MAP[gs] != b'?'
151 except KeyError:
161 except KeyError:
152 return False
162 return False
153
163
154 def status(self, match, subrepos, ignored, clean, unknown):
164 def status(
165 self,
166 match: matchmod.basematcher,
167 subrepos: bool,
168 ignored: bool,
169 clean: bool,
170 unknown: bool,
171 ) -> intdirstate.StatusReturnT:
155 listclean = clean
172 listclean = clean
156 # TODO handling of clean files - can we get that from git.status()?
173 # TODO handling of clean files - can we get that from git.status()?
157 modified, added, removed, deleted, unknown, ignored, clean = (
174 modified, added, removed, deleted, unknown, ignored, clean = (
@@ -224,24 +241,28 class gitdirstate(intdirstate.idirstate)
224 mtime_boundary,
241 mtime_boundary,
225 )
242 )
226
243
227 def flagfunc(self, buildfallback):
244 def flagfunc(
245 self, buildfallback: intdirstate.FlagFuncFallbackT
246 ) -> intdirstate.FlagFuncReturnT:
228 # TODO we can do better
247 # TODO we can do better
229 return buildfallback()
248 return buildfallback()
230
249
231 def getcwd(self):
250 def getcwd(self) -> bytes:
232 # TODO is this a good way to do this?
251 # TODO is this a good way to do this?
233 return os.path.dirname(
252 return os.path.dirname(
234 os.path.dirname(pycompat.fsencode(self.git.path))
253 os.path.dirname(pycompat.fsencode(self.git.path))
235 )
254 )
236
255
237 def get_entry(self, path):
256 def get_entry(self, path: bytes) -> intdirstate.DirstateItemT:
238 """return a DirstateItem for the associated path"""
257 """return a DirstateItem for the associated path"""
239 entry = self._map.get(path)
258 entry = self._map.get(path)
240 if entry is None:
259 if entry is None:
241 return DirstateItem()
260 return DirstateItem()
242 return entry
261 return entry
243
262
244 def normalize(self, path, isknown=False, ignoremissing=False):
263 def normalize(
264 self, path: bytes, isknown: bool = False, ignoremissing: bool = False
265 ) -> bytes:
245 normed = util.normcase(path)
266 normed = util.normcase(path)
246 assert normed == path, b"TODO handling of case folding: %s != %s" % (
267 assert normed == path, b"TODO handling of case folding: %s != %s" % (
247 normed,
268 normed,
@@ -250,10 +271,10 class gitdirstate(intdirstate.idirstate)
250 return path
271 return path
251
272
252 @property
273 @property
253 def _checklink(self):
274 def _checklink(self) -> bool:
254 return util.checklink(os.path.dirname(pycompat.fsencode(self.git.path)))
275 return util.checklink(os.path.dirname(pycompat.fsencode(self.git.path)))
255
276
256 def copies(self):
277 def copies(self) -> Dict[bytes, bytes]:
257 # TODO support copies?
278 # TODO support copies?
258 return {}
279 return {}
259
280
@@ -261,18 +282,18 class gitdirstate(intdirstate.idirstate)
261 _filecache = set()
282 _filecache = set()
262
283
263 @property
284 @property
264 def is_changing_parents(self):
285 def is_changing_parents(self) -> bool:
265 # TODO: we need to implement the context manager bits and
286 # TODO: we need to implement the context manager bits and
266 # correctly stage/revert index edits.
287 # correctly stage/revert index edits.
267 return False
288 return False
268
289
269 @property
290 @property
270 def is_changing_any(self):
291 def is_changing_any(self) -> bool:
271 # TODO: we need to implement the context manager bits and
292 # TODO: we need to implement the context manager bits and
272 # correctly stage/revert index edits.
293 # correctly stage/revert index edits.
273 return False
294 return False
274
295
275 def write(self, tr):
296 def write(self, tr: Optional[intdirstate.TransactionT]) -> None:
276 # TODO: call parent change callbacks
297 # TODO: call parent change callbacks
277
298
278 if tr:
299 if tr:
@@ -284,7 +305,7 class gitdirstate(intdirstate.idirstate)
284 else:
305 else:
285 self.git.index.write()
306 self.git.index.write()
286
307
287 def pathto(self, f, cwd=None):
308 def pathto(self, f: bytes, cwd: Optional[bytes] = None) -> bytes:
288 if cwd is None:
309 if cwd is None:
289 cwd = self.getcwd()
310 cwd = self.getcwd()
290 # TODO core dirstate does something about slashes here
311 # TODO core dirstate does something about slashes here
@@ -292,11 +313,11 class gitdirstate(intdirstate.idirstate)
292 r = util.pathto(self._root, cwd, f)
313 r = util.pathto(self._root, cwd, f)
293 return r
314 return r
294
315
295 def matches(self, match):
316 def matches(self, match: matchmod.basematcher) -> Iterable[bytes]:
296 for x in self.git.index:
317 for x in self.git.index:
297 p = pycompat.fsencode(x.path)
318 p = pycompat.fsencode(x.path)
298 if match(p):
319 if match(p):
299 yield p
320 yield p # TODO: return list instead of yielding?
300
321
301 def set_clean(self, f, parentfiledata):
322 def set_clean(self, f, parentfiledata):
302 """Mark a file normal and clean."""
323 """Mark a file normal and clean."""
@@ -308,7 +329,14 class gitdirstate(intdirstate.idirstate)
308 # TODO: for now we just let libgit2 re-stat the file. We can
329 # TODO: for now we just let libgit2 re-stat the file. We can
309 # clearly do better.
330 # clearly do better.
310
331
311 def walk(self, match, subrepos, unknown, ignored, full=True):
332 def walk(
333 self,
334 match: matchmod.basematcher,
335 subrepos: Any,
336 unknown: bool,
337 ignored: bool,
338 full: bool = True,
339 ) -> intdirstate.WalkReturnT:
312 # TODO: we need to use .status() and not iterate the index,
340 # TODO: we need to use .status() and not iterate the index,
313 # because the index doesn't force a re-walk and so `hg add` of
341 # because the index doesn't force a re-walk and so `hg add` of
314 # a new file without an intervening call to status will
342 # a new file without an intervening call to status will
@@ -370,7 +398,7 class gitdirstate(intdirstate.idirstate)
370 index.remove(pycompat.fsdecode(f))
398 index.remove(pycompat.fsdecode(f))
371 index.write()
399 index.write()
372
400
373 def copied(self, path):
401 def copied(self, file: bytes) -> Optional[bytes]:
374 # TODO: track copies?
402 # TODO: track copies?
375 return None
403 return None
376
404
@@ -387,11 +415,15 class gitdirstate(intdirstate.idirstate)
387 # TODO: track this maybe?
415 # TODO: track this maybe?
388 yield
416 yield
389
417
390 def addparentchangecallback(self, category, callback):
418 def addparentchangecallback(
419 self, category: bytes, callback: intdirstate.AddParentChangeCallbackT
420 ) -> None:
391 # TODO: should this be added to the dirstate interface?
421 # TODO: should this be added to the dirstate interface?
392 self._plchangecallbacks[category] = callback
422 self._plchangecallbacks[category] = callback
393
423
394 def setbranch(self, branch, transaction):
424 def setbranch(
425 self, branch: bytes, transaction: Optional[intdirstate.TransactionT]
426 ) -> None:
395 raise error.Abort(
427 raise error.Abort(
396 b'git repos do not support branches. try using bookmarks'
428 b'git repos do not support branches. try using bookmarks'
397 )
429 )
@@ -13,6 +13,16 import os
13 import stat
13 import stat
14 import uuid
14 import uuid
15
15
16 from typing import (
17 Any,
18 Dict,
19 Iterable,
20 Iterator,
21 List,
22 Optional,
23 Tuple,
24 )
25
16 from .i18n import _
26 from .i18n import _
17
27
18 from hgdemandimport import tracing
28 from hgdemandimport import tracing
@@ -396,7 +406,7 class dirstate(intdirstate.idirstate):
396 raise error.ProgrammingError(msg)
406 raise error.ProgrammingError(msg)
397
407
398 @property
408 @property
399 def is_changing_any(self):
409 def is_changing_any(self) -> bool:
400 """Returns true if the dirstate is in the middle of a set of changes.
410 """Returns true if the dirstate is in the middle of a set of changes.
401
411
402 This returns True for any kind of change.
412 This returns True for any kind of change.
@@ -404,7 +414,7 class dirstate(intdirstate.idirstate):
404 return self._changing_level > 0
414 return self._changing_level > 0
405
415
406 @property
416 @property
407 def is_changing_parents(self):
417 def is_changing_parents(self) -> bool:
408 """Returns true if the dirstate is in the middle of a set of changes
418 """Returns true if the dirstate is in the middle of a set of changes
409 that modify the dirstate parent.
419 that modify the dirstate parent.
410 """
420 """
@@ -413,7 +423,7 class dirstate(intdirstate.idirstate):
413 return self._change_type == CHANGE_TYPE_PARENTS
423 return self._change_type == CHANGE_TYPE_PARENTS
414
424
415 @property
425 @property
416 def is_changing_files(self):
426 def is_changing_files(self) -> bool:
417 """Returns true if the dirstate is in the middle of a set of changes
427 """Returns true if the dirstate is in the middle of a set of changes
418 that modify the files tracked or their sources.
428 that modify the files tracked or their sources.
419 """
429 """
@@ -469,11 +479,11 class dirstate(intdirstate.idirstate):
469 def _pl(self):
479 def _pl(self):
470 return self._map.parents()
480 return self._map.parents()
471
481
472 def hasdir(self, d):
482 def hasdir(self, d: bytes) -> bool:
473 return self._map.hastrackeddir(d)
483 return self._map.hastrackeddir(d)
474
484
475 @rootcache(b'.hgignore')
485 @rootcache(b'.hgignore')
476 def _ignore(self):
486 def _ignore(self) -> matchmod.basematcher:
477 files = self._ignorefiles()
487 files = self._ignorefiles()
478 if not files:
488 if not files:
479 return matchmod.never()
489 return matchmod.never()
@@ -486,11 +496,11 class dirstate(intdirstate.idirstate):
486 return self._ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/'
496 return self._ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/'
487
497
488 @propertycache
498 @propertycache
489 def _checklink(self):
499 def _checklink(self) -> bool:
490 return util.checklink(self._root)
500 return util.checklink(self._root)
491
501
492 @propertycache
502 @propertycache
493 def _checkexec(self):
503 def _checkexec(self) -> bool:
494 return bool(util.checkexec(self._root))
504 return bool(util.checkexec(self._root))
495
505
496 @propertycache
506 @propertycache
@@ -502,7 +512,9 class dirstate(intdirstate.idirstate):
502 # it's safe because f is always a relative path
512 # it's safe because f is always a relative path
503 return self._rootdir + f
513 return self._rootdir + f
504
514
505 def flagfunc(self, buildfallback):
515 def flagfunc(
516 self, buildfallback: intdirstate.FlagFuncFallbackT
517 ) -> intdirstate.FlagFuncReturnT:
506 """build a callable that returns flags associated with a filename
518 """build a callable that returns flags associated with a filename
507
519
508 The information is extracted from three possible layers:
520 The information is extracted from three possible layers:
@@ -514,7 +526,7 class dirstate(intdirstate.idirstate):
514 # small hack to cache the result of buildfallback()
526 # small hack to cache the result of buildfallback()
515 fallback_func = []
527 fallback_func = []
516
528
517 def get_flags(x):
529 def get_flags(x: bytes) -> bytes:
518 entry = None
530 entry = None
519 fallback_value = None
531 fallback_value = None
520 try:
532 try:
@@ -565,7 +577,7 class dirstate(intdirstate.idirstate):
565 return forcecwd
577 return forcecwd
566 return encoding.getcwd()
578 return encoding.getcwd()
567
579
568 def getcwd(self):
580 def getcwd(self) -> bytes:
569 """Return the path from which a canonical path is calculated.
581 """Return the path from which a canonical path is calculated.
570
582
571 This path should be used to resolve file patterns or to convert
583 This path should be used to resolve file patterns or to convert
@@ -585,7 +597,7 class dirstate(intdirstate.idirstate):
585 # we're outside the repo. return an absolute path.
597 # we're outside the repo. return an absolute path.
586 return cwd
598 return cwd
587
599
588 def pathto(self, f, cwd=None):
600 def pathto(self, f: bytes, cwd: Optional[bytes] = None) -> bytes:
589 if cwd is None:
601 if cwd is None:
590 cwd = self.getcwd()
602 cwd = self.getcwd()
591 path = util.pathto(self._root, cwd, f)
603 path = util.pathto(self._root, cwd, f)
@@ -593,31 +605,31 class dirstate(intdirstate.idirstate):
593 return util.pconvert(path)
605 return util.pconvert(path)
594 return path
606 return path
595
607
596 def get_entry(self, path):
608 def get_entry(self, path: bytes) -> intdirstate.DirstateItemT:
597 """return a DirstateItem for the associated path"""
609 """return a DirstateItem for the associated path"""
598 entry = self._map.get(path)
610 entry = self._map.get(path)
599 if entry is None:
611 if entry is None:
600 return DirstateItem()
612 return DirstateItem()
601 return entry
613 return entry
602
614
603 def __contains__(self, key):
615 def __contains__(self, key: Any) -> bool:
604 return key in self._map
616 return key in self._map
605
617
606 def __iter__(self):
618 def __iter__(self) -> Iterator[bytes]:
607 return iter(sorted(self._map))
619 return iter(sorted(self._map))
608
620
609 def items(self):
621 def items(self) -> Iterator[Tuple[bytes, intdirstate.DirstateItemT]]:
610 return self._map.items()
622 return self._map.items()
611
623
612 iteritems = items
624 iteritems = items
613
625
614 def parents(self):
626 def parents(self) -> List[bytes]:
615 return [self._validate(p) for p in self._pl]
627 return [self._validate(p) for p in self._pl]
616
628
617 def p1(self):
629 def p1(self) -> bytes:
618 return self._validate(self._pl[0])
630 return self._validate(self._pl[0])
619
631
620 def p2(self):
632 def p2(self) -> bytes:
621 return self._validate(self._pl[1])
633 return self._validate(self._pl[1])
622
634
623 @property
635 @property
@@ -625,11 +637,11 class dirstate(intdirstate.idirstate):
625 """True if a merge is in progress"""
637 """True if a merge is in progress"""
626 return self._pl[1] != self._nodeconstants.nullid
638 return self._pl[1] != self._nodeconstants.nullid
627
639
628 def branch(self):
640 def branch(self) -> bytes:
629 return encoding.tolocal(self._branch)
641 return encoding.tolocal(self._branch)
630
642
631 @requires_changing_parents
643 @requires_changing_parents
632 def setparents(self, p1, p2=None):
644 def setparents(self, p1: bytes, p2: Optional[bytes] = None):
633 """Set dirstate parents to p1 and p2.
645 """Set dirstate parents to p1 and p2.
634
646
635 When moving from two parents to one, "merged" entries a
647 When moving from two parents to one, "merged" entries a
@@ -655,7 +667,9 class dirstate(intdirstate.idirstate):
655 fold_p2 = oldp2 != nullid and p2 == nullid
667 fold_p2 = oldp2 != nullid and p2 == nullid
656 return self._map.setparents(p1, p2, fold_p2=fold_p2)
668 return self._map.setparents(p1, p2, fold_p2=fold_p2)
657
669
658 def setbranch(self, branch, transaction):
670 def setbranch(
671 self, branch: bytes, transaction: Optional[intdirstate.TransactionT]
672 ) -> None:
659 self.__class__._branch.set(self, encoding.fromlocal(branch))
673 self.__class__._branch.set(self, encoding.fromlocal(branch))
660 if transaction is not None:
674 if transaction is not None:
661 self._setup_tr_abort(transaction)
675 self._setup_tr_abort(transaction)
@@ -683,7 +697,7 class dirstate(intdirstate.idirstate):
683 def _write_branch(self, file_obj):
697 def _write_branch(self, file_obj):
684 file_obj.write(self._branch + b'\n')
698 file_obj.write(self._branch + b'\n')
685
699
686 def invalidate(self):
700 def invalidate(self) -> None:
687 """Causes the next access to reread the dirstate.
701 """Causes the next access to reread the dirstate.
688
702
689 This is different from localrepo.invalidatedirstate() because it always
703 This is different from localrepo.invalidatedirstate() because it always
@@ -703,7 +717,7 class dirstate(intdirstate.idirstate):
703 self._origpl = None
717 self._origpl = None
704
718
705 @requires_changing_any
719 @requires_changing_any
706 def copy(self, source, dest):
720 def copy(self, source: Optional[bytes], dest: bytes) -> None:
707 """Mark dest as a copy of source. Unmark dest if source is None."""
721 """Mark dest as a copy of source. Unmark dest if source is None."""
708 if source == dest:
722 if source == dest:
709 return
723 return
@@ -714,10 +728,10 class dirstate(intdirstate.idirstate):
714 else:
728 else:
715 self._map.copymap.pop(dest, None)
729 self._map.copymap.pop(dest, None)
716
730
717 def copied(self, file):
731 def copied(self, file: bytes) -> Optional[bytes]:
718 return self._map.copymap.get(file, None)
732 return self._map.copymap.get(file, None)
719
733
720 def copies(self):
734 def copies(self) -> Dict[bytes, bytes]:
721 return self._map.copymap
735 return self._map.copymap
722
736
723 @requires_changing_files
737 @requires_changing_files
@@ -983,7 +997,9 class dirstate(intdirstate.idirstate):
983 )
997 )
984 return folded
998 return folded
985
999
986 def normalize(self, path, isknown=False, ignoremissing=False):
1000 def normalize(
1001 self, path: bytes, isknown: bool = False, ignoremissing: bool = False
1002 ) -> bytes:
987 """
1003 """
988 normalize the case of a pathname when on a casefolding filesystem
1004 normalize the case of a pathname when on a casefolding filesystem
989
1005
@@ -1009,12 +1025,17 class dirstate(intdirstate.idirstate):
1009 # - its semantic is unclear
1025 # - its semantic is unclear
1010 # - do we really needs it ?
1026 # - do we really needs it ?
1011 @requires_changing_parents
1027 @requires_changing_parents
1012 def clear(self):
1028 def clear(self) -> None:
1013 self._map.clear()
1029 self._map.clear()
1014 self._dirty = True
1030 self._dirty = True
1015
1031
1016 @requires_changing_parents
1032 @requires_changing_parents
1017 def rebuild(self, parent, allfiles, changedfiles=None):
1033 def rebuild(
1034 self,
1035 parent: bytes,
1036 allfiles: Iterable[bytes], # TODO: more than iterable? (uses len())
1037 changedfiles: Optional[Iterable[bytes]] = None,
1038 ) -> None:
1018 matcher = self._sparsematcher
1039 matcher = self._sparsematcher
1019 if matcher is not None and not matcher.always():
1040 if matcher is not None and not matcher.always():
1020 # should not add non-matching files
1041 # should not add non-matching files
@@ -1080,7 +1101,7 class dirstate(intdirstate.idirstate):
1080 on_abort,
1101 on_abort,
1081 )
1102 )
1082
1103
1083 def write(self, tr):
1104 def write(self, tr: Optional[intdirstate.TransactionT]) -> None:
1084 if not self._dirty:
1105 if not self._dirty:
1085 return
1106 return
1086 # make sure we don't request a write of invalidated content
1107 # make sure we don't request a write of invalidated content
@@ -1130,7 +1151,9 class dirstate(intdirstate.idirstate):
1130 self._opener.unlink(self._filename_th)
1151 self._opener.unlink(self._filename_th)
1131 self._use_tracked_hint = False
1152 self._use_tracked_hint = False
1132
1153
1133 def addparentchangecallback(self, category, callback):
1154 def addparentchangecallback(
1155 self, category: bytes, callback: intdirstate.AddParentChangeCallbackT
1156 ) -> None:
1134 """add a callback to be called when the wd parents are changed
1157 """add a callback to be called when the wd parents are changed
1135
1158
1136 Callback will be called with the following arguments:
1159 Callback will be called with the following arguments:
@@ -1165,7 +1188,7 class dirstate(intdirstate.idirstate):
1165 return True
1188 return True
1166 return False
1189 return False
1167
1190
1168 def _ignorefiles(self):
1191 def _ignorefiles(self) -> List[bytes]:
1169 files = []
1192 files = []
1170 if os.path.exists(self._join(b'.hgignore')):
1193 if os.path.exists(self._join(b'.hgignore')):
1171 files.append(self._join(b'.hgignore'))
1194 files.append(self._join(b'.hgignore'))
@@ -1176,7 +1199,7 class dirstate(intdirstate.idirstate):
1176 files.append(os.path.join(self._rootdir, util.expandpath(path)))
1199 files.append(os.path.join(self._rootdir, util.expandpath(path)))
1177 return files
1200 return files
1178
1201
1179 def _ignorefileandline(self, f):
1202 def _ignorefileandline(self, f: bytes) -> intdirstate.IgnoreFileAndLineT:
1180 files = collections.deque(self._ignorefiles())
1203 files = collections.deque(self._ignorefiles())
1181 visited = set()
1204 visited = set()
1182 while files:
1205 while files:
@@ -1334,7 +1357,14 class dirstate(intdirstate.idirstate):
1334
1357
1335 return results, dirsfound, dirsnotfound
1358 return results, dirsfound, dirsnotfound
1336
1359
1337 def walk(self, match, subrepos, unknown, ignored, full=True):
1360 def walk(
1361 self,
1362 match: matchmod.basematcher,
1363 subrepos: Any,
1364 unknown: bool,
1365 ignored: bool,
1366 full: bool = True,
1367 ) -> intdirstate.WalkReturnT:
1338 """
1368 """
1339 Walk recursively through the directory tree, finding all files
1369 Walk recursively through the directory tree, finding all files
1340 matched by match.
1370 matched by match.
@@ -1607,7 +1637,14 class dirstate(intdirstate.idirstate):
1607 )
1637 )
1608 return (lookup, status)
1638 return (lookup, status)
1609
1639
1610 def status(self, match, subrepos, ignored, clean, unknown):
1640 def status(
1641 self,
1642 match: matchmod.basematcher,
1643 subrepos: bool,
1644 ignored: bool,
1645 clean: bool,
1646 unknown: bool,
1647 ) -> intdirstate.StatusReturnT:
1611 """Determine the status of the working copy relative to the
1648 """Determine the status of the working copy relative to the
1612 dirstate and return a pair of (unsure, status), where status is of type
1649 dirstate and return a pair of (unsure, status), where status is of type
1613 scmutil.status and:
1650 scmutil.status and:
@@ -1745,7 +1782,7 class dirstate(intdirstate.idirstate):
1745 )
1782 )
1746 return (lookup, status, mtime_boundary)
1783 return (lookup, status, mtime_boundary)
1747
1784
1748 def matches(self, match):
1785 def matches(self, match: matchmod.basematcher) -> Iterable[bytes]:
1749 """
1786 """
1750 return files in the dirstate (in whatever state) filtered by match
1787 return files in the dirstate (in whatever state) filtered by match
1751 """
1788 """
@@ -1778,7 +1815,9 class dirstate(intdirstate.idirstate):
1778 files.append(self._map.docket.data_filename())
1815 files.append(self._map.docket.data_filename())
1779 return tuple(files)
1816 return tuple(files)
1780
1817
1781 def verify(self, m1, m2, p1, narrow_matcher=None):
1818 def verify(
1819 self, m1, m2, p1: bytes, narrow_matcher: Optional[Any] = None
1820 ) -> Iterator[bytes]:
1782 """
1821 """
1783 check the dirstate contents against the parent manifest and yield errors
1822 check the dirstate contents against the parent manifest and yield errors
1784 """
1823 """
@@ -1,11 +1,19
1 from __future__ import annotations
1 from __future__ import annotations
2
2
3 import contextlib
3 import contextlib
4 import os
4 import typing
5 import typing
5
6
6 from typing import (
7 from typing import (
8 Any,
7 Callable,
9 Callable,
10 Dict,
11 Iterable,
12 Iterator,
13 List,
14 Optional,
8 Protocol,
15 Protocol,
16 Tuple,
9 )
17 )
10
18
11 if typing.TYPE_CHECKING:
19 if typing.TYPE_CHECKING:
@@ -13,8 +21,52 if typing.TYPE_CHECKING:
13 # to avoid circular imports
21 # to avoid circular imports
14 from .. import (
22 from .. import (
15 match as matchmod,
23 match as matchmod,
24 scmutil,
25 transaction as txnmod,
16 )
26 )
17
27
28 # TODO: finish adding type hints
29 AddParentChangeCallbackT = Callable[
30 ["idirstate", Tuple[Any, Any], Tuple[Any, Any]], Any
31 ]
32 """The callback type for dirstate.addparentchangecallback()."""
33
34 # TODO: add a Protocol for dirstatemap.DirStateItem? (It is
35 # conditionalized with python or rust implementations. Also,
36 # git.dirstate needs to yield non-None from ``items()``.)
37 DirstateItemT = Any # dirstatemap.DirstateItem
38
39 IgnoreFileAndLineT = Tuple[Optional[bytes], int, bytes]
40 """The return type of dirstate._ignorefileandline(), which holds
41 ``(file, lineno, originalline)``.
42 """
43
44 FlagFuncFallbackT = Callable[[], "FlagFuncReturnT"]
45 """The type for the dirstate.flagfunc() fallback function."""
46
47 FlagFuncReturnT = Callable[[bytes], bytes]
48 """The return type of dirstate.flagfunc()."""
49
50 # TODO: verify and complete this- it came from a pytype *.pyi file
51 StatusReturnT = Tuple[Any, scmutil.status, Any]
52 """The return type of dirstate.status()."""
53
54 # TODO: probably doesn't belong here.
55 TransactionT = txnmod.transaction
56 """The type for a transaction used with dirstate.
57
58 This is meant to help callers avoid having to remember to delay the import
59 of the transaction module.
60 """
61
62 # TODO: The value can also be mercurial.osutil.stat
63 WalkReturnT = Dict[bytes, Optional[os.stat_result]]
64 """The return type of dirstate.walk().
65
66 The matched files are keyed in the dictionary, mapped to a stat-like object
67 if the file exists.
68 """
69
18
70
19 class idirstate(Protocol):
71 class idirstate(Protocol):
20 # TODO: convert these constructor args to fields?
72 # TODO: convert these constructor args to fields?
@@ -56,10 +108,10 class idirstate(Protocol):
56 def is_changing_files(self) -> bool:
108 def is_changing_files(self) -> bool:
57 """True if file tracking changes in progress."""
109 """True if file tracking changes in progress."""
58
110
59 def _ignorefiles(self):
111 def _ignorefiles(self) -> List[bytes]:
60 """Return a list of files containing patterns to ignore."""
112 """Return a list of files containing patterns to ignore."""
61
113
62 def _ignorefileandline(self, f):
114 def _ignorefileandline(self, f: bytes) -> IgnoreFileAndLineT:
63 """Given a file `f`, return the ignore file and line that ignores it."""
115 """Given a file `f`, return the ignore file and line that ignores it."""
64
116
65 # TODO: decorate with `@util.propertycache` like dirstate class?
117 # TODO: decorate with `@util.propertycache` like dirstate class?
@@ -75,7 +127,7 class idirstate(Protocol):
75 """Callable for checking exec bits.""" # TODO: this comment looks stale
127 """Callable for checking exec bits.""" # TODO: this comment looks stale
76
128
77 @contextlib.contextmanager
129 @contextlib.contextmanager
78 def changing_parents(self, repo):
130 def changing_parents(self, repo) -> Iterator: # TODO: typehint this
79 """Context manager for handling dirstate parents.
131 """Context manager for handling dirstate parents.
80
132
81 If an exception occurs in the scope of the context manager,
133 If an exception occurs in the scope of the context manager,
@@ -84,7 +136,7 class idirstate(Protocol):
84 """
136 """
85
137
86 @contextlib.contextmanager
138 @contextlib.contextmanager
87 def changing_files(self, repo):
139 def changing_files(self, repo) -> Iterator: # TODO: typehint this
88 """Context manager for handling dirstate files.
140 """Context manager for handling dirstate files.
89
141
90 If an exception occurs in the scope of the context manager,
142 If an exception occurs in the scope of the context manager,
@@ -92,10 +144,10 class idirstate(Protocol):
92 released.
144 released.
93 """
145 """
94
146
95 def hasdir(self, d):
147 def hasdir(self, d: bytes) -> bool:
96 pass
148 pass
97
149
98 def flagfunc(self, buildfallback):
150 def flagfunc(self, buildfallback: FlagFuncFallbackT) -> FlagFuncReturnT:
99 """build a callable that returns flags associated with a filename
151 """build a callable that returns flags associated with a filename
100
152
101 The information is extracted from three possible layers:
153 The information is extracted from three possible layers:
@@ -104,7 +156,7 class idirstate(Protocol):
104 3. a more expensive mechanism inferring the flags from the parents.
156 3. a more expensive mechanism inferring the flags from the parents.
105 """
157 """
106
158
107 def getcwd(self):
159 def getcwd(self) -> bytes:
108 """Return the path from which a canonical path is calculated.
160 """Return the path from which a canonical path is calculated.
109
161
110 This path should be used to resolve file patterns or to convert
162 This path should be used to resolve file patterns or to convert
@@ -112,19 +164,19 class idirstate(Protocol):
112 used to get real file paths. Use vfs functions instead.
164 used to get real file paths. Use vfs functions instead.
113 """
165 """
114
166
115 def pathto(self, f, cwd=None):
167 def pathto(self, f: bytes, cwd: Optional[bytes] = None) -> bytes:
116 pass
168 pass
117
169
118 def get_entry(self, path):
170 def get_entry(self, path: bytes) -> DirstateItemT:
119 """return a DirstateItem for the associated path"""
171 """return a DirstateItem for the associated path"""
120
172
121 def __contains__(self, key):
173 def __contains__(self, key: Any) -> bool:
122 """Check if bytestring `key` is known to the dirstate."""
174 """Check if bytestring `key` is known to the dirstate."""
123
175
124 def __iter__(self):
176 def __iter__(self) -> Iterator[bytes]:
125 """Iterate the dirstate's contained filenames as bytestrings."""
177 """Iterate the dirstate's contained filenames as bytestrings."""
126
178
127 def items(self):
179 def items(self) -> Iterator[Tuple[bytes, DirstateItemT]]:
128 """Iterate the dirstate's entries as (filename, DirstateItem.
180 """Iterate the dirstate's entries as (filename, DirstateItem.
129
181
130 As usual, filename is a bytestring.
182 As usual, filename is a bytestring.
@@ -132,19 +184,20 class idirstate(Protocol):
132
184
133 iteritems = items
185 iteritems = items
134
186
135 def parents(self):
187 def parents(self) -> List[bytes]:
136 pass
188 pass
137
189
138 def p1(self):
190 def p1(self) -> bytes:
139 pass
191 pass
140
192
141 def p2(self):
193 def p2(self) -> bytes:
142 pass
194 pass
143
195
144 def branch(self):
196 def branch(self) -> bytes:
145 pass
197 pass
146
198
147 def setparents(self, p1, p2=None):
199 # TODO: typehint the return. It's a copies Map of some sort.
200 def setparents(self, p1: bytes, p2: Optional[bytes] = None):
148 """Set dirstate parents to p1 and p2.
201 """Set dirstate parents to p1 and p2.
149
202
150 When moving from two parents to one, "merged" entries a
203 When moving from two parents to one, "merged" entries a
@@ -154,26 +207,30 class idirstate(Protocol):
154 See localrepo.setparents()
207 See localrepo.setparents()
155 """
208 """
156
209
157 def setbranch(self, branch, transaction):
210 def setbranch(
211 self, branch: bytes, transaction: Optional[TransactionT]
212 ) -> None:
158 pass
213 pass
159
214
160 def invalidate(self):
215 def invalidate(self) -> None:
161 """Causes the next access to reread the dirstate.
216 """Causes the next access to reread the dirstate.
162
217
163 This is different from localrepo.invalidatedirstate() because it always
218 This is different from localrepo.invalidatedirstate() because it always
164 rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
219 rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
165 check whether the dirstate has changed before rereading it."""
220 check whether the dirstate has changed before rereading it."""
166
221
167 def copy(self, source, dest):
222 def copy(self, source: Optional[bytes], dest: bytes) -> None:
168 """Mark dest as a copy of source. Unmark dest if source is None."""
223 """Mark dest as a copy of source. Unmark dest if source is None."""
169
224
170 def copied(self, file):
225 def copied(self, file: bytes) -> Optional[bytes]:
171 pass
226 pass
172
227
173 def copies(self):
228 def copies(self) -> Dict[bytes, bytes]:
174 pass
229 pass
175
230
176 def normalize(self, path, isknown=False, ignoremissing=False):
231 def normalize(
232 self, path: bytes, isknown: bool = False, ignoremissing: bool = False
233 ) -> bytes:
177 """
234 """
178 normalize the case of a pathname when on a casefolding filesystem
235 normalize the case of a pathname when on a casefolding filesystem
179
236
@@ -191,16 +248,23 class idirstate(Protocol):
191 - version provided via command arguments
248 - version provided via command arguments
192 """
249 """
193
250
194 def clear(self):
251 def clear(self) -> None:
195 pass
252 pass
196
253
197 def rebuild(self, parent, allfiles, changedfiles=None):
254 def rebuild(
255 self,
256 parent: bytes,
257 allfiles: Iterable[bytes], # TODO: more than iterable? (uses len())
258 changedfiles: Optional[Iterable[bytes]] = None,
259 ) -> None:
198 pass
260 pass
199
261
200 def write(self, tr):
262 def write(self, tr: Optional[TransactionT]) -> None:
201 pass
263 pass
202
264
203 def addparentchangecallback(self, category, callback):
265 def addparentchangecallback(
266 self, category: bytes, callback: AddParentChangeCallbackT
267 ) -> None:
204 """add a callback to be called when the wd parents are changed
268 """add a callback to be called when the wd parents are changed
205
269
206 Callback will be called with the following arguments:
270 Callback will be called with the following arguments:
@@ -210,7 +274,14 class idirstate(Protocol):
210 with a newer callback.
274 with a newer callback.
211 """
275 """
212
276
213 def walk(self, match, subrepos, unknown, ignored, full=True):
277 def walk(
278 self,
279 match: matchmod.basematcher,
280 subrepos: Any, # TODO: figure out what this is
281 unknown: bool,
282 ignored: bool,
283 full: bool = True,
284 ) -> WalkReturnT:
214 """
285 """
215 Walk recursively through the directory tree, finding all files
286 Walk recursively through the directory tree, finding all files
216 matched by match.
287 matched by match.
@@ -222,7 +293,14 class idirstate(Protocol):
222
293
223 """
294 """
224
295
225 def status(self, match, subrepos, ignored, clean, unknown):
296 def status(
297 self,
298 match: matchmod.basematcher,
299 subrepos: bool,
300 ignored: bool,
301 clean: bool,
302 unknown: bool,
303 ) -> StatusReturnT:
226 """Determine the status of the working copy relative to the
304 """Determine the status of the working copy relative to the
227 dirstate and return a pair of (unsure, status), where status is of type
305 dirstate and return a pair of (unsure, status), where status is of type
228 scmutil.status and:
306 scmutil.status and:
@@ -239,12 +317,18 class idirstate(Protocol):
239 dirstate was written
317 dirstate was written
240 """
318 """
241
319
242 def matches(self, match):
320 # TODO: could return a list, except git.dirstate is a generator
321
322 def matches(self, match: matchmod.basematcher) -> Iterable[bytes]:
243 """
323 """
244 return files in the dirstate (in whatever state) filtered by match
324 return files in the dirstate (in whatever state) filtered by match
245 """
325 """
246
326
247 def verify(self, m1, m2, p1, narrow_matcher=None):
327 # TODO: finish adding typehints here, and to subclasses
328
329 def verify(
330 self, m1, m2, p1: bytes, narrow_matcher: Optional[Any] = None
331 ) -> Iterator[bytes]:
248 """
332 """
249 check the dirstate contents against the parent manifest and yield errors
333 check the dirstate contents against the parent manifest and yield errors
250 """
334 """
General Comments 0
You need to be logged in to leave comments. Login now