diff --git a/last_commit.txt b/last_commit.txt index 61d04f9e31..1fc01a4108 100644 --- a/last_commit.txt +++ b/last_commit.txt @@ -1,160 +1,113 @@ -Repository: Products.isurlinportal +Repository: Products.CMFPlone Branch: refs/heads/master -Date: 2023-04-09T14:44:33+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/Products.isurlinportal/commit/a62e7ea389aa1281c7e88521b8456863d36a0482 - -Configuring with plone/meta - -Files changed: -A .editorconfig -A .meta.toml -A .pre-commit-config.yaml -A news/3333c742.internal -M pyproject.toml -M setup.cfg -M tox.ini - -b'diff --git a/.editorconfig b/.editorconfig\nnew file mode 100644\nindex 0000000..b4158b8\n--- /dev/null\n+++ b/.editorconfig\n@@ -0,0 +1,39 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+#\n+# EditorConfig Configuration file, for more details see:\n+# http://EditorConfig.org\n+# EditorConfig is a convention description, that could be interpreted\n+# by multiple editors to enforce common coding conventions for specific\n+# file types\n+\n+# top-most EditorConfig file:\n+# Will ignore other EditorConfig files in Home directory or upper tree level.\n+root = true\n+\n+\n+[*] # For All Files\n+# Unix-style newlines with a newline ending every file\n+end_of_line = lf\n+insert_final_newline = true\n+trim_trailing_whitespace = true\n+# Set default charset\n+charset = utf-8\n+# Indent style default\n+indent_style = space\n+# Max Line Length - a hard line wrap, should be disabled\n+max_line_length = off\n+\n+[*.{py,cfg,ini}]\n+# 4 space indentation\n+indent_size = 4\n+\n+[*.{yml,zpt,pt,dtml,zcml}]\n+# 2 space indentation\n+indent_size = 2\n+\n+[{Makefile,.gitmodules}]\n+# Tab indentation (no size specified, but view as 4 spaces)\n+indent_style = tab\n+indent_size = unset\n+tab_width = unset\ndiff --git a/.meta.toml b/.meta.toml\nnew file mode 100644\nindex 0000000..d915ae9\n--- /dev/null\n+++ b/.meta.toml\n@@ -0,0 +1,5 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+[meta]\n+template = "default"\n+commit-id = "3333c742"\ndiff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml\nnew file mode 100644\nindex 0000000..fdafec1\n--- /dev/null\n+++ b/.pre-commit-config.yaml\n@@ -0,0 +1,42 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+ci:\n+ autofix_prs: false\n+ autoupdate_schedule: monthly\n+\n+repos:\n+- repo: https://github.com/asottile/pyupgrade\n+ rev: v3.3.1\n+ hooks:\n+ - id: pyupgrade\n+ args: [--py38-plus]\n+- repo: https://github.com/pycqa/isort\n+ rev: 5.12.0\n+ hooks:\n+ - id: isort\n+- repo: https://github.com/psf/black\n+ rev: 23.3.0\n+ hooks:\n+ - id: black\n+- repo: https://github.com/collective/zpretty\n+ rev: 3.0.3\n+ hooks:\n+ - id: zpretty\n+- repo: https://github.com/PyCQA/flake8\n+ rev: 6.0.0\n+ hooks:\n+ - id: flake8\n+- repo: https://github.com/codespell-project/codespell\n+ rev: v2.2.4\n+ hooks:\n+ - id: codespell\n+ additional_dependencies:\n+ - tomli\n+- repo: https://github.com/mgedmin/check-manifest\n+ rev: "0.49"\n+ hooks:\n+ - id: check-manifest\n+- repo: https://github.com/regebro/pyroma\n+ rev: "4.2"\n+ hooks:\n+ - id: pyroma\ndiff --git a/news/3333c742.internal b/news/3333c742.internal\nnew file mode 100644\nindex 0000000..c08f539\n--- /dev/null\n+++ b/news/3333c742.internal\n@@ -0,0 +1,2 @@\n+Update configuration files.\n+[plone devs]\ndiff --git a/pyproject.toml b/pyproject.toml\nindex 05b615d..9eb73f3 100644\n--- a/pyproject.toml\n+++ b/pyproject.toml\n@@ -1,3 +1,5 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n [tool.towncrier]\n filename = "CHANGES.rst"\n directory = "news/"\n@@ -18,3 +20,43 @@ showcontent = true\n directory = "bugfix"\n name = "Bug fixes:"\n showcontent = true\n+\n+[[tool.towncrier.type]]\n+directory = "internal"\n+name = "Internal:"\n+showcontent = true\n+\n+[[tool.towncrier.type]]\n+directory = "documentation"\n+name = "Documentation:"\n+showcontent = true\n+\n+[[tool.towncrier.type]]\n+directory = "tests"\n+name = "Tests"\n+showcontent = true\n+\n+[tool.isort]\n+profile = "plone"\n+\n+[tool.black]\n+target-version = ["py38"]\n+\n+[tool.dependencychecker]\n+Zope = [\n+ # Zope own provided namespaces\n+ \'App\', \'OFS\', \'Products.Five\', \'Products.OFSP\', \'Products.PageTemplates\',\n+ \'Products.SiteAccess\', \'Shared\', \'Testing\', \'ZPublisher\', \'ZTUtils\',\n+ \'Zope2\', \'webdav\', \'zmi\',\n+ # Zope dependencies\n+ \'Acquisition\', \'DateTime\', \'transaction\', \'zExceptions\', \'ZODB\', \'zope.component\',\n+ \'zope.configuration\', \'zope.container\', \'zope.deferredimport\', \'zope.event\',\n+ \'zope.exceptions\', \'zope.globalrequest\', \'zope.i18n\', \'zope.i18nmessageid\',\n+ \'zope.interface\', \'zope.lifecycleevent\', \'zope.location\', \'zope.publisher\',\n+ \'zope.schema\', \'zope.security\', \'zope.site\', \'zope.traversing\', \'AccessControl\',\n+]\n+\'plone.base\' = [\n+ \'AccessControl\', \'Products.BTreeFolder2\', \'Products.CMFCore\',\n+ \'Products.CMFDynamicViewFTI\', \'zope.deprecation\',\n+]\n+python-dateutil = [\'dateutil\']\ndiff --git a/setup.cfg b/setup.cfg\nindex e6d0f89..0da8f8f 100644\n--- a/setup.cfg\n+++ b/setup.cfg\n@@ -1,8 +1,23 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n [bdist_wheel]\n-universal = 1\n+universal = 0\n+\n+[flake8]\n+doctests = 1\n+ignore =\n+ # black takes care of line length\n+ E501,\n+ # black takes care of where to break lines\n+ W503,\n+ # black takes care of spaces within slicing (list[:])\n+ E203,\n+ # black takes care of spaces after commas\n+ E231,\n \n [check-manifest]\n ignore =\n- buildout.cfg\n- requirements.txt\n+ .editorconfig\n+ .meta.toml\n+ .pre-commit-config.yaml\n tox.ini\ndiff --git a/tox.ini b/tox.ini\nindex e16622e..acb4618 100644\n--- a/tox.ini\n+++ b/tox.ini\n@@ -1,39 +1,68 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n [tox]\n+# We need 4.4.0 for constrain_package_deps.\n+min_version = 4.4.0\n envlist =\n- plone60-py38\n- plone60-py39\n- plone60-py310\n- plone60-py311\n+ format\n+ lint\n+ test\n \n [testenv]\n-commands =\n- cp {toxinidir}/buildout.cfg {envdir}/buildout.cfg\n- sed -ie "s/test-6.0.x.cfg/test-{env:PLONE_VERSION}.x.cfg/" {envdir}/buildout.cfg\n- {envbindir}/buildout -c {envdir}/buildout.cfg buildout:directory={envdir} buildout:develop={toxinidir} install test\n- {envbindir}/test\n+allowlist_externals =\n+ sh\n+\n+[testenv:format]\n+description = automatically reformat code\n skip_install = true\n deps =\n- -rrequirements.txt\n-allowlist_externals =\n- cp\n- sed\n+ pre-commit\n+commands =\n+ pre-commit run -a pyupgrade\n+ pre-commit run -a isort\n+ pre-commit run -a black\n+ pre-commit run -a zpretty\n \n-[testenv:plone60-py38]\n-basepython = python3.8\n-setenv =\n- PLONE_VERSION=6.0\n+[testenv:lint]\n+description = run linters that will help improve the code style\n+skip_install = true\n+deps =\n+ pre-commit\n+commands =\n+ pre-commit run -a\n \n-[testenv:plone60-py39]\n-basepython = python3.9\n-setenv =\n- PLONE_VERSION=6.0\n+[testenv:dependencies]\n+description = check if the package defines all its dependencies and generate a graph out of them\n+deps =\n+ z3c.dependencychecker==2.11\n+ pipdeptree==2.5.1\n+ graphviz # optional dependency of pipdeptree\n+commands =\n+ dependencychecker\n+ sh -c \'pipdeptree --exclude setuptools,wheel,pipdeptree,z3c.dependencychecker,zope.interface,zope.component --graph-output svg > dependencies.svg\'\n \n-[testenv:plone60-py310]\n-basepython = python3.10\n-setenv =\n- PLONE_VERSION=6.0\n+[testenv:test]\n+usedevelop = true\n+constrain_package_deps = true\n+set_env = ROBOT_BROWSER=headlesschrome\n+deps =\n+ zope.testrunner\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+commands =\n+ zope-testrunner --all --test-path={toxinidir} -s Products.isurlinportal {posargs}\n+extras =\n+ test\n \n-[testenv:plone60-py311]\n-basepython = python3.11\n-setenv =\n- PLONE_VERSION=6.0\n+[testenv:coverage]\n+usedevelop = true\n+constrain_package_deps = true\n+set_env = ROBOT_BROWSER=headlesschrome\n+deps =\n+ coverage\n+ zope.testrunner\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+commands =\n+ coverage run {envbindir}/zope-testrunner --all --test-path={toxinidir} -s Products.isurlinportal {posargs}\n+ coverage report -m --format markdown\n+extras =\n+ test\n' - -Repository: Products.isurlinportal +Date: 2023-04-14T19:04:08+02:00 +Author: Maurits van Rees (mauritsvanrees) +Commit: https://github.com/plone/Products.CMFPlone/commit/7a5d9ad660e51b7bb0e4a289fbdbd9777e163539 +Clear the resource viewlet cache when changing the resource registry or activating an add-on. -Branch: refs/heads/master -Date: 2023-04-09T14:49:09+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/Products.isurlinportal/commit/ac0b360fb8dc96eccd545b0bc5ac030f99fc6021 - -cleanup: use generic workflow +This avoids needing a restart before seeing changes when you run in production mode. +Fixes [issue 3505](https://github.com/plone/Products.CMFPlone/issues/3505). Files changed: -D .github/workflows/tests.yml -D buildout.cfg -D requirements.txt +A Products/CMFPlone/resources/eventhandlers.py +A news/3505.bugfix +M Products/CMFPlone/controlpanel/browser/resourceregistry.py +M Products/CMFPlone/resources/browser/resource.py +M Products/CMFPlone/resources/configure.zcml -b'diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml\ndeleted file mode 100644\nindex 720ef8c..0000000\n--- a/.github/workflows/tests.yml\n+++ /dev/null\n@@ -1,54 +0,0 @@\n-name: tests\n-\n-on:\n- push:\n- branches: [ master ]\n- pull_request:\n- workflow_dispatch:\n-\n-jobs:\n- build:\n- strategy:\n- matrix:\n- config:\n- # [Python version, tox env]\n- - ["3.8", "plone60-py38"]\n- - ["3.9", "plone60-py39"]\n- - ["3.10", "plone60-py310"]\n- - ["3.11", "plone60-py311"]\n-\n- runs-on: ubuntu-latest\n- name: ${{ matrix.config[1] }}\n- steps:\n- - uses: actions/checkout@v3\n- - name: Set up Python\n- uses: actions/setup-python@v3\n- with:\n- python-version: ${{ matrix.config[0] }}\n- - name: Pip cache\n- uses: actions/cache@v3\n- with:\n- path: ~/.cache/pip\n- key: ${{ runner.os }}-pip-${{ matrix.config[0] }}-${{ hashFiles(\'setup.*\', \'tox.ini\') }}\n- restore-keys: |\n- ${{ runner.os }}-pip-${{ matrix.config[0] }}-\n- ${{ runner.os }}-pip-\n- - name: Buildout cache\n- uses: actions/cache@v3\n- with:\n- path: ~/.buildout/eggs\n- key: ${{ runner.os }}-buildout-${{ matrix.config[1] }}-${{ hashFiles(\'setup.*\', \'tox.ini\', \'*cfg\') }}\n- restore-keys: |\n- ${{ runner.os }}-buildout-${{ matrix.config[1] }}-\n- ${{ runner.os }}-buildout-\n- - name: Setup Buildout to cache eggs\n- run: |\n- mkdir -p ~/.buildout/eggs\n- echo "[buildout]" > ~/.buildout/default.cfg\n- echo "eggs-directory = $(realpath ~/.buildout/eggs)" >> ~/.buildout/default.cfg\n- - name: Install dependencies\n- run: |\n- python -m pip install --upgrade pip\n- pip install tox\n- - name: Test\n- run: tox -e ${{ matrix.config[1] }}\ndiff --git a/buildout.cfg b/buildout.cfg\ndeleted file mode 100644\nindex 800a083..0000000\n--- a/buildout.cfg\n+++ /dev/null\n@@ -1,13 +0,0 @@\n-[buildout]\n-extends =\n- https://github.com/raw/collective/buildout.plonetest/master/test-6.0.x.cfg\n-\n-package-name = Products.isurlinportal\n-\n-[versions]\n-pip =\n-setuptools =\n-wheel =\n-zc.buildout =\n-# Use development version:\n-Products.isurlinportal =\ndiff --git a/requirements.txt b/requirements.txt\ndeleted file mode 100644\nindex eed370c..0000000\n--- a/requirements.txt\n+++ /dev/null\n@@ -1,4 +0,0 @@\n-pip==22.3.1\n-setuptools==65.7.0\n-wheel==0.38.4\n-zc.buildout==3.0.1\n' +b'diff --git a/Products/CMFPlone/controlpanel/browser/resourceregistry.py b/Products/CMFPlone/controlpanel/browser/resourceregistry.py\nindex e097435ad7..eebcedd0b1 100644\n--- a/Products/CMFPlone/controlpanel/browser/resourceregistry.py\n+++ b/Products/CMFPlone/controlpanel/browser/resourceregistry.py\n@@ -2,6 +2,7 @@\n from plone.base import PloneMessageFactory as _\n from plone.base.interfaces import IBundleRegistry\n from plone.registry.interfaces import IRegistry\n+from Products.CMFPlone.resources.browser.resource import clear_resource_viewlet_caches\n from Products.Five.browser import BrowserView\n from Products.statusmessages.interfaces import IStatusMessage\n from zope.component import getUtility\n@@ -149,4 +150,5 @@ def process_form(self):\n self._switch_cache(False)\n else:\n raise ValueError("Invalid form data")\n+ clear_resource_viewlet_caches()\n self.request.response.redirect(self.request["ACTUAL_URL"])\ndiff --git a/Products/CMFPlone/resources/browser/resource.py b/Products/CMFPlone/resources/browser/resource.py\nindex c07f71f20a..57654a740a 100644\n--- a/Products/CMFPlone/resources/browser/resource.py\n+++ b/Products/CMFPlone/resources/browser/resource.py\n@@ -19,7 +19,7 @@\n logger = logging.getLogger(__name__)\n \n REQUEST_CACHE_KEY = "_WEBRESOURCE_CACHE_"\n-\n+SITE_ROOT_CACHE_KEY_PREFIX = "_v_rendered_cache_"\n GRACEFUL_DEPENDENCY_REWRITE = {\n "plone-base": "plone",\n "plone-legacy": "plone",\n@@ -59,7 +59,7 @@ def _cache_attr_name(self, site):\n for bundle in e_bundles | d_bundles:\n hashtool.update(bundle.encode(\'utf8\'))\n hashtool.update(self._user_local_roles(site).encode("utf8"))\n- return f"_v_renderend_cache_{hashtool.hexdigest()}"\n+ return f"{SITE_ROOT_CACHE_KEY_PREFIX}{hashtool.hexdigest()}"\n \n @property\n def _rendered_cache(self):\n@@ -313,3 +313,26 @@ def index(self):\n rendered = self.renderer["css"].render()\n self._rendered_cache = rendered\n return rendered\n+\n+\n+def clear_resource_viewlet_caches():\n+ """Remove volatile cache of resource viewlets.\n+\n+ See discussion in https://github.com/plone/Products.CMFPlone/issues/3505\n+ """\n+ site = getSite()\n+\n+ # I don\'t trust removing keys from a dict when iterating over this dict,\n+ # so gather them in a list first.\n+ to_remove = [\n+ name for name in site.__dict__\n+ if name.startswith(SITE_ROOT_CACHE_KEY_PREFIX)\n+ ]\n+ for name in to_remove:\n+ # The attribute is volatile, meaning it may disappear at any time,\n+ # so we catch errors.\n+ try:\n+ delattr(site, name)\n+ except AttributeError:\n+ pass\n+ logger.info("Cleared resource viewlet caches.")\ndiff --git a/Products/CMFPlone/resources/configure.zcml b/Products/CMFPlone/resources/configure.zcml\nindex 0bec1224e4..faf47d627e 100644\n--- a/Products/CMFPlone/resources/configure.zcml\n+++ b/Products/CMFPlone/resources/configure.zcml\n@@ -3,5 +3,6 @@\n i18n_domain="plone.registry">\n \n \n+ \n \n \ndiff --git a/Products/CMFPlone/resources/eventhandlers.py b/Products/CMFPlone/resources/eventhandlers.py\nnew file mode 100644\nindex 0000000000..4bd76de4ba\n--- /dev/null\n+++ b/Products/CMFPlone/resources/eventhandlers.py\n@@ -0,0 +1,16 @@\n+from Products.CMFPlone.resources.browser.resource import clear_resource_viewlet_caches\n+from Products.GenericSetup.interfaces import IProfileImportedEvent\n+from zope.component import adapter\n+\n+\n+@adapter(IProfileImportedEvent)\n+def check_registry_update(event):\n+ """Check if a profile import may have updated the configuration registry.\n+\n+ Main concern for now is: the resource registries may have changed.\n+ This means the resource viewlet caches should be cleared.\n+ See discussion in https://github.com/plone/Products.CMFPlone/issues/3505\n+ """\n+ if not (event.full_import or "plone.app.registry" in event.steps):\n+ return\n+ clear_resource_viewlet_caches()\ndiff --git a/news/3505.bugfix b/news/3505.bugfix\nnew file mode 100644\nindex 0000000000..da1ed7a2c3\n--- /dev/null\n+++ b/news/3505.bugfix\n@@ -0,0 +1,4 @@\n+Clear the resource viewlet cache when changing the resource registry or activating an add-on.\n+This avoids needing a restart before seeing changes when you run in production mode.\n+Fixes [issue 3505](https://github.com/plone/Products.CMFPlone/issues/3505).\n+[maurits]\n' -Repository: Products.isurlinportal +Repository: Products.CMFPlone Branch: refs/heads/master -Date: 2023-04-09T14:49:52+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/Products.isurlinportal/commit/4d6a41d5ed83671f658bb1c708ea54b5e1dcb34f - -chore: isort - -Files changed: -M Products/isurlinportal/__init__.py - -b'diff --git a/Products/isurlinportal/__init__.py b/Products/isurlinportal/__init__.py\nindex 768497d..8c935ee 100644\n--- a/Products/isurlinportal/__init__.py\n+++ b/Products/isurlinportal/__init__.py\n@@ -2,6 +2,7 @@\n from plone.base.interfaces import ILoginSchema\n from plone.registry.interfaces import IRegistry\n from posixpath import normpath\n+\n # This is the class we will patch:\n from Products.CMFPlone.URLTool import URLTool\n from urllib.parse import urljoin\n' - -Repository: Products.isurlinportal - +Date: 2023-04-17T23:52:45+02:00 +Author: Maurits van Rees (mauritsvanrees) +Commit: https://github.com/plone/Products.CMFPlone/commit/58b1d5f867a7fb4c565d8757430641930546659b -Branch: refs/heads/master -Date: 2023-04-09T14:50:55+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/Products.isurlinportal/commit/7b447af53bbb446e19da998fc08330537bada58e +Add a last modification time of the resource registry. -feat: configure codespell +We update this when changing anything related: when changing the resource registry in its control panel or activating an add-on. +This avoids needing a restart before seeing changes when you run in production mode. Files changed: -M pyproject.toml +M Products/CMFPlone/controlpanel/browser/resourceregistry.py +M Products/CMFPlone/resources/browser/resource.py +M Products/CMFPlone/resources/eventhandlers.py +M news/3505.bugfix -b'diff --git a/pyproject.toml b/pyproject.toml\nindex 9eb73f3..78ab968 100644\n--- a/pyproject.toml\n+++ b/pyproject.toml\n@@ -60,3 +60,6 @@ Zope = [\n \'Products.CMFDynamicViewFTI\', \'zope.deprecation\',\n ]\n python-dateutil = [\'dateutil\']\n+\n+[tool.codespell]\n+ignore-words-list = "noo"\n' +b'diff --git a/Products/CMFPlone/controlpanel/browser/resourceregistry.py b/Products/CMFPlone/controlpanel/browser/resourceregistry.py\nindex eebcedd0b1..4277e9d221 100644\n--- a/Products/CMFPlone/controlpanel/browser/resourceregistry.py\n+++ b/Products/CMFPlone/controlpanel/browser/resourceregistry.py\n@@ -2,7 +2,7 @@\n from plone.base import PloneMessageFactory as _\n from plone.base.interfaces import IBundleRegistry\n from plone.registry.interfaces import IRegistry\n-from Products.CMFPlone.resources.browser.resource import clear_resource_viewlet_caches\n+from Products.CMFPlone.resources.browser.resource import update_resource_registry_mtime\n from Products.Five.browser import BrowserView\n from Products.statusmessages.interfaces import IStatusMessage\n from zope.component import getUtility\n@@ -150,5 +150,5 @@ def process_form(self):\n self._switch_cache(False)\n else:\n raise ValueError("Invalid form data")\n- clear_resource_viewlet_caches()\n+ update_resource_registry_mtime()\n self.request.response.redirect(self.request["ACTUAL_URL"])\ndiff --git a/Products/CMFPlone/resources/browser/resource.py b/Products/CMFPlone/resources/browser/resource.py\nindex 57654a740a..685a325eae 100644\n--- a/Products/CMFPlone/resources/browser/resource.py\n+++ b/Products/CMFPlone/resources/browser/resource.py\n@@ -7,6 +7,7 @@\n from plone.base.interfaces import IBundleRegistry\n from plone.registry.interfaces import IRegistry\n from Products.CMFCore.utils import getToolByName\n+from time import time\n from zope.component import getMultiAdapter\n from zope.component import getUtility\n from zope.component.hooks import getSite\n@@ -19,7 +20,7 @@\n logger = logging.getLogger(__name__)\n \n REQUEST_CACHE_KEY = "_WEBRESOURCE_CACHE_"\n-SITE_ROOT_CACHE_KEY_PREFIX = "_v_rendered_cache_"\n+_RESOURCE_REGISTRY_MTIME = "__RESOURCE_REGISTRY_MTIME"\n GRACEFUL_DEPENDENCY_REWRITE = {\n "plone-base": "plone",\n "plone-legacy": "plone",\n@@ -59,7 +60,12 @@ def _cache_attr_name(self, site):\n for bundle in e_bundles | d_bundles:\n hashtool.update(bundle.encode(\'utf8\'))\n hashtool.update(self._user_local_roles(site).encode("utf8"))\n- return f"{SITE_ROOT_CACHE_KEY_PREFIX}{hashtool.hexdigest()}"\n+ if not getattr(self, "registry", None):\n+ self.registry = getUtility(IRegistry)\n+ mtime = getattr(self.registry, _RESOURCE_REGISTRY_MTIME, None)\n+ if mtime is not None:\n+ hashtool.update(str(mtime).encode(\'utf8\'))\n+ return f"_v_rendered_cache_{hashtool.hexdigest()}"\n \n @property\n def _rendered_cache(self):\n@@ -315,24 +321,14 @@ def index(self):\n return rendered\n \n \n-def clear_resource_viewlet_caches():\n- """Remove volatile cache of resource viewlets.\n+def update_resource_registry_mtime():\n+ """Update the last modification time of the resource registry.\n \n+ Call this when you change anything that may influence the resource registry\n+ and any of its rendered cache.\n See discussion in https://github.com/plone/Products.CMFPlone/issues/3505\n+ and https://github.com/plone/Products.CMFPlone/pull/3771\n """\n- site = getSite()\n-\n- # I don\'t trust removing keys from a dict when iterating over this dict,\n- # so gather them in a list first.\n- to_remove = [\n- name for name in site.__dict__\n- if name.startswith(SITE_ROOT_CACHE_KEY_PREFIX)\n- ]\n- for name in to_remove:\n- # The attribute is volatile, meaning it may disappear at any time,\n- # so we catch errors.\n- try:\n- delattr(site, name)\n- except AttributeError:\n- pass\n- logger.info("Cleared resource viewlet caches.")\n+ registry = getUtility(IRegistry)\n+ setattr(registry, _RESOURCE_REGISTRY_MTIME, time())\n+ logger.info("Updated resource registry mtime.")\ndiff --git a/Products/CMFPlone/resources/eventhandlers.py b/Products/CMFPlone/resources/eventhandlers.py\nindex 4bd76de4ba..dae5a5ba7f 100644\n--- a/Products/CMFPlone/resources/eventhandlers.py\n+++ b/Products/CMFPlone/resources/eventhandlers.py\n@@ -1,4 +1,4 @@\n-from Products.CMFPlone.resources.browser.resource import clear_resource_viewlet_caches\n+from Products.CMFPlone.resources.browser.resource import update_resource_registry_mtime\n from Products.GenericSetup.interfaces import IProfileImportedEvent\n from zope.component import adapter\n \n@@ -13,4 +13,4 @@ def check_registry_update(event):\n """\n if not (event.full_import or "plone.app.registry" in event.steps):\n return\n- clear_resource_viewlet_caches()\n+ update_resource_registry_mtime()\ndiff --git a/news/3505.bugfix b/news/3505.bugfix\nindex da1ed7a2c3..5cb726e238 100644\n--- a/news/3505.bugfix\n+++ b/news/3505.bugfix\n@@ -1,4 +1,5 @@\n-Clear the resource viewlet cache when changing the resource registry or activating an add-on.\n+Add a last modification time of the resource registry.\n+We update this when changing anything related: when changing the resource registry in its control panel or activating an add-on.\n This avoids needing a restart before seeing changes when you run in production mode.\n Fixes [issue 3505](https://github.com/plone/Products.CMFPlone/issues/3505).\n [maurits]\n' -Repository: Products.isurlinportal +Repository: Products.CMFPlone Branch: refs/heads/master -Date: 2023-04-09T14:55:18+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/Products.isurlinportal/commit/0fa32d4060c66a5e7c44b3215d2ade0251a18fc6 - -feat: declare dependencies - -Files changed: -M setup.py - -b'diff --git a/setup.py b/setup.py\nindex 25d2a74..30d4f03 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -36,5 +36,10 @@\n include_package_data=True,\n zip_safe=False,\n python_requires=">=3.8",\n- install_requires=["setuptools"],\n+ install_requires=[\n+ "Products.CMFPlone",\n+ "setuptools",\n+ "plone.base",\n+ "plone.registry",\n+ ],\n )\n' - -Repository: Products.isurlinportal - +Date: 2023-04-18T00:04:02+02:00 +Author: Maurits van Rees (mauritsvanrees) +Commit: https://github.com/plone/Products.CMFPlone/commit/440da1c1ab3d0cb3de3f8c040b6cb486eb883b44 -Branch: refs/heads/master -Date: 2023-04-13T16:11:17+02:00 -Author: Gil Forcada Codinachs (gforcada) -Commit: https://github.com/plone/Products.isurlinportal/commit/d8d161f25f8693309996e3a6a6bea39576e96e7f +Changes in resource settings ARE applied directly, also in production mode. -Random change to trigger GHA +So remove this from the status message that you see on the resource registry control panel. Files changed: -M tox.ini +M Products/CMFPlone/controlpanel/browser/resourceregistry.pt -b'diff --git a/tox.ini b/tox.ini\nindex acb4618..9c8d6e9 100644\n--- a/tox.ini\n+++ b/tox.ini\n@@ -20,8 +20,8 @@ deps =\n commands =\n pre-commit run -a pyupgrade\n pre-commit run -a isort\n- pre-commit run -a black\n pre-commit run -a zpretty\n+ pre-commit run -a black\n \n [testenv:lint]\n description = run linters that will help improve the code style\n' +b'diff --git a/Products/CMFPlone/controlpanel/browser/resourceregistry.pt b/Products/CMFPlone/controlpanel/browser/resourceregistry.pt\nindex 071d03817f..4279bdb02b 100644\n--- a/Products/CMFPlone/controlpanel/browser/resourceregistry.pt\n+++ b/Products/CMFPlone/controlpanel/browser/resourceregistry.pt\n@@ -68,7 +68,6 @@\n \n Resources are fast and hashes are cached in Plone.\n- Changes in resource settings are not applied directly.\n \n \n \n' -Repository: Products.isurlinportal +Repository: Products.CMFPlone Branch: refs/heads/master -Date: 2023-04-18T00:17:11+02:00 +Date: 2023-04-18T00:04:41+02:00 Author: Maurits van Rees (mauritsvanrees) -Commit: https://github.com/plone/Products.isurlinportal/commit/0e3b7d0b8a7d6242edd93d29fe6a216c1e3f1f42 +Commit: https://github.com/plone/Products.CMFPlone/commit/1575a6ab664492be470bfde988850fe174f74edf -Configuring with plone/meta +Merge branch 'master' into maurits-clear-resource-viewlet-caches Files changed: -M .meta.toml -M pyproject.toml -M tox.ini +A news/3753.bugfix +M Products/CMFPlone/browser/search.py -b'diff --git a/.meta.toml b/.meta.toml\nindex d915ae9..c510cbe 100644\n--- a/.meta.toml\n+++ b/.meta.toml\n@@ -2,4 +2,7 @@\n # https://github.com/plone/meta/tree/master/config/default\n [meta]\n template = "default"\n-commit-id = "3333c742"\n+commit-id = "d7d930a5"\n+\n+[codespell]\n+additional-ignores = "noo"\ndiff --git a/pyproject.toml b/pyproject.toml\nindex 78ab968..4bfea99 100644\n--- a/pyproject.toml\n+++ b/pyproject.toml\n@@ -42,24 +42,45 @@ profile = "plone"\n [tool.black]\n target-version = ["py38"]\n \n+[tool.codespell]\n+ignore-words-list = "noo"\n+\n [tool.dependencychecker]\n Zope = [\n # Zope own provided namespaces\n \'App\', \'OFS\', \'Products.Five\', \'Products.OFSP\', \'Products.PageTemplates\',\n \'Products.SiteAccess\', \'Shared\', \'Testing\', \'ZPublisher\', \'ZTUtils\',\n \'Zope2\', \'webdav\', \'zmi\',\n+ # ExtensionClass own provided namespaces\n+ \'ExtensionClass\', \'ComputedAttribute\', \'MethodObject\',\n # Zope dependencies\n- \'Acquisition\', \'DateTime\', \'transaction\', \'zExceptions\', \'ZODB\', \'zope.component\',\n- \'zope.configuration\', \'zope.container\', \'zope.deferredimport\', \'zope.event\',\n- \'zope.exceptions\', \'zope.globalrequest\', \'zope.i18n\', \'zope.i18nmessageid\',\n- \'zope.interface\', \'zope.lifecycleevent\', \'zope.location\', \'zope.publisher\',\n- \'zope.schema\', \'zope.security\', \'zope.site\', \'zope.traversing\', \'AccessControl\',\n+ \'AccessControl\', \'Acquisition\', \'AuthEncoding\', \'beautifulsoup4\', \'BTrees\',\n+ \'cffi\', \'Chameleon\', \'DateTime\', \'DocumentTemplate\',\n+ \'MultiMapping\', \'multipart\', \'PasteDeploy\', \'Persistence\', \'persistent\',\n+ \'pycparser\', \'python-gettext\', \'pytz\', \'RestrictedPython\', \'roman\',\n+ \'soupsieve\', \'transaction\', \'waitress\', \'WebOb\', \'WebTest\', \'WSGIProxy2\',\n+ \'z3c.pt\', \'zc.lockfile\', \'ZConfig\', \'zExceptions\', \'ZODB\', \'zodbpickle\',\n+ \'zope.annotation\', \'zope.browser\', \'zope.browsermenu\', \'zope.browserpage\',\n+ \'zope.browserresource\', \'zope.cachedescriptors\', \'zope.component\',\n+ \'zope.configuration\', \'zope.container\', \'zope.contentprovider\',\n+ \'zope.contenttype\', \'zope.datetime\', \'zope.deferredimport\',\n+ \'zope.deprecation\', \'zope.dottedname\', \'zope.event\', \'zope.exceptions\',\n+ \'zope.filerepresentation\', \'zope.globalrequest\', \'zope.hookable\',\n+ \'zope.i18n\', \'zope.i18nmessageid\', \'zope.interface\', \'zope.lifecycleevent\',\n+ \'zope.location\', \'zope.pagetemplate\', \'zope.processlifetime\', \'zope.proxy\',\n+ \'zope.ptresource\', \'zope.publisher\', \'zope.schema\', \'zope.security\',\n+ \'zope.sequencesort\', \'zope.site\', \'zope.size\', \'zope.structuredtext\',\n+ \'zope.tal\', \'zope.tales\', \'zope.testbrowser\', \'zope.testing\',\n+ \'zope.traversing\', \'zope.viewlet\'\n+]\n+\'Products.CMFCore\' = [\n+ \'docutils\', \'five.localsitemanager\', \'Missing\', \'Products.BTreeFolder2\',\n+ \'Products.GenericSetup\', \'Products.MailHost\', \'Products.PythonScripts\',\n+ \'Products.StandardCacheManagers\', \'Products.ZCatalog\', \'Record\',\n+ \'zope.sendmail\', \'Zope\'\n ]\n \'plone.base\' = [\n- \'AccessControl\', \'Products.BTreeFolder2\', \'Products.CMFCore\',\n- \'Products.CMFDynamicViewFTI\', \'zope.deprecation\',\n+ \'plone.batching\', \'plone.registry\', \'plone.schema\',\'plone.z3cform\',\n+ \'Products.CMFCore\', \'Products.CMFDynamicViewFTI\',\n ]\n python-dateutil = [\'dateutil\']\n-\n-[tool.codespell]\n-ignore-words-list = "noo"\ndiff --git a/tox.ini b/tox.ini\nindex 9c8d6e9..acb4618 100644\n--- a/tox.ini\n+++ b/tox.ini\n@@ -20,8 +20,8 @@ deps =\n commands =\n pre-commit run -a pyupgrade\n pre-commit run -a isort\n- pre-commit run -a zpretty\n pre-commit run -a black\n+ pre-commit run -a zpretty\n \n [testenv:lint]\n description = run linters that will help improve the code style\n' +b"diff --git a/Products/CMFPlone/browser/search.py b/Products/CMFPlone/browser/search.py\nindex 4d3e25cd2d..902d052720 100644\n--- a/Products/CMFPlone/browser/search.py\n+++ b/Products/CMFPlone/browser/search.py\n@@ -2,6 +2,7 @@\n from plone.app.contentlisting.interfaces import IContentListing\n from plone.app.layout.navigation.interfaces import INavigationRoot\n from plone.base.batch import Batch\n+from plone.base.interfaces.siteroot import IPloneSiteRoot\n from plone.base.interfaces import ISearchSchema\n from plone.registry.interfaces import IRegistry\n from Products.CMFCore.utils import getToolByName\n@@ -142,8 +143,8 @@ def _filter_query(self, query):\n query['portal_type'] = self.filter_types(types)\n # respect effective/expiration date\n query['show_inactive'] = False\n- # respect navigation root\n- if 'path' not in query:\n+ # respect navigation root if we're not at the site root.\n+ if 'path' not in query and not IPloneSiteRoot.providedBy(self.context):\n query['path'] = getNavigationRoot(self.context)\n \n if 'sort_order' in query and not query['sort_order']:\ndiff --git a/news/3753.bugfix b/news/3753.bugfix\nnew file mode 100644\nindex 0000000000..3069245b55\n--- /dev/null\n+++ b/news/3753.bugfix\n@@ -0,0 +1,2 @@\n+Removed path query from search view when context is site root.\n+[malthe]\n" -Repository: Products.isurlinportal +Repository: Products.CMFPlone Branch: refs/heads/master -Date: 2023-04-18T00:21:25+02:00 +Date: 2023-04-18T14:43:05+02:00 Author: Maurits van Rees (mauritsvanrees) -Commit: https://github.com/plone/Products.isurlinportal/commit/418de5a26190b4f5e723a5e6b296fd2be5bed9a9 +Commit: https://github.com/plone/Products.CMFPlone/commit/32db13272a5345ce19a35440587a990ae4015497 -Moved Products.CMFPlone to requirements in new test extra. +Registry utility may not exist, especially at site creation time. Files changed: -M .meta.toml -M pyproject.toml -M setup.py +M Products/CMFPlone/resources/browser/resource.py -b'diff --git a/.meta.toml b/.meta.toml\nindex c510cbe..473f4ed 100644\n--- a/.meta.toml\n+++ b/.meta.toml\n@@ -4,5 +4,8 @@\n template = "default"\n commit-id = "d7d930a5"\n \n+[dependencies]\n+ignores = "[\'Products.CMFPlone\']"\n+\n [codespell]\n additional-ignores = "noo"\ndiff --git a/pyproject.toml b/pyproject.toml\nindex 4bfea99..a2bcbed 100644\n--- a/pyproject.toml\n+++ b/pyproject.toml\n@@ -84,3 +84,4 @@ Zope = [\n \'Products.CMFCore\', \'Products.CMFDynamicViewFTI\',\n ]\n python-dateutil = [\'dateutil\']\n+ignore-packages = [\'Products.CMFPlone\']\ndiff --git a/setup.py b/setup.py\nindex 30d4f03..64e388b 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -37,9 +37,12 @@\n zip_safe=False,\n python_requires=">=3.8",\n install_requires=[\n- "Products.CMFPlone",\n "setuptools",\n "plone.base",\n- "plone.registry",\n ],\n+ extras_require={\n+ "test": [\n+ "Products.CMFPlone",\n+ ]\n+ },\n )\n' +b'diff --git a/Products/CMFPlone/resources/browser/resource.py b/Products/CMFPlone/resources/browser/resource.py\nindex 685a325eae..07369c6176 100644\n--- a/Products/CMFPlone/resources/browser/resource.py\n+++ b/Products/CMFPlone/resources/browser/resource.py\n@@ -10,6 +10,7 @@\n from time import time\n from zope.component import getMultiAdapter\n from zope.component import getUtility\n+from zope.component import queryUtility\n from zope.component.hooks import getSite\n \n import hashlib\n@@ -329,6 +330,9 @@ def update_resource_registry_mtime():\n See discussion in https://github.com/plone/Products.CMFPlone/issues/3505\n and https://github.com/plone/Products.CMFPlone/pull/3771\n """\n- registry = getUtility(IRegistry)\n+ registry = queryUtility(IRegistry)\n+ if registry is None:\n+ # This can happen for example during site creation.\n+ return\n setattr(registry, _RESOURCE_REGISTRY_MTIME, time())\n logger.info("Updated resource registry mtime.")\n' -Repository: Products.isurlinportal +Repository: Products.CMFPlone Branch: refs/heads/master -Date: 2023-04-18T14:32:37+02:00 -Author: Maurits van Rees (mauritsvanrees) -Commit: https://github.com/plone/Products.isurlinportal/commit/8da42cac4248d61c68bb8eddc91189817eb42bc0 +Date: 2023-04-18T16:28:51+02:00 +Author: Jens W. Klein (jensens) +Commit: https://github.com/plone/Products.CMFPlone/commit/9c2e5191ff78ab6001391a38583a0b9d10fa30bf -Merge pull request #11 from plone/config-with-default-template-79b64ed3 +Merge pull request #3771 from plone/maurits-clear-resource-viewlet-caches -Config with default template +Clear the resource viewlet cache on relevant changes Files changed: -A .editorconfig -A .meta.toml -A .pre-commit-config.yaml -A news/3333c742.internal -M Products/isurlinportal/__init__.py -M pyproject.toml -M setup.cfg -M setup.py -M tox.ini -D .github/workflows/tests.yml -D buildout.cfg -D requirements.txt - -b'diff --git a/.editorconfig b/.editorconfig\nnew file mode 100644\nindex 0000000..b4158b8\n--- /dev/null\n+++ b/.editorconfig\n@@ -0,0 +1,39 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+#\n+# EditorConfig Configuration file, for more details see:\n+# http://EditorConfig.org\n+# EditorConfig is a convention description, that could be interpreted\n+# by multiple editors to enforce common coding conventions for specific\n+# file types\n+\n+# top-most EditorConfig file:\n+# Will ignore other EditorConfig files in Home directory or upper tree level.\n+root = true\n+\n+\n+[*] # For All Files\n+# Unix-style newlines with a newline ending every file\n+end_of_line = lf\n+insert_final_newline = true\n+trim_trailing_whitespace = true\n+# Set default charset\n+charset = utf-8\n+# Indent style default\n+indent_style = space\n+# Max Line Length - a hard line wrap, should be disabled\n+max_line_length = off\n+\n+[*.{py,cfg,ini}]\n+# 4 space indentation\n+indent_size = 4\n+\n+[*.{yml,zpt,pt,dtml,zcml}]\n+# 2 space indentation\n+indent_size = 2\n+\n+[{Makefile,.gitmodules}]\n+# Tab indentation (no size specified, but view as 4 spaces)\n+indent_style = tab\n+indent_size = unset\n+tab_width = unset\ndiff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml\ndeleted file mode 100644\nindex 720ef8c..0000000\n--- a/.github/workflows/tests.yml\n+++ /dev/null\n@@ -1,54 +0,0 @@\n-name: tests\n-\n-on:\n- push:\n- branches: [ master ]\n- pull_request:\n- workflow_dispatch:\n-\n-jobs:\n- build:\n- strategy:\n- matrix:\n- config:\n- # [Python version, tox env]\n- - ["3.8", "plone60-py38"]\n- - ["3.9", "plone60-py39"]\n- - ["3.10", "plone60-py310"]\n- - ["3.11", "plone60-py311"]\n-\n- runs-on: ubuntu-latest\n- name: ${{ matrix.config[1] }}\n- steps:\n- - uses: actions/checkout@v3\n- - name: Set up Python\n- uses: actions/setup-python@v3\n- with:\n- python-version: ${{ matrix.config[0] }}\n- - name: Pip cache\n- uses: actions/cache@v3\n- with:\n- path: ~/.cache/pip\n- key: ${{ runner.os }}-pip-${{ matrix.config[0] }}-${{ hashFiles(\'setup.*\', \'tox.ini\') }}\n- restore-keys: |\n- ${{ runner.os }}-pip-${{ matrix.config[0] }}-\n- ${{ runner.os }}-pip-\n- - name: Buildout cache\n- uses: actions/cache@v3\n- with:\n- path: ~/.buildout/eggs\n- key: ${{ runner.os }}-buildout-${{ matrix.config[1] }}-${{ hashFiles(\'setup.*\', \'tox.ini\', \'*cfg\') }}\n- restore-keys: |\n- ${{ runner.os }}-buildout-${{ matrix.config[1] }}-\n- ${{ runner.os }}-buildout-\n- - name: Setup Buildout to cache eggs\n- run: |\n- mkdir -p ~/.buildout/eggs\n- echo "[buildout]" > ~/.buildout/default.cfg\n- echo "eggs-directory = $(realpath ~/.buildout/eggs)" >> ~/.buildout/default.cfg\n- - name: Install dependencies\n- run: |\n- python -m pip install --upgrade pip\n- pip install tox\n- - name: Test\n- run: tox -e ${{ matrix.config[1] }}\ndiff --git a/.meta.toml b/.meta.toml\nnew file mode 100644\nindex 0000000..473f4ed\n--- /dev/null\n+++ b/.meta.toml\n@@ -0,0 +1,11 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+[meta]\n+template = "default"\n+commit-id = "d7d930a5"\n+\n+[dependencies]\n+ignores = "[\'Products.CMFPlone\']"\n+\n+[codespell]\n+additional-ignores = "noo"\ndiff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml\nnew file mode 100644\nindex 0000000..fdafec1\n--- /dev/null\n+++ b/.pre-commit-config.yaml\n@@ -0,0 +1,42 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n+ci:\n+ autofix_prs: false\n+ autoupdate_schedule: monthly\n+\n+repos:\n+- repo: https://github.com/asottile/pyupgrade\n+ rev: v3.3.1\n+ hooks:\n+ - id: pyupgrade\n+ args: [--py38-plus]\n+- repo: https://github.com/pycqa/isort\n+ rev: 5.12.0\n+ hooks:\n+ - id: isort\n+- repo: https://github.com/psf/black\n+ rev: 23.3.0\n+ hooks:\n+ - id: black\n+- repo: https://github.com/collective/zpretty\n+ rev: 3.0.3\n+ hooks:\n+ - id: zpretty\n+- repo: https://github.com/PyCQA/flake8\n+ rev: 6.0.0\n+ hooks:\n+ - id: flake8\n+- repo: https://github.com/codespell-project/codespell\n+ rev: v2.2.4\n+ hooks:\n+ - id: codespell\n+ additional_dependencies:\n+ - tomli\n+- repo: https://github.com/mgedmin/check-manifest\n+ rev: "0.49"\n+ hooks:\n+ - id: check-manifest\n+- repo: https://github.com/regebro/pyroma\n+ rev: "4.2"\n+ hooks:\n+ - id: pyroma\ndiff --git a/Products/isurlinportal/__init__.py b/Products/isurlinportal/__init__.py\nindex 768497d..8c935ee 100644\n--- a/Products/isurlinportal/__init__.py\n+++ b/Products/isurlinportal/__init__.py\n@@ -2,6 +2,7 @@\n from plone.base.interfaces import ILoginSchema\n from plone.registry.interfaces import IRegistry\n from posixpath import normpath\n+\n # This is the class we will patch:\n from Products.CMFPlone.URLTool import URLTool\n from urllib.parse import urljoin\ndiff --git a/buildout.cfg b/buildout.cfg\ndeleted file mode 100644\nindex 800a083..0000000\n--- a/buildout.cfg\n+++ /dev/null\n@@ -1,13 +0,0 @@\n-[buildout]\n-extends =\n- https://github.com/raw/collective/buildout.plonetest/master/test-6.0.x.cfg\n-\n-package-name = Products.isurlinportal\n-\n-[versions]\n-pip =\n-setuptools =\n-wheel =\n-zc.buildout =\n-# Use development version:\n-Products.isurlinportal =\ndiff --git a/news/3333c742.internal b/news/3333c742.internal\nnew file mode 100644\nindex 0000000..c08f539\n--- /dev/null\n+++ b/news/3333c742.internal\n@@ -0,0 +1,2 @@\n+Update configuration files.\n+[plone devs]\ndiff --git a/pyproject.toml b/pyproject.toml\nindex 05b615d..a2bcbed 100644\n--- a/pyproject.toml\n+++ b/pyproject.toml\n@@ -1,3 +1,5 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n [tool.towncrier]\n filename = "CHANGES.rst"\n directory = "news/"\n@@ -18,3 +20,68 @@ showcontent = true\n directory = "bugfix"\n name = "Bug fixes:"\n showcontent = true\n+\n+[[tool.towncrier.type]]\n+directory = "internal"\n+name = "Internal:"\n+showcontent = true\n+\n+[[tool.towncrier.type]]\n+directory = "documentation"\n+name = "Documentation:"\n+showcontent = true\n+\n+[[tool.towncrier.type]]\n+directory = "tests"\n+name = "Tests"\n+showcontent = true\n+\n+[tool.isort]\n+profile = "plone"\n+\n+[tool.black]\n+target-version = ["py38"]\n+\n+[tool.codespell]\n+ignore-words-list = "noo"\n+\n+[tool.dependencychecker]\n+Zope = [\n+ # Zope own provided namespaces\n+ \'App\', \'OFS\', \'Products.Five\', \'Products.OFSP\', \'Products.PageTemplates\',\n+ \'Products.SiteAccess\', \'Shared\', \'Testing\', \'ZPublisher\', \'ZTUtils\',\n+ \'Zope2\', \'webdav\', \'zmi\',\n+ # ExtensionClass own provided namespaces\n+ \'ExtensionClass\', \'ComputedAttribute\', \'MethodObject\',\n+ # Zope dependencies\n+ \'AccessControl\', \'Acquisition\', \'AuthEncoding\', \'beautifulsoup4\', \'BTrees\',\n+ \'cffi\', \'Chameleon\', \'DateTime\', \'DocumentTemplate\',\n+ \'MultiMapping\', \'multipart\', \'PasteDeploy\', \'Persistence\', \'persistent\',\n+ \'pycparser\', \'python-gettext\', \'pytz\', \'RestrictedPython\', \'roman\',\n+ \'soupsieve\', \'transaction\', \'waitress\', \'WebOb\', \'WebTest\', \'WSGIProxy2\',\n+ \'z3c.pt\', \'zc.lockfile\', \'ZConfig\', \'zExceptions\', \'ZODB\', \'zodbpickle\',\n+ \'zope.annotation\', \'zope.browser\', \'zope.browsermenu\', \'zope.browserpage\',\n+ \'zope.browserresource\', \'zope.cachedescriptors\', \'zope.component\',\n+ \'zope.configuration\', \'zope.container\', \'zope.contentprovider\',\n+ \'zope.contenttype\', \'zope.datetime\', \'zope.deferredimport\',\n+ \'zope.deprecation\', \'zope.dottedname\', \'zope.event\', \'zope.exceptions\',\n+ \'zope.filerepresentation\', \'zope.globalrequest\', \'zope.hookable\',\n+ \'zope.i18n\', \'zope.i18nmessageid\', \'zope.interface\', \'zope.lifecycleevent\',\n+ \'zope.location\', \'zope.pagetemplate\', \'zope.processlifetime\', \'zope.proxy\',\n+ \'zope.ptresource\', \'zope.publisher\', \'zope.schema\', \'zope.security\',\n+ \'zope.sequencesort\', \'zope.site\', \'zope.size\', \'zope.structuredtext\',\n+ \'zope.tal\', \'zope.tales\', \'zope.testbrowser\', \'zope.testing\',\n+ \'zope.traversing\', \'zope.viewlet\'\n+]\n+\'Products.CMFCore\' = [\n+ \'docutils\', \'five.localsitemanager\', \'Missing\', \'Products.BTreeFolder2\',\n+ \'Products.GenericSetup\', \'Products.MailHost\', \'Products.PythonScripts\',\n+ \'Products.StandardCacheManagers\', \'Products.ZCatalog\', \'Record\',\n+ \'zope.sendmail\', \'Zope\'\n+]\n+\'plone.base\' = [\n+ \'plone.batching\', \'plone.registry\', \'plone.schema\',\'plone.z3cform\',\n+ \'Products.CMFCore\', \'Products.CMFDynamicViewFTI\',\n+]\n+python-dateutil = [\'dateutil\']\n+ignore-packages = [\'Products.CMFPlone\']\ndiff --git a/requirements.txt b/requirements.txt\ndeleted file mode 100644\nindex eed370c..0000000\n--- a/requirements.txt\n+++ /dev/null\n@@ -1,4 +0,0 @@\n-pip==22.3.1\n-setuptools==65.7.0\n-wheel==0.38.4\n-zc.buildout==3.0.1\ndiff --git a/setup.cfg b/setup.cfg\nindex e6d0f89..0da8f8f 100644\n--- a/setup.cfg\n+++ b/setup.cfg\n@@ -1,8 +1,23 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n [bdist_wheel]\n-universal = 1\n+universal = 0\n+\n+[flake8]\n+doctests = 1\n+ignore =\n+ # black takes care of line length\n+ E501,\n+ # black takes care of where to break lines\n+ W503,\n+ # black takes care of spaces within slicing (list[:])\n+ E203,\n+ # black takes care of spaces after commas\n+ E231,\n \n [check-manifest]\n ignore =\n- buildout.cfg\n- requirements.txt\n+ .editorconfig\n+ .meta.toml\n+ .pre-commit-config.yaml\n tox.ini\ndiff --git a/setup.py b/setup.py\nindex 25d2a74..64e388b 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -36,5 +36,13 @@\n include_package_data=True,\n zip_safe=False,\n python_requires=">=3.8",\n- install_requires=["setuptools"],\n+ install_requires=[\n+ "setuptools",\n+ "plone.base",\n+ ],\n+ extras_require={\n+ "test": [\n+ "Products.CMFPlone",\n+ ]\n+ },\n )\ndiff --git a/tox.ini b/tox.ini\nindex e16622e..acb4618 100644\n--- a/tox.ini\n+++ b/tox.ini\n@@ -1,39 +1,68 @@\n+# Generated from:\n+# https://github.com/plone/meta/tree/master/config/default\n [tox]\n+# We need 4.4.0 for constrain_package_deps.\n+min_version = 4.4.0\n envlist =\n- plone60-py38\n- plone60-py39\n- plone60-py310\n- plone60-py311\n+ format\n+ lint\n+ test\n \n [testenv]\n-commands =\n- cp {toxinidir}/buildout.cfg {envdir}/buildout.cfg\n- sed -ie "s/test-6.0.x.cfg/test-{env:PLONE_VERSION}.x.cfg/" {envdir}/buildout.cfg\n- {envbindir}/buildout -c {envdir}/buildout.cfg buildout:directory={envdir} buildout:develop={toxinidir} install test\n- {envbindir}/test\n+allowlist_externals =\n+ sh\n+\n+[testenv:format]\n+description = automatically reformat code\n skip_install = true\n deps =\n- -rrequirements.txt\n-allowlist_externals =\n- cp\n- sed\n+ pre-commit\n+commands =\n+ pre-commit run -a pyupgrade\n+ pre-commit run -a isort\n+ pre-commit run -a black\n+ pre-commit run -a zpretty\n \n-[testenv:plone60-py38]\n-basepython = python3.8\n-setenv =\n- PLONE_VERSION=6.0\n+[testenv:lint]\n+description = run linters that will help improve the code style\n+skip_install = true\n+deps =\n+ pre-commit\n+commands =\n+ pre-commit run -a\n \n-[testenv:plone60-py39]\n-basepython = python3.9\n-setenv =\n- PLONE_VERSION=6.0\n+[testenv:dependencies]\n+description = check if the package defines all its dependencies and generate a graph out of them\n+deps =\n+ z3c.dependencychecker==2.11\n+ pipdeptree==2.5.1\n+ graphviz # optional dependency of pipdeptree\n+commands =\n+ dependencychecker\n+ sh -c \'pipdeptree --exclude setuptools,wheel,pipdeptree,z3c.dependencychecker,zope.interface,zope.component --graph-output svg > dependencies.svg\'\n \n-[testenv:plone60-py310]\n-basepython = python3.10\n-setenv =\n- PLONE_VERSION=6.0\n+[testenv:test]\n+usedevelop = true\n+constrain_package_deps = true\n+set_env = ROBOT_BROWSER=headlesschrome\n+deps =\n+ zope.testrunner\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+commands =\n+ zope-testrunner --all --test-path={toxinidir} -s Products.isurlinportal {posargs}\n+extras =\n+ test\n \n-[testenv:plone60-py311]\n-basepython = python3.11\n-setenv =\n- PLONE_VERSION=6.0\n+[testenv:coverage]\n+usedevelop = true\n+constrain_package_deps = true\n+set_env = ROBOT_BROWSER=headlesschrome\n+deps =\n+ coverage\n+ zope.testrunner\n+ -c https://dist.plone.org/release/6.0-dev/constraints.txt\n+commands =\n+ coverage run {envbindir}/zope-testrunner --all --test-path={toxinidir} -s Products.isurlinportal {posargs}\n+ coverage report -m --format markdown\n+extras =\n+ test\n' +A Products/CMFPlone/resources/eventhandlers.py +A news/3505.bugfix +M Products/CMFPlone/controlpanel/browser/resourceregistry.pt +M Products/CMFPlone/controlpanel/browser/resourceregistry.py +M Products/CMFPlone/resources/browser/resource.py +M Products/CMFPlone/resources/configure.zcml + +b'diff --git a/Products/CMFPlone/controlpanel/browser/resourceregistry.pt b/Products/CMFPlone/controlpanel/browser/resourceregistry.pt\nindex 071d03817f..4279bdb02b 100644\n--- a/Products/CMFPlone/controlpanel/browser/resourceregistry.pt\n+++ b/Products/CMFPlone/controlpanel/browser/resourceregistry.pt\n@@ -68,7 +68,6 @@\n \n Resources are fast and hashes are cached in Plone.\n- Changes in resource settings are not applied directly.\n \n \n \ndiff --git a/Products/CMFPlone/controlpanel/browser/resourceregistry.py b/Products/CMFPlone/controlpanel/browser/resourceregistry.py\nindex e097435ad7..4277e9d221 100644\n--- a/Products/CMFPlone/controlpanel/browser/resourceregistry.py\n+++ b/Products/CMFPlone/controlpanel/browser/resourceregistry.py\n@@ -2,6 +2,7 @@\n from plone.base import PloneMessageFactory as _\n from plone.base.interfaces import IBundleRegistry\n from plone.registry.interfaces import IRegistry\n+from Products.CMFPlone.resources.browser.resource import update_resource_registry_mtime\n from Products.Five.browser import BrowserView\n from Products.statusmessages.interfaces import IStatusMessage\n from zope.component import getUtility\n@@ -149,4 +150,5 @@ def process_form(self):\n self._switch_cache(False)\n else:\n raise ValueError("Invalid form data")\n+ update_resource_registry_mtime()\n self.request.response.redirect(self.request["ACTUAL_URL"])\ndiff --git a/Products/CMFPlone/resources/browser/resource.py b/Products/CMFPlone/resources/browser/resource.py\nindex c07f71f20a..07369c6176 100644\n--- a/Products/CMFPlone/resources/browser/resource.py\n+++ b/Products/CMFPlone/resources/browser/resource.py\n@@ -7,8 +7,10 @@\n from plone.base.interfaces import IBundleRegistry\n from plone.registry.interfaces import IRegistry\n from Products.CMFCore.utils import getToolByName\n+from time import time\n from zope.component import getMultiAdapter\n from zope.component import getUtility\n+from zope.component import queryUtility\n from zope.component.hooks import getSite\n \n import hashlib\n@@ -19,7 +21,7 @@\n logger = logging.getLogger(__name__)\n \n REQUEST_CACHE_KEY = "_WEBRESOURCE_CACHE_"\n-\n+_RESOURCE_REGISTRY_MTIME = "__RESOURCE_REGISTRY_MTIME"\n GRACEFUL_DEPENDENCY_REWRITE = {\n "plone-base": "plone",\n "plone-legacy": "plone",\n@@ -59,7 +61,12 @@ def _cache_attr_name(self, site):\n for bundle in e_bundles | d_bundles:\n hashtool.update(bundle.encode(\'utf8\'))\n hashtool.update(self._user_local_roles(site).encode("utf8"))\n- return f"_v_renderend_cache_{hashtool.hexdigest()}"\n+ if not getattr(self, "registry", None):\n+ self.registry = getUtility(IRegistry)\n+ mtime = getattr(self.registry, _RESOURCE_REGISTRY_MTIME, None)\n+ if mtime is not None:\n+ hashtool.update(str(mtime).encode(\'utf8\'))\n+ return f"_v_rendered_cache_{hashtool.hexdigest()}"\n \n @property\n def _rendered_cache(self):\n@@ -313,3 +320,19 @@ def index(self):\n rendered = self.renderer["css"].render()\n self._rendered_cache = rendered\n return rendered\n+\n+\n+def update_resource_registry_mtime():\n+ """Update the last modification time of the resource registry.\n+\n+ Call this when you change anything that may influence the resource registry\n+ and any of its rendered cache.\n+ See discussion in https://github.com/plone/Products.CMFPlone/issues/3505\n+ and https://github.com/plone/Products.CMFPlone/pull/3771\n+ """\n+ registry = queryUtility(IRegistry)\n+ if registry is None:\n+ # This can happen for example during site creation.\n+ return\n+ setattr(registry, _RESOURCE_REGISTRY_MTIME, time())\n+ logger.info("Updated resource registry mtime.")\ndiff --git a/Products/CMFPlone/resources/configure.zcml b/Products/CMFPlone/resources/configure.zcml\nindex 0bec1224e4..faf47d627e 100644\n--- a/Products/CMFPlone/resources/configure.zcml\n+++ b/Products/CMFPlone/resources/configure.zcml\n@@ -3,5 +3,6 @@\n i18n_domain="plone.registry">\n \n \n+ \n \n \ndiff --git a/Products/CMFPlone/resources/eventhandlers.py b/Products/CMFPlone/resources/eventhandlers.py\nnew file mode 100644\nindex 0000000000..dae5a5ba7f\n--- /dev/null\n+++ b/Products/CMFPlone/resources/eventhandlers.py\n@@ -0,0 +1,16 @@\n+from Products.CMFPlone.resources.browser.resource import update_resource_registry_mtime\n+from Products.GenericSetup.interfaces import IProfileImportedEvent\n+from zope.component import adapter\n+\n+\n+@adapter(IProfileImportedEvent)\n+def check_registry_update(event):\n+ """Check if a profile import may have updated the configuration registry.\n+\n+ Main concern for now is: the resource registries may have changed.\n+ This means the resource viewlet caches should be cleared.\n+ See discussion in https://github.com/plone/Products.CMFPlone/issues/3505\n+ """\n+ if not (event.full_import or "plone.app.registry" in event.steps):\n+ return\n+ update_resource_registry_mtime()\ndiff --git a/news/3505.bugfix b/news/3505.bugfix\nnew file mode 100644\nindex 0000000000..5cb726e238\n--- /dev/null\n+++ b/news/3505.bugfix\n@@ -0,0 +1,5 @@\n+Add a last modification time of the resource registry.\n+We update this when changing anything related: when changing the resource registry in its control panel or activating an add-on.\n+This avoids needing a restart before seeing changes when you run in production mode.\n+Fixes [issue 3505](https://github.com/plone/Products.CMFPlone/issues/3505).\n+[maurits]\n'