diff -r 57875cf423c9 -r 2372284d9457 mercurial/dirstate.py --- a/mercurial/dirstate.py Sat Oct 05 10:29:34 2019 -0400 +++ b/mercurial/dirstate.py Sun Oct 06 09:45:02 2019 -0400 @@ -37,20 +37,25 @@ propertycache = util.propertycache filecache = scmutil.filecache -_rangemask = 0x7fffffff +_rangemask = 0x7FFFFFFF dirstatetuple = parsers.dirstatetuple + class repocache(filecache): """filecache for files in .hg/""" + def join(self, obj, fname): return obj._opener.join(fname) + class rootcache(filecache): """filecache for files in the repository root""" + def join(self, obj, fname): return obj._join(fname) + def _getfsnow(vfs): '''Get "now" timestamp on filesystem''' tmpfd, tmpname = vfs.mkstemp() @@ -60,9 +65,9 @@ os.close(tmpfd) vfs.unlink(tmpname) + @interfaceutil.implementer(intdirstate.idirstate) class dirstate(object): - def __init__(self, opener, ui, root, validate, sparsematchfn): '''Create a new dirstate object. @@ -183,6 +188,7 @@ def flagfunc(self, buildfallback): if self._checklink and self._checkexec: + def f(x): try: st = os.lstat(self._join(x)) @@ -193,24 +199,29 @@ except OSError: pass return '' + return f fallback = buildfallback() if self._checklink: + def f(x): if os.path.islink(self._join(x)): return 'l' if 'x' in fallback(x): return 'x' return '' + return f if self._checkexec: + def f(x): if 'l' in fallback(x): return 'l' if util.isexec(self._join(x)): return 'x' return '' + return f else: return fallback @@ -238,7 +249,7 @@ if not util.endswithsep(rootsep): rootsep += pycompat.ossep if cwd.startswith(rootsep): - return cwd[len(rootsep):] + return cwd[len(rootsep) :] else: # we're outside the repo. return an absolute path. return cwd @@ -296,8 +307,10 @@ See localrepo.setparents() """ if self._parentwriters == 0: - raise ValueError("cannot set dirstate parent outside of " - "dirstate.parentchange context manager") + raise ValueError( + "cannot set dirstate parent outside of " + "dirstate.parentchange context manager" + ) self._dirty = True oldp2 = self._pl[1] @@ -307,7 +320,8 @@ copies = {} if oldp2 != nullid and p2 == nullid: candidatefiles = self._map.nonnormalset.union( - self._map.otherparentset) + self._map.otherparentset + ) for f in candidatefiles: s = self._map.get(f) if s is None: @@ -339,7 +353,7 @@ ce = self._filecache['_branch'] if ce: ce.refresh() - except: # re-raises + except: # re-raises f.discard() raise @@ -382,8 +396,9 @@ if state == 'a' or oldstate == 'r': scmutil.checkfilename(f) if self._map.hastrackeddir(f): - raise error.Abort(_('directory %r already in dirstate') % - pycompat.bytestr(f)) + raise error.Abort( + _('directory %r already in dirstate') % pycompat.bytestr(f) + ) # shadows for d in util.finddirs(f): if self._map.hastrackeddir(d): @@ -391,8 +406,9 @@ entry = self._map.get(d) if entry is not None and entry[0] != 'r': raise error.Abort( - _('file %r in dirstate clashes with %r') % - (pycompat.bytestr(d), pycompat.bytestr(f))) + _('file %r in dirstate clashes with %r') + % (pycompat.bytestr(d), pycompat.bytestr(f)) + ) self._dirty = True self._updatedfiles.add(f) self._map.addfile(f, oldstate, state, mode, size, mtime) @@ -449,8 +465,9 @@ def otherparent(self, f): '''Mark as coming from the other parent, always dirty.''' if self._pl[1] == nullid: - raise error.Abort(_("setting %r to other parent " - "only allowed in merges") % f) + raise error.Abort( + _("setting %r to other parent " "only allowed in merges") % f + ) if f in self and self[f] == 'n': # merge-like self._addpath(f, 'm', 0, -2, -1) @@ -473,9 +490,9 @@ entry = self._map.get(f) if entry is not None: # backup the previous state - if entry[0] == 'm': # merge + if entry[0] == 'm': # merge size = -1 - elif entry[0] == 'n' and entry[2] == -2: # other parent + elif entry[0] == 'n' and entry[2] == -2: # other parent size = -2 self._map.otherparentset.add(f) self._updatedfiles.add(f) @@ -530,8 +547,9 @@ if isknown: folded = path else: - folded = self._discoverpath(path, normed, ignoremissing, exists, - self._map.filefoldmap) + folded = self._discoverpath( + path, normed, ignoremissing, exists, self._map.filefoldmap + ) return folded def _normalize(self, path, isknown, ignoremissing=False, exists=None): @@ -545,8 +563,9 @@ else: # store discovered result in dirfoldmap so that future # normalizefile calls don't start matching directories - folded = self._discoverpath(path, normed, ignoremissing, exists, - self._map.dirfoldmap) + folded = self._discoverpath( + path, normed, ignoremissing, exists, self._map.dirfoldmap + ) return folded def normalize(self, path, isknown=False, ignoremissing=False): @@ -625,8 +644,12 @@ self._updatedfiles.clear() # delay writing in-memory changes out - tr.addfilegenerator('dirstate', (self._filename,), - self._writedirstate, location='plain') + tr.addfilegenerator( + 'dirstate', + (self._filename,), + self._writedirstate, + location='plain', + ) return st = self._opener(filename, "w", atomictemp=True, checkambig=True) @@ -661,14 +684,15 @@ items = self._map.iteritems() for f, e in items: if e[0] == 'n' and e[3] == now: - import time # to avoid useless import + import time # to avoid useless import + # rather than sleep n seconds, sleep until the next # multiple of n seconds clock = time.time() start = int(clock) - (int(clock) % delaywrite) end = start + delaywrite time.sleep(end - clock) - now = end # trust our estimate that the end is near now + now = end # trust our estimate that the end is near now break # since the iterator is potentially not deleted, # delete the iterator to release the reference for the Rust @@ -705,16 +729,18 @@ visited = set() while files: i = files.popleft() - patterns = matchmod.readpatternfile(i, self._ui.warn, - sourceinfo=True) + patterns = matchmod.readpatternfile( + i, self._ui.warn, sourceinfo=True + ) for pattern, lineno, line in patterns: kind, p = matchmod._patsplit(pattern, 'glob') if kind == "subinclude": if p not in visited: files.append(p) continue - m = matchmod.match(self._root, '', [], [pattern], - warn=self._ui.warn) + m = matchmod.match( + self._root, '', [], [pattern], warn=self._ui.warn + ) if m(f): return (i, lineno, line) visited.add(i) @@ -807,10 +833,10 @@ badfn(ff, badtype(kind)) if nf in dmap: results[nf] = None - except OSError as inst: # nf not found on disk - it is dirstate only - if nf in dmap: # does it exactly match a missing file? + except OSError as inst: # nf not found on disk - it is dirstate only + if nf in dmap: # does it exactly match a missing file? results[nf] = None - else: # does it match a missing directory? + else: # does it match a missing directory? if self._map.hasdir(nf): if matchedir: matchedir(nf) @@ -852,8 +878,9 @@ for norm, paths in normed.iteritems(): if len(paths) > 1: for path in paths: - folded = self._discoverpath(path, norm, True, None, - self._map.dirfoldmap) + folded = self._discoverpath( + path, norm, True, None, self._map.dirfoldmap + ) if path != folded: results[path] = None @@ -897,10 +924,10 @@ join = self._join exact = skipstep3 = False - if match.isexact(): # match.exact + if match.isexact(): # match.exact exact = True - dirignore = util.always # skip step 2 - elif match.prefix(): # match.match, no patterns + dirignore = util.always # skip step 2 + elif match.prefix(): # match.match, no patterns skipstep3 = True if not exact and self._checkcase: @@ -934,8 +961,9 @@ entries = listdir(join(nd), stat=True, skip=skip) except OSError as inst: if inst.errno in (errno.EACCES, errno.ENOENT): - match.bad(self.pathto(nd), - encoding.strtolocal(inst.strerror)) + match.bad( + self.pathto(nd), encoding.strtolocal(inst.strerror) + ) continue raise for f, kind, st in entries: @@ -953,8 +981,9 @@ # even though f might be a directory, we're only # interested in comparing it to files currently in the # dmap -- therefore normalizefile is enough - nf = normalizefile(nd and (nd + "/" + f) or f, True, - True) + nf = normalizefile( + nd and (nd + "/" + f) or f, True, True + ) else: nf = nd and (nd + "/" + f) or f if nf not in results: @@ -969,8 +998,9 @@ if nf in dmap: if matchalways or matchfn(nf): results[nf] = st - elif ((matchalways or matchfn(nf)) - and not ignore(nf)): + elif (matchalways or matchfn(nf)) and not ignore( + nf + ): # unknown file -- normalize if necessary if not alreadynormed: nf = normalize(nf, False, True) @@ -1011,8 +1041,10 @@ # different case, don't add one for this, since that would # make it appear as if the file exists under both names # on disk. - if (normalizefile and - normalizefile(nf, True, True) in results): + if ( + normalizefile + and normalizefile(nf, True, True) in results + ): results[nf] = None # Report ignored items in the dmap as long as they are not # under a symlink directory. @@ -1059,7 +1091,7 @@ dmap.preload() dcontains = dmap.__contains__ dget = dmap.__getitem__ - ladd = lookup.append # aka "unsure" + ladd = lookup.append # aka "unsure" madd = modified.append aadd = added.append uadd = unknown.append @@ -1078,8 +1110,9 @@ # - match.traversedir does something, because match.traversedir should # be called for every dir in the working dir full = listclean or match.traversedir is not None - for fn, st in self.walk(match, subrepos, listunknown, listignored, - full=full).iteritems(): + for fn, st in self.walk( + match, subrepos, listunknown, listignored, full=full + ).iteritems(): if not dcontains(fn): if (listignored or mexact(fn)) and dirignore(fn): if listignored: @@ -1104,14 +1137,20 @@ if not st and state in "nma": dadd(fn) elif state == 'n': - if (size >= 0 and - ((size != st.st_size and size != st.st_size & _rangemask) - or ((mode ^ st.st_mode) & 0o100 and checkexec)) - or size == -2 # other parent - or fn in copymap): + if ( + size >= 0 + and ( + (size != st.st_size and size != st.st_size & _rangemask) + or ((mode ^ st.st_mode) & 0o100 and checkexec) + ) + or size == -2 # other parent + or fn in copymap + ): madd(fn) - elif (time != st[stat.ST_MTIME] - and time != st[stat.ST_MTIME] & _rangemask): + elif ( + time != st[stat.ST_MTIME] + and time != st[stat.ST_MTIME] & _rangemask + ): ladd(fn) elif st[stat.ST_MTIME] == lastnormaltime: # fn may have just been marked as normal and it may have @@ -1128,8 +1167,12 @@ elif state == 'r': radd(fn) - return (lookup, scmutil.status(modified, added, removed, deleted, - unknown, ignored, clean)) + return ( + lookup, + scmutil.status( + modified, added, removed, deleted, unknown, ignored, clean + ), + ) def matches(self, match): ''' @@ -1164,15 +1207,20 @@ # because the latter omits writing out if transaction is running. # output file will be used to create backup of dirstate at this point. if self._dirty or not self._opener.exists(filename): - self._writedirstate(self._opener(filename, "w", atomictemp=True, - checkambig=True)) + self._writedirstate( + self._opener(filename, "w", atomictemp=True, checkambig=True) + ) if tr: # ensure that subsequent tr.writepending returns True for # changes written out above, even if dirstate is never # changed after this - tr.addfilegenerator('dirstate', (self._filename,), - self._writedirstate, location='plain') + tr.addfilegenerator( + 'dirstate', + (self._filename,), + self._writedirstate, + location='plain', + ) # ensure that pending file written above is unlinked at # failure, even if tr.writepending isn't invoked until the @@ -1182,8 +1230,11 @@ self._opener.tryunlink(backupname) # hardlink backup is okay because _writedirstate is always called # with an "atomictemp=True" file. - util.copyfile(self._opener.join(filename), - self._opener.join(backupname), hardlink=True) + util.copyfile( + self._opener.join(filename), + self._opener.join(backupname), + hardlink=True, + ) def restorebackup(self, tr, backupname): '''Restore dirstate by backup file''' @@ -1201,6 +1252,7 @@ '''Clear backup file''' self._opener.unlink(backupname) + class dirstatemap(object): """Map encapsulating the dirstate's contents. @@ -1376,15 +1428,16 @@ except AttributeError: pass else: - return makefilefoldmap(self._map, util.normcasespec, - util.normcasefallback) + return makefilefoldmap( + self._map, util.normcasespec, util.normcasefallback + ) f = {} normcase = util.normcase for name, s in self._map.iteritems(): if s[0] != 'r': f[normcase(name)] = name - f['.'] = '.' # prevents useless util.fspath() invocation + f['.'] = '.' # prevents useless util.fspath() invocation return f def hastrackeddir(self, d): @@ -1413,8 +1466,9 @@ fp, mode = txnutil.trypending(self._root, self._opener, self._filename) if self._pendingmode is not None and self._pendingmode != mode: fp.close() - raise error.Abort(_('working directory state may be ' - 'changed parallelly')) + raise error.Abort( + _('working directory state may be ' 'changed parallelly') + ) self._pendingmode = mode return fp @@ -1436,8 +1490,9 @@ elif l == 0: self._parents = (nullid, nullid) else: - raise error.Abort(_('working directory state appears ' - 'damaged!')) + raise error.Abort( + _('working directory state appears ' 'damaged!') + ) return self._parents @@ -1448,7 +1503,8 @@ def read(self): # ignore HG_PENDING because identity is used only for writing self.identity = util.filestat.frompath( - self._opener.join(self._filename)) + self._opener.join(self._filename) + ) try: fp = self._opendirstatefile() @@ -1499,8 +1555,9 @@ self.get = self._map.get def write(self, st, now): - st.write(parsers.pack_dirstate(self._map, self.copymap, - self.parents(), now)) + st.write( + parsers.pack_dirstate(self._map, self.copymap, self.parents(), now) + ) st.close() self._dirtyparents = False self.nonnormalset, self.otherparentset = self.nonnormalentries() @@ -1532,6 +1589,7 @@ if rustmod is not None: + class dirstatemap(object): def __init__(self, ui, opener, root): self._ui = ui @@ -1604,12 +1662,14 @@ iteritems = items def _opendirstatefile(self): - fp, mode = txnutil.trypending(self._root, self._opener, - self._filename) + fp, mode = txnutil.trypending( + self._root, self._opener, self._filename + ) if self._pendingmode is not None and self._pendingmode != mode: fp.close() - raise error.Abort(_('working directory state may be ' - 'changed parallelly')) + raise error.Abort( + _('working directory state may be ' 'changed parallelly') + ) self._pendingmode = mode return fp @@ -1633,15 +1693,17 @@ try: self._parents = self._rustmap.parents(st) except ValueError: - raise error.Abort(_('working directory state appears ' - 'damaged!')) + raise error.Abort( + _('working directory state appears ' 'damaged!') + ) return self._parents def read(self): # ignore HG_PENDING because identity is used only for writing self.identity = util.filestat.frompath( - self._opener.join(self._filename)) + self._opener.join(self._filename) + ) try: fp = self._opendirstatefile() @@ -1675,11 +1737,11 @@ return self._rustmap.filefoldmapasdict() def hastrackeddir(self, d): - self._dirs # Trigger Python's propertycache + self._dirs # Trigger Python's propertycache return self._rustmap.hastrackeddir(d) def hasdir(self, d): - self._dirs # Trigger Python's propertycache + self._dirs # Trigger Python's propertycache return self._rustmap.hasdir(d) @propertycache