Commit b0fd409b authored by Sylvain Thénault's avatar Sylvain Thénault
Browse files

[uiprops] test and fix reloading of modified css files; update c-c newcube;...

[uiprops] test and fix reloading of modified css files; update c-c newcube; deprecates config.has_resource.
parent 76b828dc3b9f
...@@ -181,10 +181,6 @@ class BaseApptestConfiguration(TestServerConfiguration, TwistedConfiguration): ...@@ -181,10 +181,6 @@ class BaseApptestConfiguration(TestServerConfiguration, TwistedConfiguration):
def available_languages(self, *args): def available_languages(self, *args):
return ('en', 'fr', 'de') 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): def pyro_enabled(self):
# but export PYRO_MULTITHREAD=0 or you get problems with sqlite and threads # but export PYRO_MULTITHREAD=0 or you get problems with sqlite and threads
return True return True
......
...@@ -595,7 +595,7 @@ layout, and a full featured cube with "full" layout.', ...@@ -595,7 +595,7 @@ layout, and a full featured cube with "full" layout.',
exclude = SKEL_EXCLUDE exclude = SKEL_EXCLUDE
if self['layout'] == 'simple': if self['layout'] == 'simple':
exclude += ('sobjects.py*', 'precreate.py*', 'realdb_test*', exclude += ('sobjects.py*', 'precreate.py*', 'realdb_test*',
'cubes.*', 'external_resources*') 'cubes.*', 'uiprops.py*')
copy_skeleton(skeldir, cubedir, context, exclude=exclude) copy_skeleton(skeldir, cubedir, context, exclude=exclude)
def _ask_for_dependencies(self): def _ask_for_dependencies(self):
......
# -*- shell-script -*-
############################################################################### ###############################################################################
# #
# put here information about external resources used by your components, # Put here information about external resources / styles used by your cube,
# or to overides existing external resources configuration # 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 # CSS stylesheets to include in HTML headers
# uncomment the line below to use template specific stylesheet # uncomment the line below to use template specific stylesheet
# STYLESHEETS = DATADIR/cubes.%(cubename)s.css # STYLESHEETS = sheet['STYLESHEETS'] + [data('cubes.%(cubename)s.css')]
...@@ -56,21 +56,25 @@ class VRegistryTC(TestCase): ...@@ -56,21 +56,25 @@ class VRegistryTC(TestCase):
def test_load_subinterface_based_appobjects(self): def test_load_subinterface_based_appobjects(self):
self.vreg.reset()
self.vreg.register_objects([join(BASE, 'web', 'views', 'iprogress.py')]) self.vreg.register_objects([join(BASE, 'web', 'views', 'iprogress.py')])
# check progressbar was kicked # check progressbar was kicked
self.failIf(self.vreg['views'].get('progressbar')) 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): class MyCard(Card):
__implements__ = (IMileStone,) __implements__ = (IMileStone,)
self.vreg.reset()
self.vreg._loadedmods[__name__] = {} self.vreg._loadedmods[__name__] = {}
self.vreg.register(MyCard) self.vreg.register(MyCard)
self.vreg.register_objects([join(BASE, 'entities', '__init__.py'), self.vreg.initialization_completed()
join(BASE, 'web', 'views', 'iprogress.py')])
# check progressbar isn't kicked # check progressbar isn't kicked
self.assertEquals(len(self.vreg['views']['progressbar']), 1) self.assertEquals(len(self.vreg['views']['progressbar']), 1)
def test_properties(self): def test_properties(self):
self.vreg.reset()
self.failIf('system.version.cubicweb' in self.vreg['propertydefs']) self.failIf('system.version.cubicweb' in self.vreg['propertydefs'])
self.failUnless(self.vreg.property_info('system.version.cubicweb')) self.failUnless(self.vreg.property_info('system.version.cubicweb'))
self.assertRaises(UnknownProperty, self.vreg.property_info, 'a.non.existent.key') self.assertRaises(UnknownProperty, self.vreg.property_info, 'a.non.existent.key')
......
...@@ -47,12 +47,12 @@ class PropertySheet(dict): ...@@ -47,12 +47,12 @@ class PropertySheet(dict):
self._ordered_propfiles.append(fpath) self._ordered_propfiles.append(fpath)
def need_reload(self): 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(): for fpath, mtime in self._propfile_mtime.iteritems():
if os.stat(fpath)[-2] > mtime: if os.stat(fpath)[-2] > mtime:
return True 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 return False
def reload(self): def reload(self):
...@@ -70,7 +70,7 @@ class PropertySheet(dict): ...@@ -70,7 +70,7 @@ class PropertySheet(dict):
return self._cache[rid][0] return self._cache[rid][0]
except KeyError: except KeyError:
cachefile = osp.join(self._cache_directory, rid) 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) rdirectory, rid, cachefile)
rcachedir = osp.dirname(cachefile) rcachedir = osp.dirname(cachefile)
if not osp.exists(rcachedir): if not osp.exists(rcachedir):
...@@ -83,13 +83,14 @@ class PropertySheet(dict): ...@@ -83,13 +83,14 @@ class PropertySheet(dict):
content = self.compile(content) content = self.compile(content)
except ValueError, ex: except ValueError, ex:
self.error("can't process %s/%s: %s", rdirectory, rid, ex) self.error("can't process %s/%s: %s", rdirectory, rid, ex)
adirectory = rdirectory
else: else:
stream = file(cachefile, 'w') stream = file(cachefile, 'w')
stream.write(content) stream.write(content)
stream.close() stream.close()
rdirectory = self._cache_directory adirectory = self._cache_directory
self._cache[rid] = (rdirectory, os.stat(sourcefile)[-2]) self._cache[rid] = (adirectory, rdirectory, os.stat(sourcefile)[-2])
return rdirectory return adirectory
def compile(self, content): def compile(self, content):
return self._percent_rgx.sub('%%', content) % self return self._percent_rgx.sub('%%', content) % self
......
import os
from os.path import join, dirname from os.path import join, dirname
from shutil import rmtree
from logilab.common.testlib import TestCase, unittest_main from logilab.common.testlib import TestCase, unittest_main
from cubicweb.web.propertysheet import * from cubicweb.web.propertysheet import *
DATADIR = join(dirname(__file__), 'data') DATADIR = join(dirname(__file__), 'data')
CACHEDIR = join(DATADIR, 'uicache')
class PropertySheetTC(TestCase): class PropertySheetTC(TestCase):
def tearDown(self):
rmtree(CACHEDIR)
def test(self): 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, 'sheet1.py'))
ps.load(join(DATADIR, 'sheet2.py')) ps.load(join(DATADIR, 'sheet2.py'))
# defined by sheet1 # defined by sheet1
...@@ -20,6 +29,21 @@ class PropertySheetTC(TestCase): ...@@ -20,6 +29,21 @@ class PropertySheetTC(TestCase):
'http://cwtest.com/mycube.css']) 'http://cwtest.com/mycube.css'])
self.assertEquals(ps.compile('a {bgcolor: %(bgcolor)s; size: 1%;}'), self.assertEquals(ps.compile('a {bgcolor: %(bgcolor)s; size: 1%;}'),
'a {bgcolor: #FFFFFF; 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__': if __name__ == '__main__':
unittest_main() unittest_main()
...@@ -26,6 +26,7 @@ from os.path import join, exists, split ...@@ -26,6 +26,7 @@ from os.path import join, exists, split
from warnings import warn from warnings import warn
from logilab.common.decorators import cached from logilab.common.decorators import cached
from logilab.common.deprecation import deprecated
from cubicweb.toolsutils import read_config from cubicweb.toolsutils import read_config
from cubicweb.cwconfig import CubicWebConfiguration, register_persistent_options, merge_options from cubicweb.cwconfig import CubicWebConfiguration, register_persistent_options, merge_options
...@@ -253,29 +254,30 @@ have the python imaging library installed to use captcha)', ...@@ -253,29 +254,30 @@ have the python imaging library installed to use captcha)',
user = unicode(user) user = unicode(user)
return user, passwd 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): def locate_resource(self, rid):
"""return the directory where the given resource may be found""" """return the directory where the given resource may be found"""
return self._fs_locate(rid, 'data') return self._fs_locate(rid, 'data')
@cached
def locate_doc_file(self, fname): def locate_doc_file(self, fname):
"""return the directory where the given resource may be found""" """return the directory where the given resource may be found"""
return self._fs_locate(fname, 'wdoc') 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""" """return the directory where the given resource may be found"""
path = [self.apphome] + self.cubes_path() + [join(self.shared_dir())] path = [self.apphome] + self.cubes_path() + [join(self.shared_dir())]
for directory in path: for directory in path:
if exists(join(directory, rdirectory, rid)): if exists(join(directory, rdirectory, rid)):
if rdirectory == 'data' and rid.endswith('.css'): return directory
return self.uiprops.process_resource(join(directory, rdirectory),
rid) def _fs_locate(self, rid, rdirectory):
return join(directory, 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'): def locate_all_files(self, rid, rdirectory='wdoc'):
"""return all files corresponding to the given resource""" """return all files corresponding to the given resource"""
...@@ -319,11 +321,11 @@ have the python imaging library installed to use captcha)', ...@@ -319,11 +321,11 @@ have the python imaging library installed to use captcha)',
libuiprops = join(self.shared_dir(), 'data', 'uiprops.py') libuiprops = join(self.shared_dir(), 'data', 'uiprops.py')
self.uiprops.load(libuiprops) self.uiprops.load(libuiprops)
for path in reversed([self.apphome] + self.cubes_path()): 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) self._load_ui_properties(self.apphome)
def _load_ui_properties(self, path): def _load_ui_properties(self, path):
resourcesfile = join(path, 'external_resources') resourcesfile = join(path, 'data', 'external_resources')
if exists(resourcesfile): if exists(resourcesfile):
warn('[3.9] %s file is deprecated, use an uiprops.py file' warn('[3.9] %s file is deprecated, use an uiprops.py file'
% resourcesfile, DeprecationWarning) % resourcesfile, DeprecationWarning)
...@@ -367,3 +369,8 @@ have the python imaging library installed to use captcha)', ...@@ -367,3 +369,8 @@ have the python imaging library installed to use captcha)',
def static_file_del(self, rpath): def static_file_del(self, rpath):
if self.static_file_exists(rpath): if self.static_file_exists(rpath):
os.remove(join(self.static_directory, 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))
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment