##// END OF EJS Templates
context: add overlayworkingcontext and overlayworkingfilectx...
Phil Cohen -
r34106:f698bb31 default
parent child Browse files
Show More
@@ -1661,6 +1661,9 b' class workingctx(committablectx):'
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
@@ -1974,6 +1977,191 b' class workingfilectx(committablefilectx)'
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.
General Comments 0
You need to be logged in to leave comments. Login now