Collective.xdv breaks ugprade from 4.0.9 to 4.3


I am trying to upgrade from {Plone 4.0.9 running bare metal and upgraded when I really have to} to {Plone 4.3 in Docker containers orchestrated from GitLab and upgraded frequently}. I do not mind sharing my Dockerfile, docker-compose.yml and .gitlab-ci.yml when I am done, if anybody is interested.

I am hitting a roadblock that my limited knowledge of Plone does not help me solve. In a nutshell, the upgrade to 4.3 fails with PicklingError: Can't pickle <class 'collective.xdv.interfaces.IXDVLayer'>: import of module collective.xdv.interfaces failed

The least unreasonable workflow I have tried so far has been:

  1. Patch shipped with 4.0.9 to avoid cascading removal of utilities products:
@@ -608,6 +608,8 @@ class QuickInstallerTool(UniqueObject, O
         """Removes a list of products
+        if "utilities" in cascade:
+            cascade.remove("utilities")
         for pid in products:
             prod.uninstall(cascade=cascade, reinstall=reinstall)

This steps prevents the pesky ComponentLookupError: (<InterfaceClass plone.registry.interfaces.IRegistry>, '') issue.

  1. Restore the production (4.0.9) database to my (bare metal, 4.0.9) development environment
  2. From the ZMI, QuickInstaller, uninstall 'XDV theme support'
  3. Using /@@fix-persistent-utilities, remove InterfaceClass collective.xdv.interfaces.IXDVLayer (two occurences)
  4. bin/plonectl stop
  5. Remove collective.xdv from buildout.cfg, run bin/buildout -Nv
  6. bin/plonectl start to have a look around and confirm that the collective.xdv stuff is gone from /prefs_install_products_form and /@@fix-persistent-utilities.
  7. bin/plonectl stop, back up the database
  8. Restore the database in the containerized 4.3.
  9. Hit the "upgrade" button and stare at the containers logs scrolling until the dreadfull
2017-12-24 04:04:56 INFO GenericSetup.rolemap Role / permission map imported.
2017-12-24 04:04:56 INFO GenericSetup.catalog Catalog imported.
2017-12-24 04:04:56 INFO GenericSetup.archetypetool Archetype tool imported.
2017-12-24 04:04:56 ERROR GenericSetup Step pleonformgen has an invalid import handler
2017-12-24 04:04:56 ERROR GenericSetup Step kupu-setup has an invalid import handler
2017-12-24 04:04:56 INFO Reindex Title index with I18N Case Normalizer
2017-12-24 04:04:59 ERROR Upgrade aborted. Error:
Traceback (most recent call last):
  File "/plone/buildout-cache/eggs/Products.CMFPlone-4.3.14-py2.7.egg/Products/CMFPlone/", line 259, in upgrade
  File "/plone/buildout-cache/eggs/Products.GenericSetup-1.8.6-py2.7.egg/Products/GenericSetup/", line 166, in doStep
  File "/plone/buildout-cache/eggs/", line 11, in to43rc1
  File "/plone/buildout-cache/eggs/", line 67, in upgradeToI18NCaseNormalizer
    aq_get(context, 'REQUEST', None))
  File "/plone/buildout-cache/eggs/Products.ZCatalog-2.13.27-py2.7.egg/Products/ZCatalog/", line 436, in reindexIndex
    update_metadata=0, pghandler=pghandler)
  File "/plone/buildout-cache/eggs/Products.CMFPlone-4.3.14-py2.7.egg/Products/CMFPlone/", line 349, in catalog_object
    update_metadata, pghandler=pghandler)
  File "/plone/buildout-cache/eggs/Products.ZCatalog-2.13.27-py2.7.egg/Products/ZCatalog/", line 500, in catalog_object
  File "/plone/buildout-cache/eggs/transaction-1.1.1-py2.7.egg/transaction/", line 101, in savepoint
    return self.get().savepoint(optimistic)
  File "/plone/buildout-cache/eggs/transaction-1.1.1-py2.7.egg/transaction/", line 260, in savepoint
    self._saveAndRaiseCommitishError() # reraises!
  File "/plone/buildout-cache/eggs/transaction-1.1.1-py2.7.egg/transaction/", line 257, in savepoint
    savepoint = Savepoint(self, optimistic, *self._resources)
  File "/plone/buildout-cache/eggs/transaction-1.1.1-py2.7.egg/transaction/", line 690, in __init__
    savepoint = savepoint()
  File "/plone/buildout-cache/eggs/ZODB3-3.10.7-py2.7-linux-x86_64.egg/ZODB/", line 1125, in savepoint
  File "/plone/buildout-cache/eggs/ZODB3-3.10.7-py2.7-linux-x86_64.egg/ZODB/", line 623, in _commit
    self._store_objects(ObjectWriter(obj), transaction)
  File "/plone/buildout-cache/eggs/ZODB3-3.10.7-py2.7-linux-x86_64.egg/ZODB/", line 658, in _store_objects
    p = writer.serialize(obj)  # This calls __getstate__ of obj
  File "/plone/buildout-cache/eggs/ZODB3-3.10.7-py2.7-linux-x86_64.egg/ZODB/", line 422, in serialize
    return self._dump(meta, obj.__getstate__())
  File "/plone/buildout-cache/eggs/ZODB3-3.10.7-py2.7-linux-x86_64.egg/ZODB/", line 431, in _dump
PicklingError: Can't pickle <class 'collective.xdv.interfaces.IXDVLayer'>: import of module collective.xdv.interfaces failed
2017-12-24 04:04:59 INFO End of upgrade path, main migration has finished.
2017-12-24 04:04:59 ERROR The upgrade path did NOT reach current version.
2017-12-24 04:04:59 ERROR Migration has failed

Anybody with ideas on how to go past this?

What I think might help is the removal of the browser layer (IXDVLayer) using an uninstallation step.
At first glance, it looks like fixpersistent utilities should do this but.......
This can be achieved by registering and using an uninstall step.
More information here:
(look for the section that discusses "Uninstallation").

1 Like

Thanks for the link @pigeonflight, it is indeed a good read.

I tweaked collective/xdv/configure.zcml to add

        title="XDV theme support"
        description="Uninstall XDV"

I created a collective/xdv/Extensions folder and a file collective/xdv/Extensions/

from Products.CMFCore.utils import getToolByName
import logging
logger = logging.getLogger('collective.xdv')

def uninstall(portal):
    setup_tool = getToolByName(portal, 'portal_setup')
    logger.warning("Guillaume - uninstall of profile-collective.xdv.interfaces.IXDVLayer done")
    return "Ran all uninstall steps."

However, Plone seems to be gloriously ignoring my Nothing in the logs when I uninstall the product, but I do see the expected logs when I install it:

2017-12-24T17:42:54 INFO GenericSetup.browserlayer Browser layers imported

Does have to be declared or registered anywhere?

Try using portal_setup to run the uninstall profile.
{your-site}/portal_setup/manage > import

I can see the uninstall profile and run it from {my-site}/portal_setup/manage > import. None of the "available import steps" rings a bell, so I tried to run all of them. They do not produce the logs I would expect, and do not seem to be calling my uninstall.

Maybe I'm missing something.
If that isn't working for you, another approach is to use a genericsetup profile, similar to what is done here:

The browserlayer.xml can be used to remove specific layers.

Plone Foundation Code of Conduct