diff --git a/last_commit.txt b/last_commit.txt index 61856faf03..c4cfe7bf36 100644 --- a/last_commit.txt +++ b/last_commit.txt @@ -1,40 +1,34 @@ -Repository: plone.app.registry +Repository: plone.registry Branch: refs/heads/master -Date: 2018-06-19T10:32:35+02:00 -Author: Jens W. Klein (jensens) -Commit: https://github.com/plone/plone.app.registry/commit/a3f04df98efe85e48dd601dba0625396506172ed +Date: 2018-06-19T16:19:30+01:00 +Author: Matthew Wilkes (MatthewWilkes) +Commit: https://github.com/plone/plone.registry/commit/bc13c371e09010ccb97487cd6cdd5ecfb72365cb -added a pragmatic XML exporter for registry records +Improve performance of RecordsProxy.__iter__ Files changed: -A plone/app/registry/browser/exportxml.py -A plone/app/registry/browser/templates/exportxml.pt M CHANGES.rst -M plone/app/registry/browser/configure.zcml -M plone/app/registry/browser/templates/records.pt +M plone/registry/recordsproxy.py -b'diff --git a/CHANGES.rst b/CHANGES.rst\nindex 1b21f3f..a075242 100644\n--- a/CHANGES.rst\n+++ b/CHANGES.rst\n@@ -10,7 +10,8 @@ Breaking changes:\n \n New features:\n \n-- *add item here*\n+- Added a pragmatic XML exporter for registry records in a format meant to be used in add-ons or policy profiles.\n+ [jensens]\n \n Bug fixes:\n \ndiff --git a/plone/app/registry/browser/configure.zcml b/plone/app/registry/browser/configure.zcml\nindex 71f7a21..a1f5b22 100644\n--- a/plone/app/registry/browser/configure.zcml\n+++ b/plone/app/registry/browser/configure.zcml\n@@ -6,6 +6,11 @@\n \n \n \n+ \n+\n \n \n- \n \n \ndiff --git a/plone/app/registry/browser/exportxml.py b/plone/app/registry/browser/exportxml.py\nnew file mode 100644\nindex 0000000..4fccfd4\n--- /dev/null\n+++ b/plone/app/registry/browser/exportxml.py\n@@ -0,0 +1,138 @@\n+# -*- coding: utf-8 -*-\n+from lxml import etree\n+from plone.registry.interfaces import IRegistry\n+from Products.Five import BrowserView\n+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile\n+from zope.component import getUtility\n+\n+import os\n+\n+_current_dir = os.path.dirname(__file__)\n+\n+\n+def _sort_first_lower(key):\n+ return key[0].lower()\n+\n+\n+class RegistryExporterView(BrowserView):\n+ """this view make sane exports of the registry.\n+\n+ Main goal is to export in a way, that the output can be reused as\n+ best practive settings\n+ """\n+\n+ template = ViewPageTemplateFile(\n+ os.path.join(_current_dir, \'templates\', \'exportxml.pt\')\n+ )\n+\n+ def __call__(self):\n+ interface = self.request.form.get(\'interface\', None)\n+ name = self.request.form.get(\'name\', None)\n+ if not interface and not name:\n+ return self.template()\n+ return self.export(sinterface=interface, sname=name)\n+\n+ def interfaces(self):\n+ prefixes = []\n+ registry = getUtility(IRegistry)\n+ baseurl = \'{0}/@@configuration_registry_export_xml?interface=\'.format(\n+ self.context.absolute_url()\n+ )\n+ for record in registry.records.values():\n+ if record.interfaceName is None:\n+ continue\n+ name = record.interfaceName\n+ url = \'{0}{1}\'.format(baseurl, record.interfaceName)\n+ pair = (name, url)\n+ if pair not in prefixes:\n+ prefixes.append(pair)\n+\n+ return sorted(prefixes, key=_sort_first_lower)\n+\n+ def prefixes(self):\n+ prefixes = []\n+ registry = getUtility(IRegistry)\n+ baseurl = \'{0}/@@configuration_registry_export_xml?\'.format(\n+ self.context.absolute_url()\n+ )\n+ for record in registry.records.values():\n+ if record.interfaceName == record.__name__:\n+ continue\n+\n+ def add_split(part):\n+ url = \'{0}name={1}\'.format(baseurl, part)\n+ pair = (part, url)\n+ if pair not in prefixes:\n+ prefixes.append(pair)\n+ if part.rfind(\'/\') > part.rfind(\'.\'):\n+ new_parts = part.rsplit(\'/\', 1)\n+ else:\n+ new_parts = part.rsplit(\'.\', 1)\n+ if len(new_parts) > 1:\n+ add_split(new_parts[0])\n+\n+ add_split(record.__name__)\n+ return sorted(prefixes, key=_sort_first_lower)\n+\n+ def export(self, sinterface=None, sname=None):\n+ registry = getUtility(IRegistry)\n+ root = etree.Element(\'registry\')\n+ values = {} # full prefix to valuerecord\n+ interface2values = {}\n+ interface2prefix = {}\n+ for record in registry.records.values():\n+ if sinterface and sinterface != record.interfaceName:\n+ continue\n+ if sname and not record.__name__.startswith(sname):\n+ continue\n+ prefix, value_key = record.__name__.rsplit(\'.\', 1)\n+ xmlvalue = etree.Element(\'value\')\n+ if record.value is None:\n+ continue\n+ if isinstance(record.value, (list, tuple)):\n+ for element in record.value:\n+ xmlel = etree.SubElement(xmlvalue, \'element\')\n+ xmlel.text = element\n+ elif isinstance(record.value, bool):\n+ xmlvalue.text = \'True\' if record.value else \'False\'\n+ elif isinstance(record.value, basestring):\n+ xmlvalue.text = record.value\n+ else:\n+ xmlvalue.text = str(record.value)\n+\n+ if record.interfaceName:\n+ xmlvalue.attrib[\'key\'] = value_key\n+ if record.interfaceName not in interface2values:\n+ interface2values[record.interfaceName] = []\n+ interface2values[record.interfaceName].append(record.__name__)\n+ interface2prefix[record.interfaceName] = prefix\n+ values[record.__name__] = xmlvalue\n+\n+ for ifname in sorted(interface2values):\n+ xmlrecord = etree.SubElement(root, \'records\')\n+ xmlrecord.attrib[\'interface\'] = ifname\n+ xmlrecord.attrib[\'prefix\'] = interface2prefix[ifname]\n+ for value in sorted(interface2values[ifname]):\n+ xmlrecord.append(values.pop(value))\n+ for name, xmlvalue in values.items():\n+ xmlrecord = etree.SubElement(root, \'records\')\n+ xmlrecord.attrib[\'prefix\'] = name\n+ xmlrecord.append(xmlvalue)\n+\n+ self.request.response.setHeader(\'Content-Type\', \'text/xml\')\n+ filename = \'\'\n+ if sinterface:\n+ filename += sinterface\n+ if sinterface and sname:\n+ filename += \'_-_\'\n+ if sname:\n+ filename += sname\n+ self.request.response.setHeader(\n+ \'Content-Disposition\',\n+ \'attachment; filename={0}.xml\'.format(filename))\n+ return etree.tostring(\n+ root,\n+ pretty_print=True,\n+ xml_declaration=True,\n+ encoding=\'UTF-8\'\n+ )\ndiff --git a/plone/app/registry/browser/templates/exportxml.pt b/plone/app/registry/browser/templates/exportxml.pt\nnew file mode 100644\nindex 0000000..168620f\n--- /dev/null\n+++ b/plone/app/registry/browser/templates/exportxml.pt\n@@ -0,0 +1,25 @@\n+\n+

Export parts

\n+

\n+ Download of a XML-file optimized to be used in a GenericSetup profile of an add-on or policy profile.\n+ It contains only the selected parts.\n+

\n+\n+
\n+
\n+

by Interface

\n+ \n+
\n+
\n+

by Prefix

\n+ \n+
\n+
\n+
\ndiff --git a/plone/app/registry/browser/templates/records.pt b/plone/app/registry/browser/templates/records.pt\nindex 140f72c..0008417 100644\n--- a/plone/app/registry/browser/templates/records.pt\n+++ b/plone/app/registry/browser/templates/records.pt\n@@ -132,6 +132,8 @@\n \n \n \n+
\n+
\n
\n
\n

Import

\n' +b"diff --git a/CHANGES.rst b/CHANGES.rst\nindex 862a57e..bfb876a 100644\n--- a/CHANGES.rst\n+++ b/CHANGES.rst\n@@ -14,7 +14,9 @@ New features:\n \n Bug fixes:\n \n-- *add item here*\n+- Improve performance of RecordsProxy.__iter__ which is now invoked more in\n+ core Plone as part of the requireJS configuration\n+ [MatthewWilkes]\n \n \n 1.1.2 (2016-12-06)\ndiff --git a/plone/registry/recordsproxy.py b/plone/registry/recordsproxy.py\nindex 58a541b..06c39ac 100644\n--- a/plone/registry/recordsproxy.py\n+++ b/plone/registry/recordsproxy.py\n@@ -115,7 +115,7 @@ def __iter__(self):\n if '.' not in name:\n yield name\n else:\n- key = '.'.join(name.split('.')[:-1])\n+ key = name.rsplit('.', 1)[0]\n if key != last:\n yield key\n last = key\n" -Repository: plone.app.registry +Repository: plone.registry Branch: refs/heads/master -Date: 2018-06-19T14:18:32+02:00 -Author: agitator (agitator) -Commit: https://github.com/plone/plone.app.registry/commit/f83160e1e175365583779f25df62f0983164eedb +Date: 2018-06-20T08:39:31+02:00 +Author: Gil Forcada Codinachs (gforcada) +Commit: https://github.com/plone/plone.registry/commit/ca12637ab52dcd3f252012ecf2046cf26202b43b -Merge pull request #26 from plone/jensens-exporter +Merge pull request #15 from plone/wilkes-performance-improvement -added a pragmatic XML exporter for registry records +Improve performance of RecordsProxy.__iter__ Files changed: -A plone/app/registry/browser/exportxml.py -A plone/app/registry/browser/templates/exportxml.pt M CHANGES.rst -M plone/app/registry/browser/configure.zcml -M plone/app/registry/browser/templates/records.pt +M plone/registry/recordsproxy.py -b'diff --git a/CHANGES.rst b/CHANGES.rst\nindex 1b21f3f..a075242 100644\n--- a/CHANGES.rst\n+++ b/CHANGES.rst\n@@ -10,7 +10,8 @@ Breaking changes:\n \n New features:\n \n-- *add item here*\n+- Added a pragmatic XML exporter for registry records in a format meant to be used in add-ons or policy profiles.\n+ [jensens]\n \n Bug fixes:\n \ndiff --git a/plone/app/registry/browser/configure.zcml b/plone/app/registry/browser/configure.zcml\nindex 71f7a21..a1f5b22 100644\n--- a/plone/app/registry/browser/configure.zcml\n+++ b/plone/app/registry/browser/configure.zcml\n@@ -6,6 +6,11 @@\n \n \n \n+ \n+\n \n \n- \n \n \ndiff --git a/plone/app/registry/browser/exportxml.py b/plone/app/registry/browser/exportxml.py\nnew file mode 100644\nindex 0000000..4fccfd4\n--- /dev/null\n+++ b/plone/app/registry/browser/exportxml.py\n@@ -0,0 +1,138 @@\n+# -*- coding: utf-8 -*-\n+from lxml import etree\n+from plone.registry.interfaces import IRegistry\n+from Products.Five import BrowserView\n+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile\n+from zope.component import getUtility\n+\n+import os\n+\n+_current_dir = os.path.dirname(__file__)\n+\n+\n+def _sort_first_lower(key):\n+ return key[0].lower()\n+\n+\n+class RegistryExporterView(BrowserView):\n+ """this view make sane exports of the registry.\n+\n+ Main goal is to export in a way, that the output can be reused as\n+ best practive settings\n+ """\n+\n+ template = ViewPageTemplateFile(\n+ os.path.join(_current_dir, \'templates\', \'exportxml.pt\')\n+ )\n+\n+ def __call__(self):\n+ interface = self.request.form.get(\'interface\', None)\n+ name = self.request.form.get(\'name\', None)\n+ if not interface and not name:\n+ return self.template()\n+ return self.export(sinterface=interface, sname=name)\n+\n+ def interfaces(self):\n+ prefixes = []\n+ registry = getUtility(IRegistry)\n+ baseurl = \'{0}/@@configuration_registry_export_xml?interface=\'.format(\n+ self.context.absolute_url()\n+ )\n+ for record in registry.records.values():\n+ if record.interfaceName is None:\n+ continue\n+ name = record.interfaceName\n+ url = \'{0}{1}\'.format(baseurl, record.interfaceName)\n+ pair = (name, url)\n+ if pair not in prefixes:\n+ prefixes.append(pair)\n+\n+ return sorted(prefixes, key=_sort_first_lower)\n+\n+ def prefixes(self):\n+ prefixes = []\n+ registry = getUtility(IRegistry)\n+ baseurl = \'{0}/@@configuration_registry_export_xml?\'.format(\n+ self.context.absolute_url()\n+ )\n+ for record in registry.records.values():\n+ if record.interfaceName == record.__name__:\n+ continue\n+\n+ def add_split(part):\n+ url = \'{0}name={1}\'.format(baseurl, part)\n+ pair = (part, url)\n+ if pair not in prefixes:\n+ prefixes.append(pair)\n+ if part.rfind(\'/\') > part.rfind(\'.\'):\n+ new_parts = part.rsplit(\'/\', 1)\n+ else:\n+ new_parts = part.rsplit(\'.\', 1)\n+ if len(new_parts) > 1:\n+ add_split(new_parts[0])\n+\n+ add_split(record.__name__)\n+ return sorted(prefixes, key=_sort_first_lower)\n+\n+ def export(self, sinterface=None, sname=None):\n+ registry = getUtility(IRegistry)\n+ root = etree.Element(\'registry\')\n+ values = {} # full prefix to valuerecord\n+ interface2values = {}\n+ interface2prefix = {}\n+ for record in registry.records.values():\n+ if sinterface and sinterface != record.interfaceName:\n+ continue\n+ if sname and not record.__name__.startswith(sname):\n+ continue\n+ prefix, value_key = record.__name__.rsplit(\'.\', 1)\n+ xmlvalue = etree.Element(\'value\')\n+ if record.value is None:\n+ continue\n+ if isinstance(record.value, (list, tuple)):\n+ for element in record.value:\n+ xmlel = etree.SubElement(xmlvalue, \'element\')\n+ xmlel.text = element\n+ elif isinstance(record.value, bool):\n+ xmlvalue.text = \'True\' if record.value else \'False\'\n+ elif isinstance(record.value, basestring):\n+ xmlvalue.text = record.value\n+ else:\n+ xmlvalue.text = str(record.value)\n+\n+ if record.interfaceName:\n+ xmlvalue.attrib[\'key\'] = value_key\n+ if record.interfaceName not in interface2values:\n+ interface2values[record.interfaceName] = []\n+ interface2values[record.interfaceName].append(record.__name__)\n+ interface2prefix[record.interfaceName] = prefix\n+ values[record.__name__] = xmlvalue\n+\n+ for ifname in sorted(interface2values):\n+ xmlrecord = etree.SubElement(root, \'records\')\n+ xmlrecord.attrib[\'interface\'] = ifname\n+ xmlrecord.attrib[\'prefix\'] = interface2prefix[ifname]\n+ for value in sorted(interface2values[ifname]):\n+ xmlrecord.append(values.pop(value))\n+ for name, xmlvalue in values.items():\n+ xmlrecord = etree.SubElement(root, \'records\')\n+ xmlrecord.attrib[\'prefix\'] = name\n+ xmlrecord.append(xmlvalue)\n+\n+ self.request.response.setHeader(\'Content-Type\', \'text/xml\')\n+ filename = \'\'\n+ if sinterface:\n+ filename += sinterface\n+ if sinterface and sname:\n+ filename += \'_-_\'\n+ if sname:\n+ filename += sname\n+ self.request.response.setHeader(\n+ \'Content-Disposition\',\n+ \'attachment; filename={0}.xml\'.format(filename))\n+ return etree.tostring(\n+ root,\n+ pretty_print=True,\n+ xml_declaration=True,\n+ encoding=\'UTF-8\'\n+ )\ndiff --git a/plone/app/registry/browser/templates/exportxml.pt b/plone/app/registry/browser/templates/exportxml.pt\nnew file mode 100644\nindex 0000000..168620f\n--- /dev/null\n+++ b/plone/app/registry/browser/templates/exportxml.pt\n@@ -0,0 +1,25 @@\n+\n+

Export parts

\n+

\n+ Download of a XML-file optimized to be used in a GenericSetup profile of an add-on or policy profile.\n+ It contains only the selected parts.\n+

\n+\n+
\n+
\n+

by Interface

\n+ \n+
\n+
\n+

by Prefix

\n+ \n+
\n+
\n+
\ndiff --git a/plone/app/registry/browser/templates/records.pt b/plone/app/registry/browser/templates/records.pt\nindex 140f72c..0008417 100644\n--- a/plone/app/registry/browser/templates/records.pt\n+++ b/plone/app/registry/browser/templates/records.pt\n@@ -132,6 +132,8 @@\n \n
\n \n+
\n+
\n
\n
\n

Import

\n' +b"diff --git a/CHANGES.rst b/CHANGES.rst\nindex 862a57e..bfb876a 100644\n--- a/CHANGES.rst\n+++ b/CHANGES.rst\n@@ -14,7 +14,9 @@ New features:\n \n Bug fixes:\n \n-- *add item here*\n+- Improve performance of RecordsProxy.__iter__ which is now invoked more in\n+ core Plone as part of the requireJS configuration\n+ [MatthewWilkes]\n \n \n 1.1.2 (2016-12-06)\ndiff --git a/plone/registry/recordsproxy.py b/plone/registry/recordsproxy.py\nindex 58a541b..06c39ac 100644\n--- a/plone/registry/recordsproxy.py\n+++ b/plone/registry/recordsproxy.py\n@@ -115,7 +115,7 @@ def __iter__(self):\n if '.' not in name:\n yield name\n else:\n- key = '.'.join(name.split('.')[:-1])\n+ key = name.rsplit('.', 1)[0]\n if key != last:\n yield key\n last = key\n"