mercurial/context.py
branchstable
changeset 49366 288de6f5d724
parent 49306 2e726c934fcd
child 49959 c166b212bdee
child 50215 ae61851e6fe2
equal deleted inserted replaced
49364:e8ea403b1c46 49366:288de6f5d724
     3 # Copyright 2006, 2007 Olivia Mackall <olivia@selenic.com>
     3 # Copyright 2006, 2007 Olivia Mackall <olivia@selenic.com>
     4 #
     4 #
     5 # This software may be used and distributed according to the terms of the
     5 # This software may be used and distributed according to the terms of the
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 from __future__ import absolute_import
     8 
     9 
       
    10 import errno
       
    11 import filecmp
     9 import filecmp
    12 import os
    10 import os
    13 import stat
    11 import stat
    14 
    12 
    15 from .i18n import _
    13 from .i18n import _
    31     metadata,
    29     metadata,
    32     obsolete as obsmod,
    30     obsolete as obsmod,
    33     patch,
    31     patch,
    34     pathutil,
    32     pathutil,
    35     phases,
    33     phases,
    36     pycompat,
       
    37     repoview,
    34     repoview,
    38     scmutil,
    35     scmutil,
    39     sparse,
    36     sparse,
    40     subrepo,
    37     subrepo,
    41     subrepoutil,
    38     subrepoutil,
    50 )
    47 )
    51 
    48 
    52 propertycache = util.propertycache
    49 propertycache = util.propertycache
    53 
    50 
    54 
    51 
    55 class basectx(object):
    52 class basectx:
    56     """A basectx object represents the common logic for its children:
    53     """A basectx object represents the common logic for its children:
    57     changectx: read-only context that is already present in the repo,
    54     changectx: read-only context that is already present in the repo,
    58     workingctx: a context that represents the working directory and can
    55     workingctx: a context that represents the working directory and can
    59                 be committed,
    56                 be committed,
    60     memctx: a context that represents changes in-memory and can also
    57     memctx: a context that represents changes in-memory and can also
   122         removed = []
   119         removed = []
   123         clean = []
   120         clean = []
   124         deleted, unknown, ignored = s.deleted, s.unknown, s.ignored
   121         deleted, unknown, ignored = s.deleted, s.unknown, s.ignored
   125         deletedset = set(deleted)
   122         deletedset = set(deleted)
   126         d = mf1.diff(mf2, match=match, clean=listclean)
   123         d = mf1.diff(mf2, match=match, clean=listclean)
   127         for fn, value in pycompat.iteritems(d):
   124         for fn, value in d.items():
   128             if fn in deletedset:
   125             if fn in deletedset:
   129                 continue
   126                 continue
   130             if value is None:
   127             if value is None:
   131                 clean.append(fn)
   128                 clean.append(fn)
   132                 continue
   129                 continue
   795 
   792 
   796     def matches(self, match):
   793     def matches(self, match):
   797         return self.walk(match)
   794         return self.walk(match)
   798 
   795 
   799 
   796 
   800 class basefilectx(object):
   797 class basefilectx:
   801     """A filecontext object represents the common logic for its children:
   798     """A filecontext object represents the common logic for its children:
   802     filectx: read-only access to a filerevision that is already present
   799     filectx: read-only access to a filerevision that is already present
   803              in the repo,
   800              in the repo,
   804     workingfilectx: a filecontext that represents files from the working
   801     workingfilectx: a filecontext that represents files from the working
   805                     directory,
   802                     directory,
   991 
   988 
   992         if fctx._filenode is None:
   989         if fctx._filenode is None:
   993             if self._repo._encodefilterpats:
   990             if self._repo._encodefilterpats:
   994                 # can't rely on size() because wdir content may be decoded
   991                 # can't rely on size() because wdir content may be decoded
   995                 return self._filelog.cmp(self._filenode, fctx.data())
   992                 return self._filelog.cmp(self._filenode, fctx.data())
       
   993             # filelog.size() has two special cases:
       
   994             # - censored metadata
       
   995             # - copy/rename tracking
       
   996             # The first is detected by peaking into the delta,
       
   997             # the second is detected by abusing parent order
       
   998             # in the revlog index as flag bit. This leaves files using
       
   999             # the dummy encoding and non-standard meta attributes.
       
  1000             # The following check is a special case for the empty
       
  1001             # metadata block used if the raw file content starts with '\1\n'.
       
  1002             # Cases of arbitrary metadata flags are currently mishandled.
   996             if self.size() - 4 == fctx.size():
  1003             if self.size() - 4 == fctx.size():
   997                 # size() can match:
  1004                 # size() can match:
   998                 # if file data starts with '\1\n', empty metadata block is
  1005                 # if file data starts with '\1\n', empty metadata block is
   999                 # prepended, which adds 4 bytes to filelog.size().
  1006                 # prepended, which adds 4 bytes to filelog.size().
  1000                 return self._filelog.cmp(self._filenode, fctx.data())
  1007                 return self._filelog.cmp(self._filenode, fctx.data())
  1727             return rejected
  1734             return rejected
  1728 
  1735 
  1729     def copy(self, source, dest):
  1736     def copy(self, source, dest):
  1730         try:
  1737         try:
  1731             st = self._repo.wvfs.lstat(dest)
  1738             st = self._repo.wvfs.lstat(dest)
  1732         except OSError as err:
  1739         except FileNotFoundError:
  1733             if err.errno != errno.ENOENT:
       
  1734                 raise
       
  1735             self._repo.ui.warn(
  1740             self._repo.ui.warn(
  1736                 _(b"%s does not exist!\n") % self._repo.dirstate.pathto(dest)
  1741                 _(b"%s does not exist!\n") % self._repo.dirstate.pathto(dest)
  1737             )
  1742             )
  1738             return
  1743             return
  1739         if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
  1744         if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)):
  2159 
  2164 
  2160     def date(self):
  2165     def date(self):
  2161         t, tz = self._changectx.date()
  2166         t, tz = self._changectx.date()
  2162         try:
  2167         try:
  2163             return (self._repo.wvfs.lstat(self._path)[stat.ST_MTIME], tz)
  2168             return (self._repo.wvfs.lstat(self._path)[stat.ST_MTIME], tz)
  2164         except OSError as err:
  2169         except FileNotFoundError:
  2165             if err.errno != errno.ENOENT:
       
  2166                 raise
       
  2167             return (t, tz)
  2170             return (t, tz)
  2168 
  2171 
  2169     def exists(self):
  2172     def exists(self):
  2170         return self._repo.wvfs.exists(self._path)
  2173         return self._repo.wvfs.exists(self._path)
  2171 
  2174 
  2420                 )
  2423                 )
  2421 
  2424 
  2422         # Test that each new directory to be created to write this path from p2
  2425         # Test that each new directory to be created to write this path from p2
  2423         # is not a file in p1.
  2426         # is not a file in p1.
  2424         components = path.split(b'/')
  2427         components = path.split(b'/')
  2425         for i in pycompat.xrange(len(components)):
  2428         for i in range(len(components)):
  2426             component = b"/".join(components[0:i])
  2429             component = b"/".join(components[0:i])
  2427             if component in self:
  2430             if component in self:
  2428                 fail(path, component)
  2431                 fail(path, component)
  2429 
  2432 
  2430         # Test the other direction -- that this path from p2 isn't a directory
  2433         # Test the other direction -- that this path from p2 isn't a directory
  3103                 removed.append(f)
  3106                 removed.append(f)
  3104 
  3107 
  3105         return scmutil.status(modified, added, removed, [], [], [], [])
  3108         return scmutil.status(modified, added, removed, [], [], [], [])
  3106 
  3109 
  3107 
  3110 
  3108 class arbitraryfilectx(object):
  3111 class arbitraryfilectx:
  3109     """Allows you to use filectx-like functions on a file in an arbitrary
  3112     """Allows you to use filectx-like functions on a file in an arbitrary
  3110     location on disk, possibly not in the working directory.
  3113     location on disk, possibly not in the working directory.
  3111     """
  3114     """
  3112 
  3115 
  3113     def __init__(self, path, repo=None):
  3116     def __init__(self, path, repo=None):