Mercurial > hg
comparison mercurial/dirstate.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 | d459cd8ea42d |
children | 687b865b95ad |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
35 parsers = policy.importmod(r'parsers') | 35 parsers = policy.importmod(r'parsers') |
36 rustmod = policy.importrust(r'dirstate') | 36 rustmod = policy.importrust(r'dirstate') |
37 | 37 |
38 propertycache = util.propertycache | 38 propertycache = util.propertycache |
39 filecache = scmutil.filecache | 39 filecache = scmutil.filecache |
40 _rangemask = 0x7fffffff | 40 _rangemask = 0x7FFFFFFF |
41 | 41 |
42 dirstatetuple = parsers.dirstatetuple | 42 dirstatetuple = parsers.dirstatetuple |
43 | |
43 | 44 |
44 class repocache(filecache): | 45 class repocache(filecache): |
45 """filecache for files in .hg/""" | 46 """filecache for files in .hg/""" |
47 | |
46 def join(self, obj, fname): | 48 def join(self, obj, fname): |
47 return obj._opener.join(fname) | 49 return obj._opener.join(fname) |
48 | 50 |
51 | |
49 class rootcache(filecache): | 52 class rootcache(filecache): |
50 """filecache for files in the repository root""" | 53 """filecache for files in the repository root""" |
54 | |
51 def join(self, obj, fname): | 55 def join(self, obj, fname): |
52 return obj._join(fname) | 56 return obj._join(fname) |
57 | |
53 | 58 |
54 def _getfsnow(vfs): | 59 def _getfsnow(vfs): |
55 '''Get "now" timestamp on filesystem''' | 60 '''Get "now" timestamp on filesystem''' |
56 tmpfd, tmpname = vfs.mkstemp() | 61 tmpfd, tmpname = vfs.mkstemp() |
57 try: | 62 try: |
58 return os.fstat(tmpfd)[stat.ST_MTIME] | 63 return os.fstat(tmpfd)[stat.ST_MTIME] |
59 finally: | 64 finally: |
60 os.close(tmpfd) | 65 os.close(tmpfd) |
61 vfs.unlink(tmpname) | 66 vfs.unlink(tmpname) |
62 | 67 |
68 | |
63 @interfaceutil.implementer(intdirstate.idirstate) | 69 @interfaceutil.implementer(intdirstate.idirstate) |
64 class dirstate(object): | 70 class dirstate(object): |
65 | |
66 def __init__(self, opener, ui, root, validate, sparsematchfn): | 71 def __init__(self, opener, ui, root, validate, sparsematchfn): |
67 '''Create a new dirstate object. | 72 '''Create a new dirstate object. |
68 | 73 |
69 opener is an open()-like callable that can be used to open the | 74 opener is an open()-like callable that can be used to open the |
70 dirstate file; root is the root of the directory tracked by | 75 dirstate file; root is the root of the directory tracked by |
181 # it's safe because f is always a relative path | 186 # it's safe because f is always a relative path |
182 return self._rootdir + f | 187 return self._rootdir + f |
183 | 188 |
184 def flagfunc(self, buildfallback): | 189 def flagfunc(self, buildfallback): |
185 if self._checklink and self._checkexec: | 190 if self._checklink and self._checkexec: |
191 | |
186 def f(x): | 192 def f(x): |
187 try: | 193 try: |
188 st = os.lstat(self._join(x)) | 194 st = os.lstat(self._join(x)) |
189 if util.statislink(st): | 195 if util.statislink(st): |
190 return 'l' | 196 return 'l' |
191 if util.statisexec(st): | 197 if util.statisexec(st): |
192 return 'x' | 198 return 'x' |
193 except OSError: | 199 except OSError: |
194 pass | 200 pass |
195 return '' | 201 return '' |
202 | |
196 return f | 203 return f |
197 | 204 |
198 fallback = buildfallback() | 205 fallback = buildfallback() |
199 if self._checklink: | 206 if self._checklink: |
207 | |
200 def f(x): | 208 def f(x): |
201 if os.path.islink(self._join(x)): | 209 if os.path.islink(self._join(x)): |
202 return 'l' | 210 return 'l' |
203 if 'x' in fallback(x): | 211 if 'x' in fallback(x): |
204 return 'x' | 212 return 'x' |
205 return '' | 213 return '' |
214 | |
206 return f | 215 return f |
207 if self._checkexec: | 216 if self._checkexec: |
217 | |
208 def f(x): | 218 def f(x): |
209 if 'l' in fallback(x): | 219 if 'l' in fallback(x): |
210 return 'l' | 220 return 'l' |
211 if util.isexec(self._join(x)): | 221 if util.isexec(self._join(x)): |
212 return 'x' | 222 return 'x' |
213 return '' | 223 return '' |
224 | |
214 return f | 225 return f |
215 else: | 226 else: |
216 return fallback | 227 return fallback |
217 | 228 |
218 @propertycache | 229 @propertycache |
236 # self._root ends with a path separator if self._root is '/' or 'C:\' | 247 # self._root ends with a path separator if self._root is '/' or 'C:\' |
237 rootsep = self._root | 248 rootsep = self._root |
238 if not util.endswithsep(rootsep): | 249 if not util.endswithsep(rootsep): |
239 rootsep += pycompat.ossep | 250 rootsep += pycompat.ossep |
240 if cwd.startswith(rootsep): | 251 if cwd.startswith(rootsep): |
241 return cwd[len(rootsep):] | 252 return cwd[len(rootsep) :] |
242 else: | 253 else: |
243 # we're outside the repo. return an absolute path. | 254 # we're outside the repo. return an absolute path. |
244 return cwd | 255 return cwd |
245 | 256 |
246 def pathto(self, f, cwd=None): | 257 def pathto(self, f, cwd=None): |
294 returned by the call. | 305 returned by the call. |
295 | 306 |
296 See localrepo.setparents() | 307 See localrepo.setparents() |
297 """ | 308 """ |
298 if self._parentwriters == 0: | 309 if self._parentwriters == 0: |
299 raise ValueError("cannot set dirstate parent outside of " | 310 raise ValueError( |
300 "dirstate.parentchange context manager") | 311 "cannot set dirstate parent outside of " |
312 "dirstate.parentchange context manager" | |
313 ) | |
301 | 314 |
302 self._dirty = True | 315 self._dirty = True |
303 oldp2 = self._pl[1] | 316 oldp2 = self._pl[1] |
304 if self._origpl is None: | 317 if self._origpl is None: |
305 self._origpl = self._pl | 318 self._origpl = self._pl |
306 self._map.setparents(p1, p2) | 319 self._map.setparents(p1, p2) |
307 copies = {} | 320 copies = {} |
308 if oldp2 != nullid and p2 == nullid: | 321 if oldp2 != nullid and p2 == nullid: |
309 candidatefiles = self._map.nonnormalset.union( | 322 candidatefiles = self._map.nonnormalset.union( |
310 self._map.otherparentset) | 323 self._map.otherparentset |
324 ) | |
311 for f in candidatefiles: | 325 for f in candidatefiles: |
312 s = self._map.get(f) | 326 s = self._map.get(f) |
313 if s is None: | 327 if s is None: |
314 continue | 328 continue |
315 | 329 |
337 # make sure filecache has the correct stat info for _branch after | 351 # make sure filecache has the correct stat info for _branch after |
338 # replacing the underlying file | 352 # replacing the underlying file |
339 ce = self._filecache['_branch'] | 353 ce = self._filecache['_branch'] |
340 if ce: | 354 if ce: |
341 ce.refresh() | 355 ce.refresh() |
342 except: # re-raises | 356 except: # re-raises |
343 f.discard() | 357 f.discard() |
344 raise | 358 raise |
345 | 359 |
346 def invalidate(self): | 360 def invalidate(self): |
347 '''Causes the next access to reread the dirstate. | 361 '''Causes the next access to reread the dirstate. |
380 def _addpath(self, f, state, mode, size, mtime): | 394 def _addpath(self, f, state, mode, size, mtime): |
381 oldstate = self[f] | 395 oldstate = self[f] |
382 if state == 'a' or oldstate == 'r': | 396 if state == 'a' or oldstate == 'r': |
383 scmutil.checkfilename(f) | 397 scmutil.checkfilename(f) |
384 if self._map.hastrackeddir(f): | 398 if self._map.hastrackeddir(f): |
385 raise error.Abort(_('directory %r already in dirstate') % | 399 raise error.Abort( |
386 pycompat.bytestr(f)) | 400 _('directory %r already in dirstate') % pycompat.bytestr(f) |
401 ) | |
387 # shadows | 402 # shadows |
388 for d in util.finddirs(f): | 403 for d in util.finddirs(f): |
389 if self._map.hastrackeddir(d): | 404 if self._map.hastrackeddir(d): |
390 break | 405 break |
391 entry = self._map.get(d) | 406 entry = self._map.get(d) |
392 if entry is not None and entry[0] != 'r': | 407 if entry is not None and entry[0] != 'r': |
393 raise error.Abort( | 408 raise error.Abort( |
394 _('file %r in dirstate clashes with %r') % | 409 _('file %r in dirstate clashes with %r') |
395 (pycompat.bytestr(d), pycompat.bytestr(f))) | 410 % (pycompat.bytestr(d), pycompat.bytestr(f)) |
411 ) | |
396 self._dirty = True | 412 self._dirty = True |
397 self._updatedfiles.add(f) | 413 self._updatedfiles.add(f) |
398 self._map.addfile(f, oldstate, state, mode, size, mtime) | 414 self._map.addfile(f, oldstate, state, mode, size, mtime) |
399 | 415 |
400 def normal(self, f, parentfiledata=None): | 416 def normal(self, f, parentfiledata=None): |
447 self._map.copymap.pop(f, None) | 463 self._map.copymap.pop(f, None) |
448 | 464 |
449 def otherparent(self, f): | 465 def otherparent(self, f): |
450 '''Mark as coming from the other parent, always dirty.''' | 466 '''Mark as coming from the other parent, always dirty.''' |
451 if self._pl[1] == nullid: | 467 if self._pl[1] == nullid: |
452 raise error.Abort(_("setting %r to other parent " | 468 raise error.Abort( |
453 "only allowed in merges") % f) | 469 _("setting %r to other parent " "only allowed in merges") % f |
470 ) | |
454 if f in self and self[f] == 'n': | 471 if f in self and self[f] == 'n': |
455 # merge-like | 472 # merge-like |
456 self._addpath(f, 'm', 0, -2, -1) | 473 self._addpath(f, 'm', 0, -2, -1) |
457 else: | 474 else: |
458 # add-like | 475 # add-like |
471 size = 0 | 488 size = 0 |
472 if self._pl[1] != nullid: | 489 if self._pl[1] != nullid: |
473 entry = self._map.get(f) | 490 entry = self._map.get(f) |
474 if entry is not None: | 491 if entry is not None: |
475 # backup the previous state | 492 # backup the previous state |
476 if entry[0] == 'm': # merge | 493 if entry[0] == 'm': # merge |
477 size = -1 | 494 size = -1 |
478 elif entry[0] == 'n' and entry[2] == -2: # other parent | 495 elif entry[0] == 'n' and entry[2] == -2: # other parent |
479 size = -2 | 496 size = -2 |
480 self._map.otherparentset.add(f) | 497 self._map.otherparentset.add(f) |
481 self._updatedfiles.add(f) | 498 self._updatedfiles.add(f) |
482 self._map.removefile(f, oldstate, size) | 499 self._map.removefile(f, oldstate, size) |
483 if size == 0: | 500 if size == 0: |
528 folded = self._map.filefoldmap.get(normed, None) | 545 folded = self._map.filefoldmap.get(normed, None) |
529 if folded is None: | 546 if folded is None: |
530 if isknown: | 547 if isknown: |
531 folded = path | 548 folded = path |
532 else: | 549 else: |
533 folded = self._discoverpath(path, normed, ignoremissing, exists, | 550 folded = self._discoverpath( |
534 self._map.filefoldmap) | 551 path, normed, ignoremissing, exists, self._map.filefoldmap |
552 ) | |
535 return folded | 553 return folded |
536 | 554 |
537 def _normalize(self, path, isknown, ignoremissing=False, exists=None): | 555 def _normalize(self, path, isknown, ignoremissing=False, exists=None): |
538 normed = util.normcase(path) | 556 normed = util.normcase(path) |
539 folded = self._map.filefoldmap.get(normed, None) | 557 folded = self._map.filefoldmap.get(normed, None) |
543 if isknown: | 561 if isknown: |
544 folded = path | 562 folded = path |
545 else: | 563 else: |
546 # store discovered result in dirfoldmap so that future | 564 # store discovered result in dirfoldmap so that future |
547 # normalizefile calls don't start matching directories | 565 # normalizefile calls don't start matching directories |
548 folded = self._discoverpath(path, normed, ignoremissing, exists, | 566 folded = self._discoverpath( |
549 self._map.dirfoldmap) | 567 path, normed, ignoremissing, exists, self._map.dirfoldmap |
568 ) | |
550 return folded | 569 return folded |
551 | 570 |
552 def normalize(self, path, isknown=False, ignoremissing=False): | 571 def normalize(self, path, isknown=False, ignoremissing=False): |
553 ''' | 572 ''' |
554 normalize the case of a pathname when on a casefolding filesystem | 573 normalize the case of a pathname when on a casefolding filesystem |
623 # emulate that all 'dirstate.normal' results are written out | 642 # emulate that all 'dirstate.normal' results are written out |
624 self._lastnormaltime = 0 | 643 self._lastnormaltime = 0 |
625 self._updatedfiles.clear() | 644 self._updatedfiles.clear() |
626 | 645 |
627 # delay writing in-memory changes out | 646 # delay writing in-memory changes out |
628 tr.addfilegenerator('dirstate', (self._filename,), | 647 tr.addfilegenerator( |
629 self._writedirstate, location='plain') | 648 'dirstate', |
649 (self._filename,), | |
650 self._writedirstate, | |
651 location='plain', | |
652 ) | |
630 return | 653 return |
631 | 654 |
632 st = self._opener(filename, "w", atomictemp=True, checkambig=True) | 655 st = self._opener(filename, "w", atomictemp=True, checkambig=True) |
633 self._writedirstate(st) | 656 self._writedirstate(st) |
634 | 657 |
659 if delaywrite > 0: | 682 if delaywrite > 0: |
660 # do we have any files to delay for? | 683 # do we have any files to delay for? |
661 items = self._map.iteritems() | 684 items = self._map.iteritems() |
662 for f, e in items: | 685 for f, e in items: |
663 if e[0] == 'n' and e[3] == now: | 686 if e[0] == 'n' and e[3] == now: |
664 import time # to avoid useless import | 687 import time # to avoid useless import |
688 | |
665 # rather than sleep n seconds, sleep until the next | 689 # rather than sleep n seconds, sleep until the next |
666 # multiple of n seconds | 690 # multiple of n seconds |
667 clock = time.time() | 691 clock = time.time() |
668 start = int(clock) - (int(clock) % delaywrite) | 692 start = int(clock) - (int(clock) % delaywrite) |
669 end = start + delaywrite | 693 end = start + delaywrite |
670 time.sleep(end - clock) | 694 time.sleep(end - clock) |
671 now = end # trust our estimate that the end is near now | 695 now = end # trust our estimate that the end is near now |
672 break | 696 break |
673 # since the iterator is potentially not deleted, | 697 # since the iterator is potentially not deleted, |
674 # delete the iterator to release the reference for the Rust | 698 # delete the iterator to release the reference for the Rust |
675 # implementation. | 699 # implementation. |
676 # TODO make the Rust implementation behave like Python | 700 # TODO make the Rust implementation behave like Python |
703 def _ignorefileandline(self, f): | 727 def _ignorefileandline(self, f): |
704 files = collections.deque(self._ignorefiles()) | 728 files = collections.deque(self._ignorefiles()) |
705 visited = set() | 729 visited = set() |
706 while files: | 730 while files: |
707 i = files.popleft() | 731 i = files.popleft() |
708 patterns = matchmod.readpatternfile(i, self._ui.warn, | 732 patterns = matchmod.readpatternfile( |
709 sourceinfo=True) | 733 i, self._ui.warn, sourceinfo=True |
734 ) | |
710 for pattern, lineno, line in patterns: | 735 for pattern, lineno, line in patterns: |
711 kind, p = matchmod._patsplit(pattern, 'glob') | 736 kind, p = matchmod._patsplit(pattern, 'glob') |
712 if kind == "subinclude": | 737 if kind == "subinclude": |
713 if p not in visited: | 738 if p not in visited: |
714 files.append(p) | 739 files.append(p) |
715 continue | 740 continue |
716 m = matchmod.match(self._root, '', [], [pattern], | 741 m = matchmod.match( |
717 warn=self._ui.warn) | 742 self._root, '', [], [pattern], warn=self._ui.warn |
743 ) | |
718 if m(f): | 744 if m(f): |
719 return (i, lineno, line) | 745 return (i, lineno, line) |
720 visited.add(i) | 746 visited.add(i) |
721 return (None, -1, "") | 747 return (None, -1, "") |
722 | 748 |
805 results[nf] = st | 831 results[nf] = st |
806 else: | 832 else: |
807 badfn(ff, badtype(kind)) | 833 badfn(ff, badtype(kind)) |
808 if nf in dmap: | 834 if nf in dmap: |
809 results[nf] = None | 835 results[nf] = None |
810 except OSError as inst: # nf not found on disk - it is dirstate only | 836 except OSError as inst: # nf not found on disk - it is dirstate only |
811 if nf in dmap: # does it exactly match a missing file? | 837 if nf in dmap: # does it exactly match a missing file? |
812 results[nf] = None | 838 results[nf] = None |
813 else: # does it match a missing directory? | 839 else: # does it match a missing directory? |
814 if self._map.hasdir(nf): | 840 if self._map.hasdir(nf): |
815 if matchedir: | 841 if matchedir: |
816 matchedir(nf) | 842 matchedir(nf) |
817 notfoundadd(nf) | 843 notfoundadd(nf) |
818 else: | 844 else: |
850 paths.add(f) | 876 paths.add(f) |
851 | 877 |
852 for norm, paths in normed.iteritems(): | 878 for norm, paths in normed.iteritems(): |
853 if len(paths) > 1: | 879 if len(paths) > 1: |
854 for path in paths: | 880 for path in paths: |
855 folded = self._discoverpath(path, norm, True, None, | 881 folded = self._discoverpath( |
856 self._map.dirfoldmap) | 882 path, norm, True, None, self._map.dirfoldmap |
883 ) | |
857 if path != folded: | 884 if path != folded: |
858 results[path] = None | 885 results[path] = None |
859 | 886 |
860 return results, dirsfound, dirsnotfound | 887 return results, dirsfound, dirsnotfound |
861 | 888 |
895 regkind = stat.S_IFREG | 922 regkind = stat.S_IFREG |
896 lnkkind = stat.S_IFLNK | 923 lnkkind = stat.S_IFLNK |
897 join = self._join | 924 join = self._join |
898 | 925 |
899 exact = skipstep3 = False | 926 exact = skipstep3 = False |
900 if match.isexact(): # match.exact | 927 if match.isexact(): # match.exact |
901 exact = True | 928 exact = True |
902 dirignore = util.always # skip step 2 | 929 dirignore = util.always # skip step 2 |
903 elif match.prefix(): # match.match, no patterns | 930 elif match.prefix(): # match.match, no patterns |
904 skipstep3 = True | 931 skipstep3 = True |
905 | 932 |
906 if not exact and self._checkcase: | 933 if not exact and self._checkcase: |
907 normalize = self._normalize | 934 normalize = self._normalize |
908 normalizefile = self._normalizefile | 935 normalizefile = self._normalizefile |
932 skip = '.hg' | 959 skip = '.hg' |
933 try: | 960 try: |
934 entries = listdir(join(nd), stat=True, skip=skip) | 961 entries = listdir(join(nd), stat=True, skip=skip) |
935 except OSError as inst: | 962 except OSError as inst: |
936 if inst.errno in (errno.EACCES, errno.ENOENT): | 963 if inst.errno in (errno.EACCES, errno.ENOENT): |
937 match.bad(self.pathto(nd), | 964 match.bad( |
938 encoding.strtolocal(inst.strerror)) | 965 self.pathto(nd), encoding.strtolocal(inst.strerror) |
966 ) | |
939 continue | 967 continue |
940 raise | 968 raise |
941 for f, kind, st in entries: | 969 for f, kind, st in entries: |
942 # Some matchers may return files in the visitentries set, | 970 # Some matchers may return files in the visitentries set, |
943 # instead of 'this', if the matcher explicitly mentions them | 971 # instead of 'this', if the matcher explicitly mentions them |
951 continue | 979 continue |
952 if normalizefile: | 980 if normalizefile: |
953 # even though f might be a directory, we're only | 981 # even though f might be a directory, we're only |
954 # interested in comparing it to files currently in the | 982 # interested in comparing it to files currently in the |
955 # dmap -- therefore normalizefile is enough | 983 # dmap -- therefore normalizefile is enough |
956 nf = normalizefile(nd and (nd + "/" + f) or f, True, | 984 nf = normalizefile( |
957 True) | 985 nd and (nd + "/" + f) or f, True, True |
986 ) | |
958 else: | 987 else: |
959 nf = nd and (nd + "/" + f) or f | 988 nf = nd and (nd + "/" + f) or f |
960 if nf not in results: | 989 if nf not in results: |
961 if kind == dirkind: | 990 if kind == dirkind: |
962 if not ignore(nf): | 991 if not ignore(nf): |
967 results[nf] = None | 996 results[nf] = None |
968 elif kind == regkind or kind == lnkkind: | 997 elif kind == regkind or kind == lnkkind: |
969 if nf in dmap: | 998 if nf in dmap: |
970 if matchalways or matchfn(nf): | 999 if matchalways or matchfn(nf): |
971 results[nf] = st | 1000 results[nf] = st |
972 elif ((matchalways or matchfn(nf)) | 1001 elif (matchalways or matchfn(nf)) and not ignore( |
973 and not ignore(nf)): | 1002 nf |
1003 ): | |
974 # unknown file -- normalize if necessary | 1004 # unknown file -- normalize if necessary |
975 if not alreadynormed: | 1005 if not alreadynormed: |
976 nf = normalize(nf, False, True) | 1006 nf = normalize(nf, False, True) |
977 results[nf] = st | 1007 results[nf] = st |
978 elif nf in dmap and (matchalways or matchfn(nf)): | 1008 elif nf in dmap and (matchalways or matchfn(nf)): |
1009 for nf in iter(visit): | 1039 for nf in iter(visit): |
1010 # If a stat for the same file was already added with a | 1040 # If a stat for the same file was already added with a |
1011 # different case, don't add one for this, since that would | 1041 # different case, don't add one for this, since that would |
1012 # make it appear as if the file exists under both names | 1042 # make it appear as if the file exists under both names |
1013 # on disk. | 1043 # on disk. |
1014 if (normalizefile and | 1044 if ( |
1015 normalizefile(nf, True, True) in results): | 1045 normalizefile |
1046 and normalizefile(nf, True, True) in results | |
1047 ): | |
1016 results[nf] = None | 1048 results[nf] = None |
1017 # Report ignored items in the dmap as long as they are not | 1049 # Report ignored items in the dmap as long as they are not |
1018 # under a symlink directory. | 1050 # under a symlink directory. |
1019 elif audit_path.check(nf): | 1051 elif audit_path.check(nf): |
1020 try: | 1052 try: |
1057 | 1089 |
1058 dmap = self._map | 1090 dmap = self._map |
1059 dmap.preload() | 1091 dmap.preload() |
1060 dcontains = dmap.__contains__ | 1092 dcontains = dmap.__contains__ |
1061 dget = dmap.__getitem__ | 1093 dget = dmap.__getitem__ |
1062 ladd = lookup.append # aka "unsure" | 1094 ladd = lookup.append # aka "unsure" |
1063 madd = modified.append | 1095 madd = modified.append |
1064 aadd = added.append | 1096 aadd = added.append |
1065 uadd = unknown.append | 1097 uadd = unknown.append |
1066 iadd = ignored.append | 1098 iadd = ignored.append |
1067 radd = removed.append | 1099 radd = removed.append |
1076 # We need to do full walks when either | 1108 # We need to do full walks when either |
1077 # - we're listing all clean files, or | 1109 # - we're listing all clean files, or |
1078 # - match.traversedir does something, because match.traversedir should | 1110 # - match.traversedir does something, because match.traversedir should |
1079 # be called for every dir in the working dir | 1111 # be called for every dir in the working dir |
1080 full = listclean or match.traversedir is not None | 1112 full = listclean or match.traversedir is not None |
1081 for fn, st in self.walk(match, subrepos, listunknown, listignored, | 1113 for fn, st in self.walk( |
1082 full=full).iteritems(): | 1114 match, subrepos, listunknown, listignored, full=full |
1115 ).iteritems(): | |
1083 if not dcontains(fn): | 1116 if not dcontains(fn): |
1084 if (listignored or mexact(fn)) and dirignore(fn): | 1117 if (listignored or mexact(fn)) and dirignore(fn): |
1085 if listignored: | 1118 if listignored: |
1086 iadd(fn) | 1119 iadd(fn) |
1087 else: | 1120 else: |
1102 time = t[3] | 1135 time = t[3] |
1103 | 1136 |
1104 if not st and state in "nma": | 1137 if not st and state in "nma": |
1105 dadd(fn) | 1138 dadd(fn) |
1106 elif state == 'n': | 1139 elif state == 'n': |
1107 if (size >= 0 and | 1140 if ( |
1108 ((size != st.st_size and size != st.st_size & _rangemask) | 1141 size >= 0 |
1109 or ((mode ^ st.st_mode) & 0o100 and checkexec)) | 1142 and ( |
1110 or size == -2 # other parent | 1143 (size != st.st_size and size != st.st_size & _rangemask) |
1111 or fn in copymap): | 1144 or ((mode ^ st.st_mode) & 0o100 and checkexec) |
1145 ) | |
1146 or size == -2 # other parent | |
1147 or fn in copymap | |
1148 ): | |
1112 madd(fn) | 1149 madd(fn) |
1113 elif (time != st[stat.ST_MTIME] | 1150 elif ( |
1114 and time != st[stat.ST_MTIME] & _rangemask): | 1151 time != st[stat.ST_MTIME] |
1152 and time != st[stat.ST_MTIME] & _rangemask | |
1153 ): | |
1115 ladd(fn) | 1154 ladd(fn) |
1116 elif st[stat.ST_MTIME] == lastnormaltime: | 1155 elif st[stat.ST_MTIME] == lastnormaltime: |
1117 # fn may have just been marked as normal and it may have | 1156 # fn may have just been marked as normal and it may have |
1118 # changed in the same second without changing its size. | 1157 # changed in the same second without changing its size. |
1119 # This can happen if we quickly do multiple commits. | 1158 # This can happen if we quickly do multiple commits. |
1126 elif state == 'a': | 1165 elif state == 'a': |
1127 aadd(fn) | 1166 aadd(fn) |
1128 elif state == 'r': | 1167 elif state == 'r': |
1129 radd(fn) | 1168 radd(fn) |
1130 | 1169 |
1131 return (lookup, scmutil.status(modified, added, removed, deleted, | 1170 return ( |
1132 unknown, ignored, clean)) | 1171 lookup, |
1172 scmutil.status( | |
1173 modified, added, removed, deleted, unknown, ignored, clean | |
1174 ), | |
1175 ) | |
1133 | 1176 |
1134 def matches(self, match): | 1177 def matches(self, match): |
1135 ''' | 1178 ''' |
1136 return files in the dirstate (in whatever state) filtered by match | 1179 return files in the dirstate (in whatever state) filtered by match |
1137 ''' | 1180 ''' |
1162 | 1205 |
1163 # use '_writedirstate' instead of 'write' to write changes certainly, | 1206 # use '_writedirstate' instead of 'write' to write changes certainly, |
1164 # because the latter omits writing out if transaction is running. | 1207 # because the latter omits writing out if transaction is running. |
1165 # output file will be used to create backup of dirstate at this point. | 1208 # output file will be used to create backup of dirstate at this point. |
1166 if self._dirty or not self._opener.exists(filename): | 1209 if self._dirty or not self._opener.exists(filename): |
1167 self._writedirstate(self._opener(filename, "w", atomictemp=True, | 1210 self._writedirstate( |
1168 checkambig=True)) | 1211 self._opener(filename, "w", atomictemp=True, checkambig=True) |
1212 ) | |
1169 | 1213 |
1170 if tr: | 1214 if tr: |
1171 # ensure that subsequent tr.writepending returns True for | 1215 # ensure that subsequent tr.writepending returns True for |
1172 # changes written out above, even if dirstate is never | 1216 # changes written out above, even if dirstate is never |
1173 # changed after this | 1217 # changed after this |
1174 tr.addfilegenerator('dirstate', (self._filename,), | 1218 tr.addfilegenerator( |
1175 self._writedirstate, location='plain') | 1219 'dirstate', |
1220 (self._filename,), | |
1221 self._writedirstate, | |
1222 location='plain', | |
1223 ) | |
1176 | 1224 |
1177 # ensure that pending file written above is unlinked at | 1225 # ensure that pending file written above is unlinked at |
1178 # failure, even if tr.writepending isn't invoked until the | 1226 # failure, even if tr.writepending isn't invoked until the |
1179 # end of this transaction | 1227 # end of this transaction |
1180 tr.registertmp(filename, location='plain') | 1228 tr.registertmp(filename, location='plain') |
1181 | 1229 |
1182 self._opener.tryunlink(backupname) | 1230 self._opener.tryunlink(backupname) |
1183 # hardlink backup is okay because _writedirstate is always called | 1231 # hardlink backup is okay because _writedirstate is always called |
1184 # with an "atomictemp=True" file. | 1232 # with an "atomictemp=True" file. |
1185 util.copyfile(self._opener.join(filename), | 1233 util.copyfile( |
1186 self._opener.join(backupname), hardlink=True) | 1234 self._opener.join(filename), |
1235 self._opener.join(backupname), | |
1236 hardlink=True, | |
1237 ) | |
1187 | 1238 |
1188 def restorebackup(self, tr, backupname): | 1239 def restorebackup(self, tr, backupname): |
1189 '''Restore dirstate by backup file''' | 1240 '''Restore dirstate by backup file''' |
1190 # this "invalidate()" prevents "wlock.release()" from writing | 1241 # this "invalidate()" prevents "wlock.release()" from writing |
1191 # changes of dirstate out after restoring from backup file | 1242 # changes of dirstate out after restoring from backup file |
1198 o.rename(backupname, filename, checkambig=True) | 1249 o.rename(backupname, filename, checkambig=True) |
1199 | 1250 |
1200 def clearbackup(self, tr, backupname): | 1251 def clearbackup(self, tr, backupname): |
1201 '''Clear backup file''' | 1252 '''Clear backup file''' |
1202 self._opener.unlink(backupname) | 1253 self._opener.unlink(backupname) |
1254 | |
1203 | 1255 |
1204 class dirstatemap(object): | 1256 class dirstatemap(object): |
1205 """Map encapsulating the dirstate's contents. | 1257 """Map encapsulating the dirstate's contents. |
1206 | 1258 |
1207 The dirstate contains the following state: | 1259 The dirstate contains the following state: |
1374 try: | 1426 try: |
1375 makefilefoldmap = parsers.make_file_foldmap | 1427 makefilefoldmap = parsers.make_file_foldmap |
1376 except AttributeError: | 1428 except AttributeError: |
1377 pass | 1429 pass |
1378 else: | 1430 else: |
1379 return makefilefoldmap(self._map, util.normcasespec, | 1431 return makefilefoldmap( |
1380 util.normcasefallback) | 1432 self._map, util.normcasespec, util.normcasefallback |
1433 ) | |
1381 | 1434 |
1382 f = {} | 1435 f = {} |
1383 normcase = util.normcase | 1436 normcase = util.normcase |
1384 for name, s in self._map.iteritems(): | 1437 for name, s in self._map.iteritems(): |
1385 if s[0] != 'r': | 1438 if s[0] != 'r': |
1386 f[normcase(name)] = name | 1439 f[normcase(name)] = name |
1387 f['.'] = '.' # prevents useless util.fspath() invocation | 1440 f['.'] = '.' # prevents useless util.fspath() invocation |
1388 return f | 1441 return f |
1389 | 1442 |
1390 def hastrackeddir(self, d): | 1443 def hastrackeddir(self, d): |
1391 """ | 1444 """ |
1392 Returns True if the dirstate contains a tracked (not removed) file | 1445 Returns True if the dirstate contains a tracked (not removed) file |
1411 | 1464 |
1412 def _opendirstatefile(self): | 1465 def _opendirstatefile(self): |
1413 fp, mode = txnutil.trypending(self._root, self._opener, self._filename) | 1466 fp, mode = txnutil.trypending(self._root, self._opener, self._filename) |
1414 if self._pendingmode is not None and self._pendingmode != mode: | 1467 if self._pendingmode is not None and self._pendingmode != mode: |
1415 fp.close() | 1468 fp.close() |
1416 raise error.Abort(_('working directory state may be ' | 1469 raise error.Abort( |
1417 'changed parallelly')) | 1470 _('working directory state may be ' 'changed parallelly') |
1471 ) | |
1418 self._pendingmode = mode | 1472 self._pendingmode = mode |
1419 return fp | 1473 return fp |
1420 | 1474 |
1421 def parents(self): | 1475 def parents(self): |
1422 if not self._parents: | 1476 if not self._parents: |
1434 if l == 40: | 1488 if l == 40: |
1435 self._parents = (st[:20], st[20:40]) | 1489 self._parents = (st[:20], st[20:40]) |
1436 elif l == 0: | 1490 elif l == 0: |
1437 self._parents = (nullid, nullid) | 1491 self._parents = (nullid, nullid) |
1438 else: | 1492 else: |
1439 raise error.Abort(_('working directory state appears ' | 1493 raise error.Abort( |
1440 'damaged!')) | 1494 _('working directory state appears ' 'damaged!') |
1495 ) | |
1441 | 1496 |
1442 return self._parents | 1497 return self._parents |
1443 | 1498 |
1444 def setparents(self, p1, p2): | 1499 def setparents(self, p1, p2): |
1445 self._parents = (p1, p2) | 1500 self._parents = (p1, p2) |
1446 self._dirtyparents = True | 1501 self._dirtyparents = True |
1447 | 1502 |
1448 def read(self): | 1503 def read(self): |
1449 # ignore HG_PENDING because identity is used only for writing | 1504 # ignore HG_PENDING because identity is used only for writing |
1450 self.identity = util.filestat.frompath( | 1505 self.identity = util.filestat.frompath( |
1451 self._opener.join(self._filename)) | 1506 self._opener.join(self._filename) |
1507 ) | |
1452 | 1508 |
1453 try: | 1509 try: |
1454 fp = self._opendirstatefile() | 1510 fp = self._opendirstatefile() |
1455 try: | 1511 try: |
1456 st = fp.read() | 1512 st = fp.read() |
1497 self.__contains__ = self._map.__contains__ | 1553 self.__contains__ = self._map.__contains__ |
1498 self.__getitem__ = self._map.__getitem__ | 1554 self.__getitem__ = self._map.__getitem__ |
1499 self.get = self._map.get | 1555 self.get = self._map.get |
1500 | 1556 |
1501 def write(self, st, now): | 1557 def write(self, st, now): |
1502 st.write(parsers.pack_dirstate(self._map, self.copymap, | 1558 st.write( |
1503 self.parents(), now)) | 1559 parsers.pack_dirstate(self._map, self.copymap, self.parents(), now) |
1560 ) | |
1504 st.close() | 1561 st.close() |
1505 self._dirtyparents = False | 1562 self._dirtyparents = False |
1506 self.nonnormalset, self.otherparentset = self.nonnormalentries() | 1563 self.nonnormalset, self.otherparentset = self.nonnormalentries() |
1507 | 1564 |
1508 @propertycache | 1565 @propertycache |
1530 f[normcase(name)] = name | 1587 f[normcase(name)] = name |
1531 return f | 1588 return f |
1532 | 1589 |
1533 | 1590 |
1534 if rustmod is not None: | 1591 if rustmod is not None: |
1592 | |
1535 class dirstatemap(object): | 1593 class dirstatemap(object): |
1536 def __init__(self, ui, opener, root): | 1594 def __init__(self, ui, opener, root): |
1537 self._ui = ui | 1595 self._ui = ui |
1538 self._opener = opener | 1596 self._opener = opener |
1539 self._root = root | 1597 self._root = root |
1602 | 1660 |
1603 # forward for python2,3 compat | 1661 # forward for python2,3 compat |
1604 iteritems = items | 1662 iteritems = items |
1605 | 1663 |
1606 def _opendirstatefile(self): | 1664 def _opendirstatefile(self): |
1607 fp, mode = txnutil.trypending(self._root, self._opener, | 1665 fp, mode = txnutil.trypending( |
1608 self._filename) | 1666 self._root, self._opener, self._filename |
1667 ) | |
1609 if self._pendingmode is not None and self._pendingmode != mode: | 1668 if self._pendingmode is not None and self._pendingmode != mode: |
1610 fp.close() | 1669 fp.close() |
1611 raise error.Abort(_('working directory state may be ' | 1670 raise error.Abort( |
1612 'changed parallelly')) | 1671 _('working directory state may be ' 'changed parallelly') |
1672 ) | |
1613 self._pendingmode = mode | 1673 self._pendingmode = mode |
1614 return fp | 1674 return fp |
1615 | 1675 |
1616 def setparents(self, p1, p2): | 1676 def setparents(self, p1, p2): |
1617 self._rustmap.setparents(p1, p2) | 1677 self._rustmap.setparents(p1, p2) |
1631 st = '' | 1691 st = '' |
1632 | 1692 |
1633 try: | 1693 try: |
1634 self._parents = self._rustmap.parents(st) | 1694 self._parents = self._rustmap.parents(st) |
1635 except ValueError: | 1695 except ValueError: |
1636 raise error.Abort(_('working directory state appears ' | 1696 raise error.Abort( |
1637 'damaged!')) | 1697 _('working directory state appears ' 'damaged!') |
1698 ) | |
1638 | 1699 |
1639 return self._parents | 1700 return self._parents |
1640 | 1701 |
1641 def read(self): | 1702 def read(self): |
1642 # ignore HG_PENDING because identity is used only for writing | 1703 # ignore HG_PENDING because identity is used only for writing |
1643 self.identity = util.filestat.frompath( | 1704 self.identity = util.filestat.frompath( |
1644 self._opener.join(self._filename)) | 1705 self._opener.join(self._filename) |
1706 ) | |
1645 | 1707 |
1646 try: | 1708 try: |
1647 fp = self._opendirstatefile() | 1709 fp = self._opendirstatefile() |
1648 try: | 1710 try: |
1649 st = fp.read() | 1711 st = fp.read() |
1673 non-normalized versions. | 1735 non-normalized versions. |
1674 """ | 1736 """ |
1675 return self._rustmap.filefoldmapasdict() | 1737 return self._rustmap.filefoldmapasdict() |
1676 | 1738 |
1677 def hastrackeddir(self, d): | 1739 def hastrackeddir(self, d): |
1678 self._dirs # Trigger Python's propertycache | 1740 self._dirs # Trigger Python's propertycache |
1679 return self._rustmap.hastrackeddir(d) | 1741 return self._rustmap.hastrackeddir(d) |
1680 | 1742 |
1681 def hasdir(self, d): | 1743 def hasdir(self, d): |
1682 self._dirs # Trigger Python's propertycache | 1744 self._dirs # Trigger Python's propertycache |
1683 return self._rustmap.hasdir(d) | 1745 return self._rustmap.hasdir(d) |
1684 | 1746 |
1685 @propertycache | 1747 @propertycache |
1686 def _dirs(self): | 1748 def _dirs(self): |
1687 return self._rustmap.getdirs() | 1749 return self._rustmap.getdirs() |