Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ResourceRegistry in development mode #1859

Merged
merged 3 commits into from Dec 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGES.rst
Expand Up @@ -111,6 +111,17 @@ New features:

- Toolbar: Let the toolbar submenus be as wide as they need to be and do not break entries into multiple lines. [thet]

- Resource Registry:
In ``debug-mode`` (zope.conf, buildout) do not load cache the production bundle.
[jensens]

- Resource Registry:
In ``debug-mode`` (zope.conf, buildout) do not ignore development mode for anonymous users.
[jensens]

- Resource Registry: If file system version is newer than ``last_compilation`` date of a bundle, use this as ``last_compilation`` date.
[jensens]


Bug fixes:

Expand Down Expand Up @@ -197,6 +208,8 @@ Bug fixes:
- URL change for bug tracker, wording tweaks to UPGRADE.txt
[tkimnguyen]

- Cleanup code of resource registry.
[jensens]

5.1a2 (2016-08-19)
------------------
Expand Down
36 changes: 20 additions & 16 deletions Products/CMFPlone/resources/__init__.py
Expand Up @@ -2,36 +2,40 @@
import os


RESOURCE_DEVELOPMENT_MODE = False
if os.getenv('FEDEV', '').lower() == 'true':
RESOURCE_DEVELOPMENT_MODE = True
RESOURCE_DEVELOPMENT_MODE = os.getenv('FEDEV', '').lower() == 'true'


def add_resource_on_request(request, resource):
""" Adds the resource to the request
"""
if not hasattr(request, 'enabled_resources'):
request.enabled_resources = []

if isinstance(resource, str) and resource not in request.enabled_resources:
if not isinstance(resource, str):
raise ValueError(
'add_resource_on_request expects a string value for resource'
)
request.enabled_resources = getattr(request, 'enabled_resources', [])
if resource not in request.enabled_resources:
request.enabled_resources.append(resource)


def add_bundle_on_request(request, bundle):
""" Adds the bundle to the request
"""
if not hasattr(request, 'enabled_bundles'):
request.enabled_bundles = []

if isinstance(bundle, str) and bundle not in request.enabled_bundles:
if not isinstance(bundle, str):
raise ValueError(
'add_bundle_on_request expects a string value for bundle'
)
request.enabled_bundles = getattr(request, 'enabled_bundles', [])
if bundle not in request.enabled_bundles:
request.enabled_bundles.append(bundle)


def remove_bundle_on_request(request, bundle):
""" Removes the bundle to the request
"""
if hasattr(request, 'disabled_bundles'):
if isinstance(bundle, str):
request.disabled_bundles.append(bundle)
else:
request.disabled_bundles = [bundle]
if not isinstance(bundle, str):
raise ValueError(
'remove_bundle_on_request expects a string value for bundle'
)
request.disabled_bundles = getattr(request, 'disabled_bundles', [])
if bundle not in request.disabled_bundles:
request.disabled_bundles.append(bundle)
1 change: 1 addition & 0 deletions Products/CMFPlone/resources/browser/__init__.py
@@ -0,0 +1 @@
# -*- coding: utf-8 -*-
60 changes: 40 additions & 20 deletions Products/CMFPlone/resources/browser/combine.py
Expand Up @@ -14,23 +14,24 @@
import logging
import re

PRODUCTION_RESOURCE_DIRECTORY = "production"

PRODUCTION_RESOURCE_DIRECTORY = 'production'
logger = logging.getLogger(__name__)


def get_production_resource_directory():
persistent_directory = queryUtility(IResourceDirectory, name="persistent")
persistent_directory = queryUtility(IResourceDirectory, name='persistent')
if persistent_directory is None:
return ''
container = persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]
try:
production_folder = container[PRODUCTION_RESOURCE_DIRECTORY]
except NotFound:
return "%s/++unique++1" % PRODUCTION_RESOURCE_DIRECTORY
return '%s/++unique++1' % PRODUCTION_RESOURCE_DIRECTORY
if 'timestamp.txt' not in production_folder:
return "%s/++unique++1" % PRODUCTION_RESOURCE_DIRECTORY
return '%s/++unique++1' % PRODUCTION_RESOURCE_DIRECTORY
timestamp = production_folder.readFile('timestamp.txt')
return "%s/++unique++%s" % (
return '%s/++unique++%s' % (
PRODUCTION_RESOURCE_DIRECTORY, timestamp)


Expand All @@ -46,7 +47,7 @@ def get_resource(context, path):
try:
resource = context.unrestrictedTraverse(path)
except NotFound:
logger.warn(u"Could not find resource {0}. You may have to create it first.".format(path)) # noqa
logger.warn(u'Could not find resource {0}. You may have to create it first.'.format(path)) # noqa
return

if isinstance(resource, FilesystemFile):
Expand All @@ -66,19 +67,35 @@ def write_js(context, folder, meta_bundle):
resources = []

# default resources
if meta_bundle == 'default' and registry.records.get(
'plone.resources/jquery.js'
if (
meta_bundle == 'default' and
registry.records.get('plone.resources/jquery.js')
):
resources.append(get_resource(context,
registry.records['plone.resources/jquery.js'].value))
resources.append(get_resource(context,
registry.records['plone.resources.requirejs'].value))
resources.append(get_resource(context,
registry.records['plone.resources.configjs'].value))
resources.append(
get_resource(
context,
registry.records['plone.resources/jquery.js'].value
)
)
resources.append(
get_resource(
context,
registry.records['plone.resources.requirejs'].value
)
)
resources.append(
get_resource(
context,
registry.records['plone.resources.configjs'].value
)
)

# bundles
bundles = registry.collectionOfInterface(
IBundleRegistry, prefix="plone.bundles", check=False)
IBundleRegistry,
prefix='plone.bundles',
check=False
)
for bundle in bundles.values():
if bundle.merge_with == meta_bundle and bundle.jscompilation:
resource = get_resource(context, bundle.jscompilation)
Expand All @@ -89,15 +106,18 @@ def write_js(context, folder, meta_bundle):
fi = StringIO()
for script in resources:
fi.write(script + '\n')
folder.writeFile(meta_bundle + ".js", fi)
folder.writeFile(meta_bundle + '.js', fi)


def write_css(context, folder, meta_bundle):
registry = getUtility(IRegistry)
resources = []

bundles = registry.collectionOfInterface(
IBundleRegistry, prefix="plone.bundles", check=False)
IBundleRegistry,
prefix='plone.bundles',
check=False
)
for bundle in bundles.values():
if bundle.merge_with == meta_bundle and bundle.csscompilation:
css = get_resource(context, bundle.csscompilation)
Expand All @@ -116,11 +136,11 @@ def write_css(context, folder, meta_bundle):
fi = StringIO()
for script in resources:
fi.write(script + '\n')
folder.writeFile(meta_bundle + ".css", fi)
folder.writeFile(meta_bundle + '.css', fi)


def get_override_directory(context):
persistent_directory = queryUtility(IResourceDirectory, name="persistent")
persistent_directory = queryUtility(IResourceDirectory, name='persistent')
if persistent_directory is None:
return
if OVERRIDE_RESOURCE_DIRECTORY_NAME not in persistent_directory:
Expand All @@ -137,7 +157,7 @@ def combine_bundles(context):
# store timestamp
fi = StringIO()
fi.write(datetime.now().isoformat())
production_folder.writeFile("timestamp.txt", fi)
production_folder.writeFile('timestamp.txt', fi)

# generate new combined bundles
write_js(context, production_folder, 'default')
Expand Down
14 changes: 8 additions & 6 deletions Products/CMFPlone/resources/browser/configjs.py
@@ -1,12 +1,12 @@
# -*- coding: utf-8 -*-
import json
import re

from plone.registry.interfaces import IRegistry
from Products.CMFPlone.interfaces import IResourceRegistry
from Products.Five.browser import BrowserView
from plone.registry.interfaces import IRegistry
from zope.component import getUtility

import json
import re


configjs = """requirejs.config({
baseUrl: PORTAL_URL,
Expand Down Expand Up @@ -87,8 +87,10 @@ class ConfigJsView(RequireJsView):

def __call__(self):
(paths, shims) = self.get_requirejs_config()
self.request.response.setHeader("Content-Type",
"application/javascript")
self.request.response.setHeader(
'Content-Type',
'application/javascript'
)
return configjs % (
json.dumps(paths, indent=4),
_format_shims(shims)
Expand Down
116 changes: 62 additions & 54 deletions Products/CMFPlone/resources/browser/cook.py
@@ -1,26 +1,48 @@
# -*- coding: utf-8 -*-
import logging

from Products.CMFPlone.interfaces.resources import IResourceRegistry
from Products.CMFPlone.interfaces.resources import IBundleRegistry
from Products.CMFPlone.interfaces.resources import OVERRIDE_RESOURCE_DIRECTORY_NAME # noqa
from Products.CMFPlone.resources.browser.combine import combine_bundles
from StringIO import StringIO
from cssmin import cssmin
from datetime import datetime
from plone.protect.interfaces import IDisableCSRFProtection
from plone.registry.interfaces import IRegistry
from plone.resource.interfaces import IResourceDirectory
from plone.subrequest import subrequest
from Products.CMFPlone.interfaces.resources import IBundleRegistry
from Products.CMFPlone.interfaces.resources import IResourceRegistry
from Products.CMFPlone.interfaces.resources import OVERRIDE_RESOURCE_DIRECTORY_NAME # noqa
from Products.CMFPlone.resources.browser.combine import combine_bundles
from slimit import minify
from StringIO import StringIO
from zExceptions import NotFound
from zope.component import getUtility
from zope.component.hooks import getSite
from zope.globalrequest import getRequest
from zope.interface import alsoProvides
from zExceptions import NotFound

import logging


logger = logging.getLogger('Products.CMFPlone')

REQUIREJS_RESET_PREFIX = """
/* reset requirejs definitions so that people who
put requirejs in legacy compilation do not get errors */
var _old_define = define;
var _old_require = require;
define = undefined;
require = undefined;
try{
"""
REQUIREJS_RESET_POSTFIX = """
}catch(e){
// log it
if (typeof console !== "undefined"){
console.log('Error loading javascripts!' + e);
}
}finally{
define = _old_define;
require = _old_require;
}
"""


def cookWhenChangingSettings(context, bundle=None):
"""When our settings are changed, re-cook the not compilable bundles
Expand All @@ -38,60 +60,46 @@ def cookWhenChangingSettings(context, bundle=None):
bundle = bundles.setdefault('plone-legacy')
bundle.resources = []


if not bundle.resources:
# you can have a bundle without any resources defined and it's just shipped
# as a legacy compiled js file
# you can have a bundle without any resources defined and it's just
# shipped as a legacy compiled js file
return

# Let's join all css and js
css_file = ""
cooked_js = """
/* reset requirejs definitions so that people who
put requirejs in legacy compilation do not get errors */
var _old_define = define;
var _old_require = require;
define = undefined;
require = undefined;
try{
"""
css_file = ''
cooked_js = REQUIREJS_RESET_PREFIX
siteUrl = getSite().absolute_url()
request = getRequest()
for package in bundle.resources or []:
if package in resources:
resource = resources[package]
for css in resource.css:
response = subrequest(siteUrl + '/' + css)
if response.status == 200:
css_file += response.getBody()
css_file += '\n'

if resource.js:
response = subrequest(siteUrl + '/' + resource.js)
if response.status == 200:
js = response.getBody()
try:
cooked_js += '\n/* resource: %s */\n%s' % (
resource.js,
minify(js, mangle=False, mangle_toplevel=False)
)
except SyntaxError:
cooked_js += '\n/* resource(error cooking): %s */\n%s' % (
resource.js, js)
else:
cooked_js += '\n/* Could not find resource: %s */\n\n' % resource.js
if package not in resources:
continue
resource = resources[package]
for css in resource.css:
url = siteUrl + '/' + css
response = subrequest(url)
if response.status == 200:
css_file += response.getBody()
css_file += '\n'
else:
css_file += '\n/* Could not find resource: %s */\n\n' % url
if not resource.js:
continue
url = siteUrl + '/' + resource.js
response = subrequest(url)
if response.status == 200:
js = response.getBody()
try:
cooked_js += '\n/* resource: %s */\n%s' % (
resource.js,
minify(js, mangle=False, mangle_toplevel=False)
)
except SyntaxError:
cooked_js += '\n/* resource(error cooking): %s */\n%s' % (
resource.js, js)
else:
cooked_js += '\n/* Could not find resource: %s */\n\n' % url

cooked_js += """
}catch(e){
// log it
if (typeof console !== "undefined"){
console.log('Error loading javascripts!' + e);
}
}finally{
define = _old_define;
require = _old_require;
}
"""
cooked_js += REQUIREJS_RESET_POSTFIX
cooked_css = cssmin(css_file)

js_path = bundle.jscompilation
Expand Down