# HG changeset patch # User Sylvain Thénault # Date 1273047731 -7200 # Node ID b5af2ac0c43c910ddb6fc7a1c586ff5fcf1c5667 # Parent 76b828dc3b9f05481302e97b07bfac5464e49b2a [uiprops] test and fix reloading of modified css files; update c-c newcube; deprecates config.has_resource. diff -r 76b828dc3b9f -r b5af2ac0c43c devtools/__init__.py --- a/devtools/__init__.py Mon May 03 14:17:45 2010 +0200 +++ b/devtools/__init__.py Wed May 05 10:22:11 2010 +0200 @@ -181,10 +181,6 @@ def available_languages(self, *args): return ('en', 'fr', 'de') - def ext_resources_file(self): - """return instance's external resources file""" - return join(self.apphome, 'data', 'external_resources') - def pyro_enabled(self): # but export PYRO_MULTITHREAD=0 or you get problems with sqlite and threads return True diff -r 76b828dc3b9f -r b5af2ac0c43c devtools/devctl.py --- a/devtools/devctl.py Mon May 03 14:17:45 2010 +0200 +++ b/devtools/devctl.py Wed May 05 10:22:11 2010 +0200 @@ -595,7 +595,7 @@ exclude = SKEL_EXCLUDE if self['layout'] == 'simple': exclude += ('sobjects.py*', 'precreate.py*', 'realdb_test*', - 'cubes.*', 'external_resources*') + 'cubes.*', 'uiprops.py*') copy_skeleton(skeldir, cubedir, context, exclude=exclude) def _ask_for_dependencies(self): diff -r 76b828dc3b9f -r b5af2ac0c43c skeleton/data/external_resources.tmpl --- a/skeleton/data/external_resources.tmpl Mon May 03 14:17:45 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -# -*- shell-script -*- -############################################################################### -# -# put here information about external resources used by your components, -# or to overides existing external resources configuration -# -############################################################################### - -# CSS stylesheets to include in HTML headers -# uncomment the line below to use template specific stylesheet -# STYLESHEETS = DATADIR/cubes.%(cubename)s.css diff -r 76b828dc3b9f -r b5af2ac0c43c skeleton/uiprops.py.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/skeleton/uiprops.py.tmpl Wed May 05 10:22:11 2010 +0200 @@ -0,0 +1,15 @@ +############################################################################### +# +# Put here information about external resources / styles used by your cube, +# or to overides existing UI properties. +# +# Existing properties are available through the `sheet` dictionary available +# in the global namespace. You also have access to a `data` function which +# will return proper url for resources in the 'data' directory. +# +# /!\ this file should not be imported /!\ +############################################################################### + +# CSS stylesheets to include in HTML headers +# uncomment the line below to use template specific stylesheet +# STYLESHEETS = sheet['STYLESHEETS'] + [data('cubes.%(cubename)s.css')] diff -r 76b828dc3b9f -r b5af2ac0c43c test/unittest_vregistry.py --- a/test/unittest_vregistry.py Mon May 03 14:17:45 2010 +0200 +++ b/test/unittest_vregistry.py Wed May 05 10:22:11 2010 +0200 @@ -56,21 +56,25 @@ def test_load_subinterface_based_appobjects(self): - self.vreg.reset() self.vreg.register_objects([join(BASE, 'web', 'views', 'iprogress.py')]) # check progressbar was kicked self.failIf(self.vreg['views'].get('progressbar')) + # we've to emulate register_objects to add custom MyCard objects + path = [join(BASE, 'entities', '__init__.py'), + join(BASE, 'web', 'views', 'iprogress.py')] + filemods = self.vreg.init_registration(path, None) + for filepath, modname in filemods: + self.vreg.load_file(filepath, modname) class MyCard(Card): __implements__ = (IMileStone,) - self.vreg.reset() self.vreg._loadedmods[__name__] = {} self.vreg.register(MyCard) - self.vreg.register_objects([join(BASE, 'entities', '__init__.py'), - join(BASE, 'web', 'views', 'iprogress.py')]) + self.vreg.initialization_completed() # check progressbar isn't kicked self.assertEquals(len(self.vreg['views']['progressbar']), 1) def test_properties(self): + self.vreg.reset() self.failIf('system.version.cubicweb' in self.vreg['propertydefs']) self.failUnless(self.vreg.property_info('system.version.cubicweb')) self.assertRaises(UnknownProperty, self.vreg.property_info, 'a.non.existent.key') diff -r 76b828dc3b9f -r b5af2ac0c43c web/propertysheet.py --- a/web/propertysheet.py Mon May 03 14:17:45 2010 +0200 +++ b/web/propertysheet.py Wed May 05 10:22:11 2010 +0200 @@ -47,12 +47,12 @@ self._ordered_propfiles.append(fpath) def need_reload(self): + for rid, (adirectory, rdirectory, mtime) in self._cache.items(): + if os.stat(osp.join(rdirectory, rid))[-2] > mtime: + del self._cache[rid] for fpath, mtime in self._propfile_mtime.iteritems(): if os.stat(fpath)[-2] > mtime: return True - for rid, (directory, mtime) in self._cache.items(): - if os.stat(osp.join(directory, rid))[-2] > mtime: - del self._cache[rid] return False def reload(self): @@ -70,7 +70,7 @@ return self._cache[rid][0] except KeyError: cachefile = osp.join(self._cache_directory, rid) - self.debug('caching processed css %s/%s into %s', + self.debug('caching processed %s/%s into %s', rdirectory, rid, cachefile) rcachedir = osp.dirname(cachefile) if not osp.exists(rcachedir): @@ -83,13 +83,14 @@ content = self.compile(content) except ValueError, ex: self.error("can't process %s/%s: %s", rdirectory, rid, ex) + adirectory = rdirectory else: stream = file(cachefile, 'w') stream.write(content) stream.close() - rdirectory = self._cache_directory - self._cache[rid] = (rdirectory, os.stat(sourcefile)[-2]) - return rdirectory + adirectory = self._cache_directory + self._cache[rid] = (adirectory, rdirectory, os.stat(sourcefile)[-2]) + return adirectory def compile(self, content): return self._percent_rgx.sub('%%', content) % self diff -r 76b828dc3b9f -r b5af2ac0c43c web/test/unittest_propertysheet.py --- a/web/test/unittest_propertysheet.py Mon May 03 14:17:45 2010 +0200 +++ b/web/test/unittest_propertysheet.py Wed May 05 10:22:11 2010 +0200 @@ -1,12 +1,21 @@ +import os from os.path import join, dirname +from shutil import rmtree + from logilab.common.testlib import TestCase, unittest_main + from cubicweb.web.propertysheet import * DATADIR = join(dirname(__file__), 'data') +CACHEDIR = join(DATADIR, 'uicache') + class PropertySheetTC(TestCase): + def tearDown(self): + rmtree(CACHEDIR) + def test(self): - ps = PropertySheet(None, datadir_url='http://cwtest.com') + ps = PropertySheet(CACHEDIR, datadir_url='http://cwtest.com') ps.load(join(DATADIR, 'sheet1.py')) ps.load(join(DATADIR, 'sheet2.py')) # defined by sheet1 @@ -20,6 +29,21 @@ 'http://cwtest.com/mycube.css']) self.assertEquals(ps.compile('a {bgcolor: %(bgcolor)s; size: 1%;}'), 'a {bgcolor: #FFFFFF; size: 1%;}') + self.assertEquals(ps.process_resource(DATADIR, 'pouet.css'), + CACHEDIR) + self.failUnless('pouet.css' in ps._cache) + self.failIf(ps.need_reload()) + os.utime(join(DATADIR, 'sheet1.py'), None) + self.failUnless('pouet.css' in ps._cache) + self.failUnless(ps.need_reload()) + self.failUnless('pouet.css' in ps._cache) + ps.reload() + self.failIf('pouet.css' in ps._cache) + self.failIf(ps.need_reload()) + ps.process_resource(DATADIR, 'pouet.css') # put in cache + os.utime(join(DATADIR, 'pouet.css'), None) + self.failIf(ps.need_reload()) + self.failIf('pouet.css' in ps._cache) if __name__ == '__main__': unittest_main() diff -r 76b828dc3b9f -r b5af2ac0c43c web/webconfig.py --- a/web/webconfig.py Mon May 03 14:17:45 2010 +0200 +++ b/web/webconfig.py Wed May 05 10:22:11 2010 +0200 @@ -26,6 +26,7 @@ from warnings import warn from logilab.common.decorators import cached +from logilab.common.deprecation import deprecated from cubicweb.toolsutils import read_config from cubicweb.cwconfig import CubicWebConfiguration, register_persistent_options, merge_options @@ -253,29 +254,30 @@ user = unicode(user) return user, passwd - def has_resource(self, rid): - """return true if an external resource is defined""" - return bool(self.uiprops.get(rid)) - - @cached def locate_resource(self, rid): """return the directory where the given resource may be found""" return self._fs_locate(rid, 'data') - @cached def locate_doc_file(self, fname): """return the directory where the given resource may be found""" return self._fs_locate(fname, 'wdoc') - def _fs_locate(self, rid, rdirectory): + @cached + def _fs_path_locate(self, rid, rdirectory): """return the directory where the given resource may be found""" path = [self.apphome] + self.cubes_path() + [join(self.shared_dir())] for directory in path: if exists(join(directory, rdirectory, rid)): - if rdirectory == 'data' and rid.endswith('.css'): - return self.uiprops.process_resource(join(directory, rdirectory), - rid) - return join(directory, rdirectory) + return directory + + def _fs_locate(self, rid, rdirectory): + """return the directory where the given resource may be found""" + directory = self._fs_path_locate(rid, rdirectory) + if directory is None: + return None + if rdirectory == 'data' and rid.endswith('.css'): + return self.uiprops.process_resource(join(directory, rdirectory), rid) + return join(directory, rdirectory) def locate_all_files(self, rid, rdirectory='wdoc'): """return all files corresponding to the given resource""" @@ -319,11 +321,11 @@ libuiprops = join(self.shared_dir(), 'data', 'uiprops.py') self.uiprops.load(libuiprops) for path in reversed([self.apphome] + self.cubes_path()): - self._load_ui_properties(join(path, 'data')) + self._load_ui_properties(path) self._load_ui_properties(self.apphome) def _load_ui_properties(self, path): - resourcesfile = join(path, 'external_resources') + resourcesfile = join(path, 'data', 'external_resources') if exists(resourcesfile): warn('[3.9] %s file is deprecated, use an uiprops.py file' % resourcesfile, DeprecationWarning) @@ -367,3 +369,8 @@ def static_file_del(self, rpath): if self.static_file_exists(rpath): os.remove(join(self.static_directory, rpath)) + + @deprecated('[3.9] use _cw.uiprops.get(rid)') + def has_resource(self, rid): + """return true if an external resource is defined""" + return bool(self.uiprops.get(rid))