mercurial/dirstate.py
changeset 45942 89a2afe31e82
parent 45243 ad7006830106
child 46678 0d055849d5f9
child 46780 6266d19556ad
equal deleted inserted replaced
45941:346af7687c6f 45942:89a2afe31e82
    72 
    72 
    73 
    73 
    74 @interfaceutil.implementer(intdirstate.idirstate)
    74 @interfaceutil.implementer(intdirstate.idirstate)
    75 class dirstate(object):
    75 class dirstate(object):
    76     def __init__(self, opener, ui, root, validate, sparsematchfn):
    76     def __init__(self, opener, ui, root, validate, sparsematchfn):
    77         '''Create a new dirstate object.
    77         """Create a new dirstate object.
    78 
    78 
    79         opener is an open()-like callable that can be used to open the
    79         opener is an open()-like callable that can be used to open the
    80         dirstate file; root is the root of the directory tracked by
    80         dirstate file; root is the root of the directory tracked by
    81         the dirstate.
    81         the dirstate.
    82         '''
    82         """
    83         self._opener = opener
    83         self._opener = opener
    84         self._validate = validate
    84         self._validate = validate
    85         self._root = root
    85         self._root = root
    86         self._sparsematchfn = sparsematchfn
    86         self._sparsematchfn = sparsematchfn
    87         # ntpath.join(root, '') of Python 2.7.9 does not add sep if root is
    87         # ntpath.join(root, '') of Python 2.7.9 does not add sep if root is
   110         """
   110         """
   111         self._pl
   111         self._pl
   112 
   112 
   113     @contextlib.contextmanager
   113     @contextlib.contextmanager
   114     def parentchange(self):
   114     def parentchange(self):
   115         '''Context manager for handling dirstate parents.
   115         """Context manager for handling dirstate parents.
   116 
   116 
   117         If an exception occurs in the scope of the context manager,
   117         If an exception occurs in the scope of the context manager,
   118         the incoherent dirstate won't be written when wlock is
   118         the incoherent dirstate won't be written when wlock is
   119         released.
   119         released.
   120         '''
   120         """
   121         self._parentwriters += 1
   121         self._parentwriters += 1
   122         yield
   122         yield
   123         # Typically we want the "undo" step of a context manager in a
   123         # Typically we want the "undo" step of a context manager in a
   124         # finally block so it happens even when an exception
   124         # finally block so it happens even when an exception
   125         # occurs. In this case, however, we only want to decrement
   125         # occurs. In this case, however, we only want to decrement
   126         # parentwriters if the code in the with statement exits
   126         # parentwriters if the code in the with statement exits
   127         # normally, so we don't have a try/finally here on purpose.
   127         # normally, so we don't have a try/finally here on purpose.
   128         self._parentwriters -= 1
   128         self._parentwriters -= 1
   129 
   129 
   130     def pendingparentchange(self):
   130     def pendingparentchange(self):
   131         '''Returns true if the dirstate is in the middle of a set of changes
   131         """Returns true if the dirstate is in the middle of a set of changes
   132         that modify the dirstate parent.
   132         that modify the dirstate parent.
   133         '''
   133         """
   134         return self._parentwriters > 0
   134         return self._parentwriters > 0
   135 
   135 
   136     @propertycache
   136     @propertycache
   137     def _map(self):
   137     def _map(self):
   138         """Return the dirstate contents (see documentation for dirstatemap)."""
   138         """Return the dirstate contents (see documentation for dirstatemap)."""
   245         if forcecwd:
   245         if forcecwd:
   246             return forcecwd
   246             return forcecwd
   247         return encoding.getcwd()
   247         return encoding.getcwd()
   248 
   248 
   249     def getcwd(self):
   249     def getcwd(self):
   250         '''Return the path from which a canonical path is calculated.
   250         """Return the path from which a canonical path is calculated.
   251 
   251 
   252         This path should be used to resolve file patterns or to convert
   252         This path should be used to resolve file patterns or to convert
   253         canonical paths back to file paths for display. It shouldn't be
   253         canonical paths back to file paths for display. It shouldn't be
   254         used to get real file paths. Use vfs functions instead.
   254         used to get real file paths. Use vfs functions instead.
   255         '''
   255         """
   256         cwd = self._cwd
   256         cwd = self._cwd
   257         if cwd == self._root:
   257         if cwd == self._root:
   258             return b''
   258             return b''
   259         # self._root ends with a path separator if self._root is '/' or 'C:\'
   259         # self._root ends with a path separator if self._root is '/' or 'C:\'
   260         rootsep = self._root
   260         rootsep = self._root
   273         if self._slash:
   273         if self._slash:
   274             return util.pconvert(path)
   274             return util.pconvert(path)
   275         return path
   275         return path
   276 
   276 
   277     def __getitem__(self, key):
   277     def __getitem__(self, key):
   278         '''Return the current state of key (a filename) in the dirstate.
   278         """Return the current state of key (a filename) in the dirstate.
   279 
   279 
   280         States are:
   280         States are:
   281           n  normal
   281           n  normal
   282           m  needs merging
   282           m  needs merging
   283           r  marked for removal
   283           r  marked for removal
   284           a  marked for addition
   284           a  marked for addition
   285           ?  not tracked
   285           ?  not tracked
   286         '''
   286         """
   287         return self._map.get(key, (b"?",))[0]
   287         return self._map.get(key, (b"?",))[0]
   288 
   288 
   289     def __contains__(self, key):
   289     def __contains__(self, key):
   290         return key in self._map
   290         return key in self._map
   291 
   291 
   368         except:  # re-raises
   368         except:  # re-raises
   369             f.discard()
   369             f.discard()
   370             raise
   370             raise
   371 
   371 
   372     def invalidate(self):
   372     def invalidate(self):
   373         '''Causes the next access to reread the dirstate.
   373         """Causes the next access to reread the dirstate.
   374 
   374 
   375         This is different from localrepo.invalidatedirstate() because it always
   375         This is different from localrepo.invalidatedirstate() because it always
   376         rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
   376         rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
   377         check whether the dirstate has changed before rereading it.'''
   377         check whether the dirstate has changed before rereading it."""
   378 
   378 
   379         for a in ("_map", "_branch", "_ignore"):
   379         for a in ("_map", "_branch", "_ignore"):
   380             if a in self.__dict__:
   380             if a in self.__dict__:
   381                 delattr(self, a)
   381                 delattr(self, a)
   382         self._lastnormaltime = 0
   382         self._lastnormaltime = 0
   424         self._dirty = True
   424         self._dirty = True
   425         self._updatedfiles.add(f)
   425         self._updatedfiles.add(f)
   426         self._map.addfile(f, oldstate, state, mode, size, mtime)
   426         self._map.addfile(f, oldstate, state, mode, size, mtime)
   427 
   427 
   428     def normal(self, f, parentfiledata=None):
   428     def normal(self, f, parentfiledata=None):
   429         '''Mark a file normal and clean.
   429         """Mark a file normal and clean.
   430 
   430 
   431         parentfiledata: (mode, size, mtime) of the clean file
   431         parentfiledata: (mode, size, mtime) of the clean file
   432 
   432 
   433         parentfiledata should be computed from memory (for mode,
   433         parentfiledata should be computed from memory (for mode,
   434         size), as or close as possible from the point where we
   434         size), as or close as possible from the point where we
   435         determined the file was clean, to limit the risk of the
   435         determined the file was clean, to limit the risk of the
   436         file having been changed by an external process between the
   436         file having been changed by an external process between the
   437         moment where the file was determined to be clean and now.'''
   437         moment where the file was determined to be clean and now."""
   438         if parentfiledata:
   438         if parentfiledata:
   439             (mode, size, mtime) = parentfiledata
   439             (mode, size, mtime) = parentfiledata
   440         else:
   440         else:
   441             s = os.lstat(self._join(f))
   441             s = os.lstat(self._join(f))
   442             mode = s.st_mode
   442             mode = s.st_mode
   579                     path, normed, ignoremissing, exists, self._map.dirfoldmap
   579                     path, normed, ignoremissing, exists, self._map.dirfoldmap
   580                 )
   580                 )
   581         return folded
   581         return folded
   582 
   582 
   583     def normalize(self, path, isknown=False, ignoremissing=False):
   583     def normalize(self, path, isknown=False, ignoremissing=False):
   584         '''
   584         """
   585         normalize the case of a pathname when on a casefolding filesystem
   585         normalize the case of a pathname when on a casefolding filesystem
   586 
   586 
   587         isknown specifies whether the filename came from walking the
   587         isknown specifies whether the filename came from walking the
   588         disk, to avoid extra filesystem access.
   588         disk, to avoid extra filesystem access.
   589 
   589 
   594         The normalized case is determined based on the following precedence:
   594         The normalized case is determined based on the following precedence:
   595 
   595 
   596         - version of name already stored in the dirstate
   596         - version of name already stored in the dirstate
   597         - version of name stored on disk
   597         - version of name stored on disk
   598         - version provided via command arguments
   598         - version provided via command arguments
   599         '''
   599         """
   600 
   600 
   601         if self._checkcase:
   601         if self._checkcase:
   602             return self._normalize(path, isknown, ignoremissing)
   602             return self._normalize(path, isknown, ignoremissing)
   603         return path
   603         return path
   604 
   604 
   641             self.drop(f)
   641             self.drop(f)
   642 
   642 
   643         self._dirty = True
   643         self._dirty = True
   644 
   644 
   645     def identity(self):
   645     def identity(self):
   646         '''Return identity of dirstate itself to detect changing in storage
   646         """Return identity of dirstate itself to detect changing in storage
   647 
   647 
   648         If identity of previous dirstate is equal to this, writing
   648         If identity of previous dirstate is equal to this, writing
   649         changes based on the former dirstate out can keep consistency.
   649         changes based on the former dirstate out can keep consistency.
   650         '''
   650         """
   651         return self._map.identity
   651         return self._map.identity
   652 
   652 
   653     def write(self, tr):
   653     def write(self, tr):
   654         if not self._dirty:
   654         if not self._dirty:
   655             return
   655             return
   767                     return (i, lineno, line)
   767                     return (i, lineno, line)
   768             visited.add(i)
   768             visited.add(i)
   769         return (None, -1, b"")
   769         return (None, -1, b"")
   770 
   770 
   771     def _walkexplicit(self, match, subrepos):
   771     def _walkexplicit(self, match, subrepos):
   772         '''Get stat data about the files explicitly specified by match.
   772         """Get stat data about the files explicitly specified by match.
   773 
   773 
   774         Return a triple (results, dirsfound, dirsnotfound).
   774         Return a triple (results, dirsfound, dirsnotfound).
   775         - results is a mapping from filename to stat result. It also contains
   775         - results is a mapping from filename to stat result. It also contains
   776           listings mapping subrepos and .hg to None.
   776           listings mapping subrepos and .hg to None.
   777         - dirsfound is a list of files found to be directories.
   777         - dirsfound is a list of files found to be directories.
   778         - dirsnotfound is a list of files that the dirstate thinks are
   778         - dirsnotfound is a list of files that the dirstate thinks are
   779           directories and that were not found.'''
   779           directories and that were not found."""
   780 
   780 
   781         def badtype(mode):
   781         def badtype(mode):
   782             kind = _(b'unknown')
   782             kind = _(b'unknown')
   783             if stat.S_ISCHR(mode):
   783             if stat.S_ISCHR(mode):
   784                 kind = _(b'character device')
   784                 kind = _(b'character device')
   902                             results[path] = None
   902                             results[path] = None
   903 
   903 
   904         return results, dirsfound, dirsnotfound
   904         return results, dirsfound, dirsnotfound
   905 
   905 
   906     def walk(self, match, subrepos, unknown, ignored, full=True):
   906     def walk(self, match, subrepos, unknown, ignored, full=True):
   907         '''
   907         """
   908         Walk recursively through the directory tree, finding all files
   908         Walk recursively through the directory tree, finding all files
   909         matched by match.
   909         matched by match.
   910 
   910 
   911         If full is False, maybe skip some known-clean files.
   911         If full is False, maybe skip some known-clean files.
   912 
   912 
   913         Return a dict mapping filename to stat-like object (either
   913         Return a dict mapping filename to stat-like object (either
   914         mercurial.osutil.stat instance or return value of os.stat()).
   914         mercurial.osutil.stat instance or return value of os.stat()).
   915 
   915 
   916         '''
   916         """
   917         # full is a flag that extensions that hook into walk can use -- this
   917         # full is a flag that extensions that hook into walk can use -- this
   918         # implementation doesn't use it at all. This satisfies the contract
   918         # implementation doesn't use it at all. This satisfies the contract
   919         # because we only guarantee a "maybe".
   919         # because we only guarantee a "maybe".
   920 
   920 
   921         if ignored:
   921         if ignored:
  1166             clean=clean,
  1166             clean=clean,
  1167         )
  1167         )
  1168         return (lookup, status)
  1168         return (lookup, status)
  1169 
  1169 
  1170     def status(self, match, subrepos, ignored, clean, unknown):
  1170     def status(self, match, subrepos, ignored, clean, unknown):
  1171         '''Determine the status of the working copy relative to the
  1171         """Determine the status of the working copy relative to the
  1172         dirstate and return a pair of (unsure, status), where status is of type
  1172         dirstate and return a pair of (unsure, status), where status is of type
  1173         scmutil.status and:
  1173         scmutil.status and:
  1174 
  1174 
  1175           unsure:
  1175           unsure:
  1176             files that might have been modified since the dirstate was
  1176             files that might have been modified since the dirstate was
  1180             files that have definitely been modified since the dirstate
  1180             files that have definitely been modified since the dirstate
  1181             was written (different size or mode)
  1181             was written (different size or mode)
  1182           status.clean:
  1182           status.clean:
  1183             files that have definitely not been modified since the
  1183             files that have definitely not been modified since the
  1184             dirstate was written
  1184             dirstate was written
  1185         '''
  1185         """
  1186         listignored, listclean, listunknown = ignored, clean, unknown
  1186         listignored, listclean, listunknown = ignored, clean, unknown
  1187         lookup, modified, added, unknown, ignored = [], [], [], [], []
  1187         lookup, modified, added, unknown, ignored = [], [], [], [], []
  1188         removed, deleted, clean = [], [], []
  1188         removed, deleted, clean = [], [], []
  1189 
  1189 
  1190         dmap = self._map
  1190         dmap = self._map
  1303             modified, added, removed, deleted, unknown, ignored, clean
  1303             modified, added, removed, deleted, unknown, ignored, clean
  1304         )
  1304         )
  1305         return (lookup, status)
  1305         return (lookup, status)
  1306 
  1306 
  1307     def matches(self, match):
  1307     def matches(self, match):
  1308         '''
  1308         """
  1309         return files in the dirstate (in whatever state) filtered by match
  1309         return files in the dirstate (in whatever state) filtered by match
  1310         '''
  1310         """
  1311         dmap = self._map
  1311         dmap = self._map
  1312         if rustmod is not None:
  1312         if rustmod is not None:
  1313             dmap = self._map._rustmap
  1313             dmap = self._map._rustmap
  1314 
  1314 
  1315         if match.always():
  1315         if match.always():