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()