@@ -12,6 +12,7 @@ import os, stat, errno
propertycache = util.propertycache
filecache = scmutil.filecache
+dynamicfilecache = scmutil.dynamicfilecache
_rangemask = 0x7fffffff
dirstatetuple = parsers.dirstatetuple
@@ -141,7 +142,7 @@ class dirstate(object):
def dirs(self):
return self._dirs
- @rootcache('.hgignore')
+ @dynamicfilecache()
def _ignore(self):
files = [self._join('.hgignore')]
for name, path in self._ui.configitems("ui"):
@@ -149,7 +150,8 @@ class dirstate(object):
# we need to use os.path.join here rather than self._join
# because path is arbitrary and user-specified
files.append(os.path.join(self._rootdir, util.expandpath(path)))
- return ignore.ignore(self._ui, self._root, files)
+ matcher, paths = ignore.ignore(self._ui, self._root, files)
+ return paths, matcher
@propertycache
def _slash(self):
@@ -74,14 +74,16 @@ def readpats(ui, root, files):
'''return a dict mapping ignore-file-name to list-of-patterns'''
pats = {}
+ paths = set()
for f in files:
if f in pats:
continue
skipwarning = f == files[0]
fullpath = os.path.normpath(os.path.join(root, f))
+ paths.add(fullpath)
pats[f] = readignorefile(ui, root, fullpath, skipwarning=skipwarning)
- return [(f, pats[f]) for f in files if f in pats]
+ return [(f, pats[f]) for f in files if f in pats], paths
def ignore(ui, root, files):
'''return matcher covering patterns in 'files'.
@@ -103,13 +105,13 @@ def ignore(ui, root, files):
glob:pattern # non-rooted glob
pattern # pattern of the current default type'''
- pats = readpats(ui, root, files)
+ pats, paths = readpats(ui, root, files)
allpats = []
for f, patlist in pats:
allpats.extend(patlist)
if not allpats:
- return util.never
+ return util.never, paths
try:
ignorefunc = match.match(root, '', [], allpats)
@@ -121,4 +123,4 @@ def ignore(ui, root, files):
except util.Abort, inst:
raise util.Abort('%s: %s' % (f, inst[0]))
- return ignorefunc
+ return ignorefunc, paths
@@ -1164,3 +1164,29 @@ class filecache(object):
del obj.__dict__[self.name]
except KeyError:
raise AttributeError(self.name)
+
+class dynamicfilecache(filecache):
+ """A filecache whose file list is dynamically determined.
+
+ This operates just like a normal filecache, except it expects the returned
+ value to be of the form (paths, value). The paths part represents which
+ files were used to compute the value and is used to check if the cached
+ value is invalid.
+
+ By default, all dynamically defined paths are expected to be absolute paths.
+ """
+ def join(self, obj, fname):
+ return fname
+
+ def __get__(self, obj, type=None):
+ paths, value = super(dynamicfilecache, self).__get__(obj, type=type)
+ if paths != self.paths:
+ self.paths = paths
+ entry = filecacheentry(paths, True)
+ entry.obj = (paths, value)
+ obj._filecache[self.name] = entry
+
+ return value
+
+ def __set__(self, obj, value):
+ super(dynamicfilecache, self).__set__(obj, (self.paths, value))