filecache: create an entry in _filecache when __set__ is called for a missing one
Preserve the invariant that if P is a filecached property on X then
P in X.__dict__ => P in X._filecache.
Previously, it was possible for a filecached property to become out of sync
with the filesystem if it was set before getting it first, since the initial
filecacheentry was created in __get__.
Old behaviour:
repo.prop = x
repo.invalidate() # prop has no entry in _filecache, it's not removed
# from __dict__
repo.prop # returns x like before without checking with the
# filesystem
New:
repo.prop = x # an empty entry is created in _filecache
repo.invalidate() # prop is removed from __dict__
repo.prop # recreates prop
--- a/mercurial/scmutil.py Thu Jan 10 23:54:53 2013 +0200
+++ b/mercurial/scmutil.py Mon Dec 17 15:25:45 2012 +0200
@@ -950,6 +950,7 @@
def __get__(self, obj, type=None):
# do we need to check if the file changed?
if self.name in obj.__dict__:
+ assert self.name in obj._filecache, self.name
return obj.__dict__[self.name]
entry = obj._filecache.get(self.name)
@@ -971,8 +972,15 @@
return entry.obj
def __set__(self, obj, value):
- if self.name in obj._filecache:
- obj._filecache[self.name].obj = value # update cached copy
+ if self.name not in obj._filecache:
+ # we add an entry for the missing value because X in __dict__
+ # implies X in _filecache
+ ce = filecacheentry(self.join(obj, self.path), False)
+ obj._filecache[self.name] = ce
+ else:
+ ce = obj._filecache[self.name]
+
+ ce.obj = value # update cached copy
obj.__dict__[self.name] = value # update copy returned by obj.x
def __delete__(self, obj):
--- a/tests/test-filecache.py Thu Jan 10 23:54:53 2013 +0200
+++ b/tests/test-filecache.py Mon Dec 17 15:25:45 2012 +0200
@@ -101,6 +101,17 @@
# it
repo.commit('.')
+def setbeforeget(repo):
+ os.remove('x')
+ repo.cached = 0
+ repo.invalidate()
+ print repo.cached
+ repo.invalidate()
+ f = open('x', 'w')
+ f.write('a')
+ f.close()
+ print repo.cached
+
print 'basic:'
print
basic(fakerepo())
@@ -109,3 +120,7 @@
print
fakeuncacheable()
test_filecache_synced()
+print
+print 'setbeforeget:'
+print
+setbeforeget(fakerepo())
--- a/tests/test-filecache.py.out Thu Jan 10 23:54:53 2013 +0200
+++ b/tests/test-filecache.py.out Mon Dec 17 15:25:45 2012 +0200
@@ -17,3 +17,9 @@
working directory now based on revision -1
repository tip rolled back to revision -1 (undo commit)
working directory now based on revision -1
+
+setbeforeget:
+
+0
+creating
+None