[web] remove PropertySheet._cache
Instead of remembering that a css file has been processed, we re-process it at
every request. This prevents our cache getting out of date with the file
system. Closes #6893185
While we're at it, write the file atomically so that we don't risk serving
partial data.
--- a/web/propertysheet.py Mon Nov 23 17:47:46 2015 +0100
+++ b/web/propertysheet.py Mon Nov 23 17:58:10 2015 +0100
@@ -22,6 +22,8 @@
import re
import os
import os.path as osp
+import tempfile
+
TYPE_CHECKS = [('STYLESHEETS', list), ('JAVASCRIPTS', list),
('STYLESHEETS_IE', list), ('STYLESHEETS_PRINT', list),
@@ -52,7 +54,6 @@
self._ordered_propfiles = []
self._propfile_mtime = {}
self._sourcefile_mtime = {}
- self._cache = {}
def load(self, fpath):
scriptglobals = self.context.copy()
@@ -69,9 +70,6 @@
self._ordered_propfiles.append(fpath)
def need_reload(self):
- for rid, (adirectory, rdirectory, mtime) in list(self._cache.items()):
- if os.stat(osp.join(rdirectory, rid)).st_mtime > mtime:
- del self._cache[rid]
for fpath, mtime in self._propfile_mtime.items():
if os.stat(fpath).st_mtime > mtime:
return True
@@ -88,31 +86,29 @@
self.reload()
def process_resource(self, rdirectory, rid):
+ cachefile = osp.join(self._cache_directory, rid)
+ self.debug('processing %s/%s into %s',
+ rdirectory, rid, cachefile)
+ rcachedir = osp.dirname(cachefile)
+ if not osp.exists(rcachedir):
+ os.makedirs(rcachedir)
+ sourcefile = osp.join(rdirectory, rid)
+ with open(sourcefile) as f:
+ content = f.read()
+ # XXX replace % not followed by a paren by %% to avoid having to do
+ # this in the source css file ?
try:
- return self._cache[rid][0]
- except KeyError:
- cachefile = osp.join(self._cache_directory, rid)
- self.debug('caching processed %s/%s into %s',
- rdirectory, rid, cachefile)
- rcachedir = osp.dirname(cachefile)
- if not osp.exists(rcachedir):
- os.makedirs(rcachedir)
- sourcefile = osp.join(rdirectory, rid)
- content = open(sourcefile).read()
- # XXX replace % not followed by a paren by %% to avoid having to do
- # this in the source css file ?
- try:
- content = self.compile(content)
- except ValueError as ex:
- self.error("can't process %s/%s: %s", rdirectory, rid, ex)
- adirectory = rdirectory
- else:
- stream = open(cachefile, 'w')
+ content = self.compile(content)
+ except ValueError as ex:
+ self.error("can't process %s/%s: %s", rdirectory, rid, ex)
+ adirectory = rdirectory
+ else:
+ tmpfd, tmpfile = tempfile.mkstemp(dir=rcachedir, prefix=osp.basename(cachefile))
+ with os.fdopen(tmpfd, 'w') as stream:
stream.write(content)
- stream.close()
- adirectory = self._cache_directory
- self._cache[rid] = (adirectory, rdirectory, os.stat(sourcefile).st_mtime)
- return adirectory
+ os.rename(tmpfile, cachefile)
+ adirectory = self._cache_directory
+ return adirectory
def compile(self, content):
return self._percent_rgx.sub('%%', content) % self
--- a/web/test/unittest_propertysheet.py Mon Nov 23 17:47:46 2015 +0100
+++ b/web/test/unittest_propertysheet.py Mon Nov 23 17:58:10 2015 +0100
@@ -49,19 +49,14 @@
'a {bgcolor: #FFFFFF; size: 1%;}')
self.assertEqual(ps.process_resource(DATADIR, 'pouet.css'),
self.cachedir)
- self.assertIn('pouet.css', ps._cache)
self.assertFalse(ps.need_reload())
os.utime(self.data('sheet1.py'), None)
- self.assertIn('pouet.css', ps._cache)
self.assertTrue(ps.need_reload())
- self.assertIn('pouet.css', ps._cache)
ps.reload()
- self.assertNotIn('pouet.css', ps._cache)
self.assertFalse(ps.need_reload())
ps.process_resource(DATADIR, 'pouet.css') # put in cache
os.utime(self.data('pouet.css'), None)
self.assertFalse(ps.need_reload())
- self.assertNotIn('pouet.css', ps._cache)
if __name__ == '__main__':