Skip to content

Commit

Permalink
TMP - Fixes test setup for yet unknown reason.
Browse files Browse the repository at this point in the history
  • Loading branch information
thet committed Mar 24, 2022
1 parent 706f825 commit b5118f9
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Products/CMFPlone/exportimport/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@
description="Import CMFDiffTool settings">
</genericsetup:importStep>

<genericsetup:importStep
name="combine-bundles"
title="Bundle combination"
description="Combine JS/CSS bundles together"
handler="Products.CMFPlone.resources.exportimport.bundles.combine">
<depends name="plone.app.registry" />
</genericsetup:importStep>

<genericsetup:exportStep
name="content"
title="Content"
Expand Down
154 changes: 154 additions & 0 deletions Products/CMFPlone/resources/browser/combine.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
from Acquisition import aq_base
from datetime import datetime
from io import BytesIO
from plone.registry.interfaces import IRegistry
from plone.resource.file import FilesystemFile
from plone.resource.interfaces import IResourceDirectory
from Products.CMFPlone.interfaces import IBundleRegistry
from Products.CMFPlone.interfaces.resources import OVERRIDE_RESOURCE_DIRECTORY_NAME # noqa
from zExceptions import NotFound
from zope.component import getUtility
from zope.component import queryUtility

import logging
import re
import zope.deferredimport


Expand All @@ -8,3 +22,143 @@
PRODUCTION_RESOURCE_DIRECTORY="Products.CMFPlone:resources.utils.PRODUCTION_RESOURCE_DIRECTORY",
get_override_directory="Products.CMFPlone:resources.utils.get_override_directory",
)


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


def get_production_resource_directory():
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
if "timestamp.txt" not in production_folder:
return "%s/++unique++1" % PRODUCTION_RESOURCE_DIRECTORY
timestamp = production_folder.readFile("timestamp.txt")
if isinstance(timestamp, bytes):
timestamp = timestamp.decode()
return "{}/++unique++{}".format(PRODUCTION_RESOURCE_DIRECTORY, timestamp)


def get_resource(context, path):
if path.startswith("++plone++"):
# ++plone++ resources can be customized, we return their override
# value if any
overrides = get_override_directory(context)
filepath = path[9:]
if overrides.isFile(filepath):
return overrides.readFile(filepath)

try:
resource = context.unrestrictedTraverse(path)
except (NotFound, AttributeError):
logger.warning(
f"Could not find resource {path}. You may have to create it first."
) # noqa
return

if isinstance(resource, FilesystemFile):
(directory, sep, filename) = path.rpartition("/")
return context.unrestrictedTraverse(directory).readFile(filename)

# calling the resource may modify the header, i.e. the content-type.
# we do not want this, so keep the original header intact.
response_before = context.REQUEST.response
context.REQUEST.response = response_before.__class__()
if hasattr(aq_base(resource), "GET"):
# for FileResource
result = resource.GET()
else:
# any BrowserView
result = resource()
context.REQUEST.response = response_before
return result


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

# bundles
bundles = registry.collectionOfInterface(
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)
if not resource:
continue
resources.append(resource)

fi = BytesIO()
for script in resources:
if not isinstance(script, bytes):
script = script.encode()
fi.write(script + b"\n")
folder.writeFile(meta_bundle + ".js", fi)
logger.info('Wrote combined JS bundle "%s".' % meta_bundle)


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

bundles = registry.collectionOfInterface(
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)
if not css:
continue
(path, sep, filename) = bundle.csscompilation.rpartition("/")
# Process relative urls:
# we prefix with current resource path any url not starting with
# '/' or http: or data:
if not isinstance(path, bytes):
path = path.encode()
css = re.sub(
br"""(url\(['"]?(?!['"]?([a-z]+:|\/)))""", br"\1%s/" % path, css
)
resources.append(css)

fi = BytesIO()
for script in resources:
if not isinstance(script, bytes):
script = script.encode()
fi.write(script + b"\n")
folder.writeFile(meta_bundle + ".css", fi)
logger.info('Wrote combined CSS bundle "%s".' % meta_bundle)


def get_override_directory(context):
persistent_directory = queryUtility(IResourceDirectory, name="persistent")
if persistent_directory is None:
return
if OVERRIDE_RESOURCE_DIRECTORY_NAME not in persistent_directory:
persistent_directory.makeDirectory(OVERRIDE_RESOURCE_DIRECTORY_NAME)
return persistent_directory[OVERRIDE_RESOURCE_DIRECTORY_NAME]


def combine_bundles(context):
container = get_override_directory(context)
if PRODUCTION_RESOURCE_DIRECTORY not in container:
container.makeDirectory(PRODUCTION_RESOURCE_DIRECTORY)
production_folder = container[PRODUCTION_RESOURCE_DIRECTORY]

# store timestamp
fi = BytesIO()
fi.write(datetime.now().isoformat().encode())
production_folder.writeFile("timestamp.txt", fi)

# generate new combined bundles
write_js(context, production_folder, "default")
write_js(context, production_folder, "logged-in")
write_css(context, production_folder, "default")
write_css(context, production_folder, "logged-in")
logger.info("Finished bundle compilation.")
Empty file.
33 changes: 33 additions & 0 deletions Products/CMFPlone/resources/exportimport/bundles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from ..browser.combine import combine_bundles
from plone.registry.interfaces import IRegistry
from zope.component import queryUtility


def combine(context):
logger = context.getLogger("bundles")
registry = queryUtility(IRegistry)

if registry is None:
logger.info("Cannot find registry")
return

# Look for a keyword in registry.xml or the registry directory.
filepaths = ["registry.xml"]
if context.isDirectory("registry"):
for filename in context.listDirectory("registry"):
filepaths.append("registry/" + filename)
found = False
for filepath in filepaths:
body = context.readDataFile(filepath)
if body is not None and b"IBundleRegistry" in body:
found = True
break
if not found:
return

# Calling combine_bundles used to have as side effect that the
# Content-Type header of the response was set to application/javascript,
# which we do not want. But that was fixed already in Plone 5.1b2.
# See https://github.com/plone/Products.CMFPlone/pull/1924
site = context.getSite()
combine_bundles(site)

0 comments on commit b5118f9

Please sign in to comment.