##// END OF EJS Templates
context: add overlayworkingcontext and overlayworkingfilectx...
Phil Cohen -
r34106:f698bb31 default
parent child Browse files
Show More
@@ -1661,6 +1661,9 class workingctx(committablectx):
1661 1661 listsubrepos=listsubrepos, badfn=badfn,
1662 1662 icasefs=icasefs)
1663 1663
1664 def flushall(self):
1665 pass # For overlayworkingfilectx compatibility.
1666
1664 1667 def _filtersuspectsymlink(self, files):
1665 1668 if not files or self._repo.dirstate._checklink:
1666 1669 return files
@@ -1974,6 +1977,191 class workingfilectx(committablefilectx)
1974 1977 def setflags(self, l, x):
1975 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 2165 class workingcommitctx(workingctx):
1978 2166 """A workingcommitctx object makes access to data related to
1979 2167 the revision being committed convenient.
General Comments 0
You need to be logged in to leave comments. Login now