Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/context.py @ 34119:f698bb31bdfb
context: add overlayworkingcontext and overlayworkingfilectx
These two classes will be used extensively in the first in-memory merge
milestone.
Differential Revision: https://phab.mercurial-scm.org/D616
author | Phil Cohen <phillco@fb.com> |
---|---|
date | Mon, 11 Sep 2017 13:03:27 -0700 |
parents | d2fc88426d21 |
children | 0fa781320203 |
comparison
equal
deleted
inserted
replaced
34118:92f1e2be8ab6 | 34119:f698bb31bdfb |
---|---|
1659 return matchmod.match(r.root, r.getcwd(), pats, include, exclude, | 1659 return matchmod.match(r.root, r.getcwd(), pats, include, exclude, |
1660 default, auditor=r.auditor, ctx=self, | 1660 default, auditor=r.auditor, ctx=self, |
1661 listsubrepos=listsubrepos, badfn=badfn, | 1661 listsubrepos=listsubrepos, badfn=badfn, |
1662 icasefs=icasefs) | 1662 icasefs=icasefs) |
1663 | 1663 |
1664 def flushall(self): | |
1665 pass # For overlayworkingfilectx compatibility. | |
1666 | |
1664 def _filtersuspectsymlink(self, files): | 1667 def _filtersuspectsymlink(self, files): |
1665 if not files or self._repo.dirstate._checklink: | 1668 if not files or self._repo.dirstate._checklink: |
1666 return files | 1669 return files |
1667 | 1670 |
1668 # Symlink placeholders may get non-symlink-like contents | 1671 # Symlink placeholders may get non-symlink-like contents |
1972 wvfs.removedirs(self._path) | 1975 wvfs.removedirs(self._path) |
1973 | 1976 |
1974 def setflags(self, l, x): | 1977 def setflags(self, l, x): |
1975 self._repo.wvfs.setflags(self._path, l, x) | 1978 self._repo.wvfs.setflags(self._path, l, x) |
1976 | 1979 |
1980 class overlayworkingctx(workingctx): | |
1981 """Wraps another mutable context with a write-back cache that can be flushed | |
1982 at a later time. | |
1983 | |
1984 self._cache[path] maps to a dict with keys: { | |
1985 'exists': bool? | |
1986 'date': date? | |
1987 'data': str? | |
1988 'flags': str? | |
1989 } | |
1990 If `exists` is True, `flags` must be non-None and 'date' is non-None. If it | |
1991 is `False`, the file was deleted. | |
1992 """ | |
1993 | |
1994 def __init__(self, repo, wrappedctx): | |
1995 super(overlayworkingctx, self).__init__(repo) | |
1996 self._repo = repo | |
1997 self._wrappedctx = wrappedctx | |
1998 self._clean() | |
1999 | |
2000 def data(self, path): | |
2001 if self.isdirty(path): | |
2002 if self._cache[path]['exists']: | |
2003 if self._cache[path]['data']: | |
2004 return self._cache[path]['data'] | |
2005 else: | |
2006 # Must fallback here, too, because we only set flags. | |
2007 return self._wrappedctx[path].data() | |
2008 else: | |
2009 raise error.ProgrammingError("No such file or directory: %s" % | |
2010 self._path) | |
2011 else: | |
2012 return self._wrappedctx[path].data() | |
2013 | |
2014 def filedate(self, path): | |
2015 if self.isdirty(path): | |
2016 return self._cache[path]['date'] | |
2017 else: | |
2018 return self._wrappedctx[path].date() | |
2019 | |
2020 def flags(self, path): | |
2021 if self.isdirty(path): | |
2022 if self._cache[path]['exists']: | |
2023 return self._cache[path]['flags'] | |
2024 else: | |
2025 raise error.ProgrammingError("No such file or directory: %s" % | |
2026 self._path) | |
2027 else: | |
2028 return self._wrappedctx[path].flags() | |
2029 | |
2030 def write(self, path, data, flags=''): | |
2031 if data is None: | |
2032 raise error.ProgrammingError("data must be non-None") | |
2033 self._markdirty(path, exists=True, data=data, date=util.makedate(), | |
2034 flags=flags) | |
2035 | |
2036 def setflags(self, path, l, x): | |
2037 self._markdirty(path, exists=True, date=util.makedate(), | |
2038 flags=(l and 'l' or '') + (x and 'x' or '')) | |
2039 | |
2040 def remove(self, path): | |
2041 self._markdirty(path, exists=False) | |
2042 | |
2043 def exists(self, path): | |
2044 """exists behaves like `lexists`, but needs to follow symlinks and | |
2045 return False if they are broken. | |
2046 """ | |
2047 if self.isdirty(path): | |
2048 # If this path exists and is a symlink, "follow" it by calling | |
2049 # exists on the destination path. | |
2050 if (self._cache[path]['exists'] and | |
2051 'l' in self._cache[path]['flags']): | |
2052 return self.exists(self._cache[path]['data'].strip()) | |
2053 else: | |
2054 return self._cache[path]['exists'] | |
2055 return self._wrappedctx[path].exists() | |
2056 | |
2057 def lexists(self, path): | |
2058 """lexists returns True if the path exists""" | |
2059 if self.isdirty(path): | |
2060 return self._cache[path]['exists'] | |
2061 return self._wrappedctx[path].lexists() | |
2062 | |
2063 def size(self, path): | |
2064 if self.isdirty(path): | |
2065 if self._cache[path]['exists']: | |
2066 return len(self._cache[path]['data']) | |
2067 else: | |
2068 raise error.ProgrammingError("No such file or directory: %s" % | |
2069 self._path) | |
2070 return self._wrappedctx[path].size() | |
2071 | |
2072 def flushall(self): | |
2073 for path in self._writeorder: | |
2074 entry = self._cache[path] | |
2075 if entry['exists']: | |
2076 self._wrappedctx[path].clearunknown() | |
2077 if entry['data'] is not None: | |
2078 if entry['flags'] is None: | |
2079 raise error.ProgrammingError('data set but not flags') | |
2080 self._wrappedctx[path].write( | |
2081 entry['data'], | |
2082 entry['flags']) | |
2083 else: | |
2084 self._wrappedctx[path].setflags( | |
2085 'l' in entry['flags'], | |
2086 'x' in entry['flags']) | |
2087 else: | |
2088 self._wrappedctx[path].remove(path) | |
2089 self._clean() | |
2090 | |
2091 def isdirty(self, path): | |
2092 return path in self._cache | |
2093 | |
2094 def _clean(self): | |
2095 self._cache = {} | |
2096 self._writeorder = [] | |
2097 | |
2098 def _markdirty(self, path, exists, data=None, date=None, flags=''): | |
2099 if path not in self._cache: | |
2100 self._writeorder.append(path) | |
2101 | |
2102 self._cache[path] = { | |
2103 'exists': exists, | |
2104 'data': data, | |
2105 'date': date, | |
2106 'flags': flags, | |
2107 } | |
2108 | |
2109 def filectx(self, path, filelog=None): | |
2110 return overlayworkingfilectx(self._repo, path, parent=self, | |
2111 filelog=filelog) | |
2112 | |
2113 class overlayworkingfilectx(workingfilectx): | |
2114 """Wrap a ``workingfilectx`` but intercepts all writes into an in-memory | |
2115 cache, which can be flushed through later by calling ``flush()``.""" | |
2116 | |
2117 def __init__(self, repo, path, filelog=None, parent=None): | |
2118 super(overlayworkingfilectx, self).__init__(repo, path, filelog, | |
2119 parent) | |
2120 self._repo = repo | |
2121 self._parent = parent | |
2122 self._path = path | |
2123 | |
2124 def ctx(self): | |
2125 return self._parent | |
2126 | |
2127 def data(self): | |
2128 return self._parent.data(self._path) | |
2129 | |
2130 def date(self): | |
2131 return self._parent.filedate(self._path) | |
2132 | |
2133 def exists(self): | |
2134 return self.lexists() | |
2135 | |
2136 def lexists(self): | |
2137 return self._parent.exists(self._path) | |
2138 | |
2139 def renamed(self): | |
2140 # Copies are currently tracked in the dirstate as before. Straight copy | |
2141 # from workingfilectx. | |
2142 rp = self._repo.dirstate.copied(self._path) | |
2143 if not rp: | |
2144 return None | |
2145 return rp, self._changectx._parents[0]._manifest.get(rp, nullid) | |
2146 | |
2147 def size(self): | |
2148 return self._parent.size(self._path) | |
2149 | |
2150 def audit(self): | |
2151 pass | |
2152 | |
2153 def flags(self): | |
2154 return self._parent.flags(self._path) | |
2155 | |
2156 def setflags(self, islink, isexec): | |
2157 return self._parent.setflags(self._path, islink, isexec) | |
2158 | |
2159 def write(self, data, flags, backgroundclose=False): | |
2160 return self._parent.write(self._path, data, flags) | |
2161 | |
2162 def remove(self, ignoremissing=False): | |
2163 return self._parent.remove(self._path) | |
2164 | |
1977 class workingcommitctx(workingctx): | 2165 class workingcommitctx(workingctx): |
1978 """A workingcommitctx object makes access to data related to | 2166 """A workingcommitctx object makes access to data related to |
1979 the revision being committed convenient. | 2167 the revision being committed convenient. |
1980 | 2168 |
1981 This hides changes in the working directory, if they aren't | 2169 This hides changes in the working directory, if they aren't |