mercurial/dirstate.py
changeset 43077 687b865b95ad
parent 43076 2372284d9457
child 43090 1f339b503a40
--- a/mercurial/dirstate.py	Sun Oct 06 09:45:02 2019 -0400
+++ b/mercurial/dirstate.py	Sun Oct 06 09:48:39 2019 -0400
@@ -87,8 +87,8 @@
         self._ui = ui
         self._filecache = {}
         self._parentwriters = 0
-        self._filename = 'dirstate'
-        self._pendingfilename = '%s.pending' % self._filename
+        self._filename = b'dirstate'
+        self._pendingfilename = b'%s.pending' % self._filename
         self._plchangecallbacks = {}
         self._origpl = None
         self._updatedfiles = set()
@@ -140,14 +140,14 @@
         # cache to keep the lookup fast.)
         return self._sparsematchfn()
 
-    @repocache('branch')
+    @repocache(b'branch')
     def _branch(self):
         try:
-            return self._opener.read("branch").strip() or "default"
+            return self._opener.read(b"branch").strip() or b"default"
         except IOError as inst:
             if inst.errno != errno.ENOENT:
                 raise
-            return "default"
+            return b"default"
 
     @property
     def _pl(self):
@@ -156,18 +156,18 @@
     def hasdir(self, d):
         return self._map.hastrackeddir(d)
 
-    @rootcache('.hgignore')
+    @rootcache(b'.hgignore')
     def _ignore(self):
         files = self._ignorefiles()
         if not files:
             return matchmod.never()
 
-        pats = ['include:%s' % f for f in files]
-        return matchmod.match(self._root, '', [], pats, warn=self._ui.warn)
+        pats = [b'include:%s' % f for f in files]
+        return matchmod.match(self._root, b'', [], pats, warn=self._ui.warn)
 
     @propertycache
     def _slash(self):
-        return self._ui.configbool('ui', 'slash') and pycompat.ossep != '/'
+        return self._ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/'
 
     @propertycache
     def _checklink(self):
@@ -179,7 +179,7 @@
 
     @propertycache
     def _checkcase(self):
-        return not util.fscasesensitive(self._join('.hg'))
+        return not util.fscasesensitive(self._join(b'.hg'))
 
     def _join(self, f):
         # much faster than os.path.join()
@@ -193,12 +193,12 @@
                 try:
                     st = os.lstat(self._join(x))
                     if util.statislink(st):
-                        return 'l'
+                        return b'l'
                     if util.statisexec(st):
-                        return 'x'
+                        return b'x'
                 except OSError:
                     pass
-                return ''
+                return b''
 
             return f
 
@@ -207,20 +207,20 @@
 
             def f(x):
                 if os.path.islink(self._join(x)):
-                    return 'l'
-                if 'x' in fallback(x):
-                    return 'x'
-                return ''
+                    return b'l'
+                if b'x' in fallback(x):
+                    return b'x'
+                return b''
 
             return f
         if self._checkexec:
 
             def f(x):
-                if 'l' in fallback(x):
-                    return 'l'
+                if b'l' in fallback(x):
+                    return b'l'
                 if util.isexec(self._join(x)):
-                    return 'x'
-                return ''
+                    return b'x'
+                return b''
 
             return f
         else:
@@ -229,7 +229,7 @@
     @propertycache
     def _cwd(self):
         # internal config: ui.forcecwd
-        forcecwd = self._ui.config('ui', 'forcecwd')
+        forcecwd = self._ui.config(b'ui', b'forcecwd')
         if forcecwd:
             return forcecwd
         return encoding.getcwd()
@@ -243,7 +243,7 @@
         '''
         cwd = self._cwd
         if cwd == self._root:
-            return ''
+            return b''
         # self._root ends with a path separator if self._root is '/' or 'C:\'
         rootsep = self._root
         if not util.endswithsep(rootsep):
@@ -272,7 +272,7 @@
           a  marked for addition
           ?  not tracked
         '''
-        return self._map.get(key, ("?",))[0]
+        return self._map.get(key, (b"?",))[0]
 
     def __contains__(self, key):
         return key in self._map
@@ -308,8 +308,8 @@
         """
         if self._parentwriters == 0:
             raise ValueError(
-                "cannot set dirstate parent outside of "
-                "dirstate.parentchange context manager"
+                b"cannot set dirstate parent outside of "
+                b"dirstate.parentchange context manager"
             )
 
         self._dirty = True
@@ -328,13 +328,13 @@
                     continue
 
                 # Discard 'm' markers when moving away from a merge state
-                if s[0] == 'm':
+                if s[0] == b'm':
                     source = self._map.copymap.get(f)
                     if source:
                         copies[f] = source
                     self.normallookup(f)
                 # Also fix up otherparent markers
-                elif s[0] == 'n' and s[2] == -2:
+                elif s[0] == b'n' and s[2] == -2:
                     source = self._map.copymap.get(f)
                     if source:
                         copies[f] = source
@@ -343,14 +343,14 @@
 
     def setbranch(self, branch):
         self.__class__._branch.set(self, encoding.fromlocal(branch))
-        f = self._opener('branch', 'w', atomictemp=True, checkambig=True)
+        f = self._opener(b'branch', b'w', atomictemp=True, checkambig=True)
         try:
-            f.write(self._branch + '\n')
+            f.write(self._branch + b'\n')
             f.close()
 
             # make sure filecache has the correct stat info for _branch after
             # replacing the underlying file
-            ce = self._filecache['_branch']
+            ce = self._filecache[b'_branch']
             if ce:
                 ce.refresh()
         except:  # re-raises
@@ -393,20 +393,20 @@
 
     def _addpath(self, f, state, mode, size, mtime):
         oldstate = self[f]
-        if state == 'a' or oldstate == 'r':
+        if state == b'a' or oldstate == b'r':
             scmutil.checkfilename(f)
             if self._map.hastrackeddir(f):
                 raise error.Abort(
-                    _('directory %r already in dirstate') % pycompat.bytestr(f)
+                    _(b'directory %r already in dirstate') % pycompat.bytestr(f)
                 )
             # shadows
             for d in util.finddirs(f):
                 if self._map.hastrackeddir(d):
                     break
                 entry = self._map.get(d)
-                if entry is not None and entry[0] != 'r':
+                if entry is not None and entry[0] != b'r':
                     raise error.Abort(
-                        _('file %r in dirstate clashes with %r')
+                        _(b'file %r in dirstate clashes with %r')
                         % (pycompat.bytestr(d), pycompat.bytestr(f))
                     )
         self._dirty = True
@@ -430,7 +430,7 @@
             mode = s.st_mode
             size = s.st_size
             mtime = s[stat.ST_MTIME]
-        self._addpath(f, 'n', mode, size & _rangemask, mtime & _rangemask)
+        self._addpath(f, b'n', mode, size & _rangemask, mtime & _rangemask)
         self._map.copymap.pop(f, None)
         if f in self._map.nonnormalset:
             self._map.nonnormalset.remove(f)
@@ -448,7 +448,7 @@
             # being removed, restore that state.
             entry = self._map.get(f)
             if entry is not None:
-                if entry[0] == 'r' and entry[2] in (-1, -2):
+                if entry[0] == b'r' and entry[2] in (-1, -2):
                     source = self._map.copymap.get(f)
                     if entry[2] == -1:
                         self.merge(f)
@@ -457,28 +457,28 @@
                     if source:
                         self.copy(source, f)
                     return
-                if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
+                if entry[0] == b'm' or entry[0] == b'n' and entry[2] == -2:
                     return
-        self._addpath(f, 'n', 0, -1, -1)
+        self._addpath(f, b'n', 0, -1, -1)
         self._map.copymap.pop(f, None)
 
     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
+                _(b"setting %r to other parent " b"only allowed in merges") % f
             )
-        if f in self and self[f] == 'n':
+        if f in self and self[f] == b'n':
             # merge-like
-            self._addpath(f, 'm', 0, -2, -1)
+            self._addpath(f, b'm', 0, -2, -1)
         else:
             # add-like
-            self._addpath(f, 'n', 0, -2, -1)
+            self._addpath(f, b'n', 0, -2, -1)
         self._map.copymap.pop(f, None)
 
     def add(self, f):
         '''Mark a file added.'''
-        self._addpath(f, 'a', 0, -1, -1)
+        self._addpath(f, b'a', 0, -1, -1)
         self._map.copymap.pop(f, None)
 
     def remove(self, f):
@@ -490,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] == b'm':  # merge
                     size = -1
-                elif entry[0] == 'n' and entry[2] == -2:  # other parent
+                elif entry[0] == b'n' and entry[2] == -2:  # other parent
                     size = -2
                     self._map.otherparentset.add(f)
         self._updatedfiles.add(f)
@@ -519,21 +519,21 @@
             exists = os.path.lexists(os.path.join(self._root, path))
         if not exists:
             # Maybe a path component exists
-            if not ignoremissing and '/' in path:
-                d, f = path.rsplit('/', 1)
+            if not ignoremissing and b'/' in path:
+                d, f = path.rsplit(b'/', 1)
                 d = self._normalize(d, False, ignoremissing, None)
-                folded = d + "/" + f
+                folded = d + b"/" + f
             else:
                 # No path components, preserve original case
                 folded = path
         else:
             # recursively normalize leading directory components
             # against dirstate
-            if '/' in normed:
-                d, f = normed.rsplit('/', 1)
+            if b'/' in normed:
+                d, f = normed.rsplit(b'/', 1)
                 d = self._normalize(d, False, ignoremissing, True)
-                r = self._root + "/" + d
-                folded = d + "/" + util.fspath(f, r)
+                r = self._root + b"/" + d
+                folded = d + b"/" + util.fspath(f, r)
             else:
                 folded = util.fspath(normed, self._root)
             storemap[normed] = folded
@@ -645,14 +645,14 @@
 
             # delay writing in-memory changes out
             tr.addfilegenerator(
-                'dirstate',
+                b'dirstate',
                 (self._filename,),
                 self._writedirstate,
-                location='plain',
+                location=b'plain',
             )
             return
 
-        st = self._opener(filename, "w", atomictemp=True, checkambig=True)
+        st = self._opener(filename, b"w", atomictemp=True, checkambig=True)
         self._writedirstate(st)
 
     def addparentchangecallback(self, category, callback):
@@ -678,12 +678,12 @@
 
         # enough 'delaywrite' prevents 'pack_dirstate' from dropping
         # timestamp of each entries in dirstate, because of 'now > mtime'
-        delaywrite = self._ui.configint('debug', 'dirstate.delaywrite')
+        delaywrite = self._ui.configint(b'debug', b'dirstate.delaywrite')
         if delaywrite > 0:
             # do we have any files to delay for?
             items = self._map.iteritems()
             for f, e in items:
-                if e[0] == 'n' and e[3] == now:
+                if e[0] == b'n' and e[3] == now:
                     import time  # to avoid useless import
 
                     # rather than sleep n seconds, sleep until the next
@@ -715,10 +715,10 @@
 
     def _ignorefiles(self):
         files = []
-        if os.path.exists(self._join('.hgignore')):
-            files.append(self._join('.hgignore'))
-        for name, path in self._ui.configitems("ui"):
-            if name == 'ignore' or name.startswith('ignore.'):
+        if os.path.exists(self._join(b'.hgignore')):
+            files.append(self._join(b'.hgignore'))
+        for name, path in self._ui.configitems(b"ui"):
+            if name == b'ignore' or name.startswith(b'ignore.'):
                 # we need to use os.path.join here rather than self._join
                 # because path is arbitrary and user-specified
                 files.append(os.path.join(self._rootdir, util.expandpath(path)))
@@ -733,18 +733,18 @@
                 i, self._ui.warn, sourceinfo=True
             )
             for pattern, lineno, line in patterns:
-                kind, p = matchmod._patsplit(pattern, 'glob')
-                if kind == "subinclude":
+                kind, p = matchmod._patsplit(pattern, b'glob')
+                if kind == b"subinclude":
                     if p not in visited:
                         files.append(p)
                     continue
                 m = matchmod.match(
-                    self._root, '', [], [pattern], warn=self._ui.warn
+                    self._root, b'', [], [pattern], warn=self._ui.warn
                 )
                 if m(f):
                     return (i, lineno, line)
             visited.add(i)
-        return (None, -1, "")
+        return (None, -1, b"")
 
     def _walkexplicit(self, match, subrepos):
         '''Get stat data about the files explicitly specified by match.
@@ -757,18 +757,18 @@
           directories and that were not found.'''
 
         def badtype(mode):
-            kind = _('unknown')
+            kind = _(b'unknown')
             if stat.S_ISCHR(mode):
-                kind = _('character device')
+                kind = _(b'character device')
             elif stat.S_ISBLK(mode):
-                kind = _('block device')
+                kind = _(b'block device')
             elif stat.S_ISFIFO(mode):
-                kind = _('fifo')
+                kind = _(b'fifo')
             elif stat.S_ISSOCK(mode):
-                kind = _('socket')
+                kind = _(b'socket')
             elif stat.S_ISDIR(mode):
-                kind = _('directory')
-            return _('unsupported file type (type is %s)') % kind
+                kind = _(b'directory')
+            return _(b'unsupported file type (type is %s)') % kind
 
         matchedir = match.explicitdir
         badfn = match.bad
@@ -793,7 +793,7 @@
         subrepos.sort()
         i, j = 0, 0
         while i < len(files) and j < len(subrepos):
-            subpath = subrepos[j] + "/"
+            subpath = subrepos[j] + b"/"
             if files[i] < subpath:
                 i += 1
                 continue
@@ -801,13 +801,13 @@
                 del files[i]
             j += 1
 
-        if not files or '' in files:
-            files = ['']
+        if not files or b'' in files:
+            files = [b'']
             # constructing the foldmap is expensive, so don't do it for the
             # common case where files is ['']
             normalize = None
         results = dict.fromkeys(subrepos)
-        results['.hg'] = None
+        results[b'.hg'] = None
 
         for ff in files:
             if normalize:
@@ -849,7 +849,7 @@
         # aren't filtered here because they will be tested later.
         if match.anypats():
             for f in list(results):
-                if f == '.hg' or f in subrepos:
+                if f == b'.hg' or f in subrepos:
                     # keep sentinel to disable further out-of-repo walks
                     continue
                 if not match(f):
@@ -952,11 +952,11 @@
                 visitentries = match.visitchildrenset(nd)
                 if not visitentries:
                     continue
-                if visitentries == 'this' or visitentries == 'all':
+                if visitentries == b'this' or visitentries == b'all':
                     visitentries = None
                 skip = None
-                if nd != '':
-                    skip = '.hg'
+                if nd != b'':
+                    skip = b'.hg'
                 try:
                     entries = listdir(join(nd), stat=True, skip=skip)
                 except OSError as inst:
@@ -982,10 +982,10 @@
                         # interested in comparing it to files currently in the
                         # dmap -- therefore normalizefile is enough
                         nf = normalizefile(
-                            nd and (nd + "/" + f) or f, True, True
+                            nd and (nd + b"/" + f) or f, True, True
                         )
                     else:
-                        nf = nd and (nd + "/" + f) or f
+                        nf = nd and (nd + b"/" + f) or f
                     if nf not in results:
                         if kind == dirkind:
                             if not ignore(nf):
@@ -1016,7 +1016,7 @@
 
         for s in subrepos:
             del results[s]
-        del results['.hg']
+        del results[b'.hg']
 
         # step 3: visit remaining files from dmap
         if not skipstep3 and not exact:
@@ -1134,9 +1134,9 @@
             size = t[2]
             time = t[3]
 
-            if not st and state in "nma":
+            if not st and state in b"nma":
                 dadd(fn)
-            elif state == 'n':
+            elif state == b'n':
                 if (
                     size >= 0
                     and (
@@ -1160,11 +1160,11 @@
                     ladd(fn)
                 elif listclean:
                     cadd(fn)
-            elif state == 'm':
+            elif state == b'm':
                 madd(fn)
-            elif state == 'a':
+            elif state == b'a':
                 aadd(fn)
-            elif state == 'r':
+            elif state == b'r':
                 radd(fn)
 
         return (
@@ -1208,7 +1208,7 @@
         # 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._opener(filename, b"w", atomictemp=True, checkambig=True)
             )
 
         if tr:
@@ -1216,16 +1216,16 @@
             # changes written out above, even if dirstate is never
             # changed after this
             tr.addfilegenerator(
-                'dirstate',
+                b'dirstate',
                 (self._filename,),
                 self._writedirstate,
-                location='plain',
+                location=b'plain',
             )
 
             # ensure that pending file written above is unlinked at
             # failure, even if tr.writepending isn't invoked until the
             # end of this transaction
-            tr.registertmp(filename, location='plain')
+            tr.registertmp(filename, location=b'plain')
 
         self._opener.tryunlink(backupname)
         # hardlink backup is okay because _writedirstate is always called
@@ -1291,7 +1291,7 @@
         self._ui = ui
         self._opener = opener
         self._root = root
-        self._filename = 'dirstate'
+        self._filename = b'dirstate'
 
         self._parents = None
         self._dirtyparents = False
@@ -1315,12 +1315,12 @@
         self._map.clear()
         self.copymap.clear()
         self.setparents(nullid, nullid)
-        util.clearcachedproperty(self, "_dirs")
-        util.clearcachedproperty(self, "_alldirs")
-        util.clearcachedproperty(self, "filefoldmap")
-        util.clearcachedproperty(self, "dirfoldmap")
-        util.clearcachedproperty(self, "nonnormalset")
-        util.clearcachedproperty(self, "otherparentset")
+        util.clearcachedproperty(self, b"_dirs")
+        util.clearcachedproperty(self, b"_alldirs")
+        util.clearcachedproperty(self, b"filefoldmap")
+        util.clearcachedproperty(self, b"dirfoldmap")
+        util.clearcachedproperty(self, b"nonnormalset")
+        util.clearcachedproperty(self, b"otherparentset")
 
     def items(self):
         return self._map.iteritems()
@@ -1352,12 +1352,12 @@
 
     def addfile(self, f, oldstate, state, mode, size, mtime):
         """Add a tracked file to the dirstate."""
-        if oldstate in "?r" and r"_dirs" in self.__dict__:
+        if oldstate in b"?r" and r"_dirs" in self.__dict__:
             self._dirs.addpath(f)
-        if oldstate == "?" and r"_alldirs" in self.__dict__:
+        if oldstate == b"?" and r"_alldirs" in self.__dict__:
             self._alldirs.addpath(f)
         self._map[f] = dirstatetuple(state, mode, size, mtime)
-        if state != 'n' or mtime == -1:
+        if state != b'n' or mtime == -1:
             self.nonnormalset.add(f)
         if size == -2:
             self.otherparentset.add(f)
@@ -1370,14 +1370,14 @@
         the file's previous state.  In the future, we should refactor this
         to be more explicit about what that state is.
         """
-        if oldstate not in "?r" and r"_dirs" in self.__dict__:
+        if oldstate not in b"?r" and r"_dirs" in self.__dict__:
             self._dirs.delpath(f)
-        if oldstate == "?" and r"_alldirs" in self.__dict__:
+        if oldstate == b"?" and r"_alldirs" in self.__dict__:
             self._alldirs.addpath(f)
         if r"filefoldmap" in self.__dict__:
             normed = util.normcase(f)
             self.filefoldmap.pop(normed, None)
-        self._map[f] = dirstatetuple('r', 0, size, 0)
+        self._map[f] = dirstatetuple(b'r', 0, size, 0)
         self.nonnormalset.add(f)
 
     def dropfile(self, f, oldstate):
@@ -1387,7 +1387,7 @@
         """
         exists = self._map.pop(f, None) is not None
         if exists:
-            if oldstate != "r" and r"_dirs" in self.__dict__:
+            if oldstate != b"r" and r"_dirs" in self.__dict__:
                 self._dirs.delpath(f)
             if r"_alldirs" in self.__dict__:
                 self._alldirs.delpath(f)
@@ -1400,7 +1400,7 @@
     def clearambiguoustimes(self, files, now):
         for f in files:
             e = self.get(f)
-            if e is not None and e[0] == 'n' and e[3] == now:
+            if e is not None and e[0] == b'n' and e[3] == now:
                 self._map[f] = dirstatetuple(e[0], e[1], e[2], -1)
                 self.nonnormalset.add(f)
 
@@ -1412,9 +1412,9 @@
             nonnorm = set()
             otherparent = set()
             for fname, e in self._map.iteritems():
-                if e[0] != 'n' or e[3] == -1:
+                if e[0] != b'n' or e[3] == -1:
                     nonnorm.add(fname)
-                if e[0] == 'n' and e[2] == -2:
+                if e[0] == b'n' and e[2] == -2:
                     otherparent.add(fname)
             return nonnorm, otherparent
 
@@ -1435,9 +1435,9 @@
         f = {}
         normcase = util.normcase
         for name, s in self._map.iteritems():
-            if s[0] != 'r':
+            if s[0] != b'r':
                 f[normcase(name)] = name
-        f['.'] = '.'  # prevents useless util.fspath() invocation
+        f[b'.'] = b'.'  # prevents useless util.fspath() invocation
         return f
 
     def hastrackeddir(self, d):
@@ -1456,7 +1456,7 @@
 
     @propertycache
     def _dirs(self):
-        return util.dirs(self._map, 'r')
+        return util.dirs(self._map, b'r')
 
     @propertycache
     def _alldirs(self):
@@ -1467,7 +1467,7 @@
         if self._pendingmode is not None and self._pendingmode != mode:
             fp.close()
             raise error.Abort(
-                _('working directory state may be ' 'changed parallelly')
+                _(b'working directory state may be ' b'changed parallelly')
             )
         self._pendingmode = mode
         return fp
@@ -1482,7 +1482,7 @@
                 if err.errno != errno.ENOENT:
                     raise
                 # File doesn't exist, so the current state is empty
-                st = ''
+                st = b''
 
             l = len(st)
             if l == 40:
@@ -1491,7 +1491,7 @@
                 self._parents = (nullid, nullid)
             else:
                 raise error.Abort(
-                    _('working directory state appears ' 'damaged!')
+                    _(b'working directory state appears ' b'damaged!')
                 )
 
         return self._parents
@@ -1519,7 +1519,7 @@
         if not st:
             return
 
-        if util.safehasattr(parsers, 'dict_new_presized'):
+        if util.safehasattr(parsers, b'dict_new_presized'):
             # Make an estimate of the number of files in the dirstate based on
             # its size. From a linear regression on a set of real-world repos,
             # all over 10,000 files, the size of a dirstate entry is 85
@@ -1595,7 +1595,7 @@
             self._ui = ui
             self._opener = opener
             self._root = root
-            self._filename = 'dirstate'
+            self._filename = b'dirstate'
             self._parents = None
             self._dirtyparents = False
 
@@ -1636,9 +1636,9 @@
         def clear(self):
             self._rustmap.clear()
             self.setparents(nullid, nullid)
-            util.clearcachedproperty(self, "_dirs")
-            util.clearcachedproperty(self, "_alldirs")
-            util.clearcachedproperty(self, "dirfoldmap")
+            util.clearcachedproperty(self, b"_dirs")
+            util.clearcachedproperty(self, b"_alldirs")
+            util.clearcachedproperty(self, b"dirfoldmap")
 
         def items(self):
             return self._rustmap.items()
@@ -1668,7 +1668,7 @@
             if self._pendingmode is not None and self._pendingmode != mode:
                 fp.close()
                 raise error.Abort(
-                    _('working directory state may be ' 'changed parallelly')
+                    _(b'working directory state may be ' b'changed parallelly')
                 )
             self._pendingmode = mode
             return fp
@@ -1688,13 +1688,13 @@
                     if err.errno != errno.ENOENT:
                         raise
                     # File doesn't exist, so the current state is empty
-                    st = ''
+                    st = b''
 
                 try:
                     self._parents = self._rustmap.parents(st)
                 except ValueError:
                     raise error.Abort(
-                        _('working directory state appears ' 'damaged!')
+                        _(b'working directory state appears ' b'damaged!')
                     )
 
             return self._parents