-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Ross Patterson wrote:
> I got tired of reindexing large indexes that were cleared
> unintelligently by the index import adapters so I wrote the following
> exportimport.pluginindexes and overrides.zcml.  I'm posting them here
> in case anyone wants to use the code.
> 
> This doesn't handle reindexing indexes when it's needed but it does
> keep the adapters from needlessly clearing the indexes.

Thanks!  I've reworked your changes as a patch against the GenericSetup
trunk, including tests of both cases (clear / don't clear).  (Patch
attached).

Can anybody offer a reason not to merge this the the trunk?  What about
released branches?


Tres.
- --
===================================================================
Tres Seaver          +1 540-429-0999          [EMAIL PROTECTED]
Palladion Software   "Excellence by Design"    http://palladion.com
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFFdtNc+gerLs4ltQ4RAuG6AJ9bsZvahlbKvwISPfAWgroT4k9NCACgyfZm
ypF8qXGohdAxq51YoUw1hHs=
=QQy6
-----END PGP SIGNATURE-----
Index: PluginIndexes/tests/test_exportimport.py
===================================================================
--- PluginIndexes/tests/test_exportimport.py	(revision 71431)
+++ PluginIndexes/tests/test_exportimport.py	(working copy)
@@ -18,6 +18,9 @@
 import unittest
 import Testing
 
+from xml.dom.minidom import parseString
+
+from Products.GenericSetup.testing import DummySetupEnviron
 from Products.GenericSetup.testing import NodeAdapterTestCase
 from Products.GenericSetup.testing import ExportImportZCMLLayer
 
@@ -67,7 +70,63 @@
 </index>
 """
 
+class DummyIndex:
+    _cleared = False
+    def __init__(self, **kw):
+        self.__dict__.update(kw)
 
+    def clear(self):
+        self._cleared = True
+
+class DummyIndexWithProperties(DummyIndex):
+
+    def __init__(self, props, **kw):
+        DummyIndex.__init__(self, **kw)
+        map = self._map = []
+        pdict = self._pdict = {}
+        for prop in props:
+            info = {'id': prop[0], 'type': prop[1], 'mode': prop[2]}
+            map.append(info)
+            pdict[prop[0]] = info
+
+    def _propertyMap(self):
+        return self._map
+
+    def getProperty(self, name):
+        return getattr(self, name)
+
+    def _updateProperty(self, name, value):
+        setattr(self, name, value)
+
+    def propdict(self):
+        return self._pdict
+
+class DummyDateRangeIndex(DummyIndex):
+
+    def __init__(self, since_field, until_field):
+        self._edit(since_field, until_field)
+
+    def _edit(self, since_field, until_field):
+        self.since_field = since_field
+        self.until_field = until_field
+
+    def getSinceField(self):
+        return self.since_field
+
+    def getUntilField(self):
+        return self.until_field
+
+class DummyFilteredSet(DummyIndex):
+
+    def __init__(self, expr):
+        self.expr = expr
+
+    def getExpression(self):
+        return self.expr
+
+    def setExpression(self, value):
+        self.expr = value
+
 class DateIndexNodeAdapterTests(NodeAdapterTestCase):
 
     layer = ExportImportZCMLLayer
@@ -85,7 +144,30 @@
         self._obj = DateIndex('foo_date')
         self._XML = _DATE_XML
 
+    def test__importNode_clears_if_change(self):
+        index = DummyIndexWithProperties(
+                    [('index_naive_time_as_local', 'boolean', 'w')],
+                    index_naive_time_as_local=False,
+                   )
+        environ = DummySetupEnviron()
+        adapter = self._getTargetClass()(index, environ)
+        document = parseString(self._XML)
+        adapter._importNode(document.firstChild)
+        self.failUnless(index._cleared)
 
+    def test__importNode_doesnt_clear_if_no_change(self):
+        index = DummyIndexWithProperties(
+                    [('index_naive_time_as_local', 'boolean', 'w')],
+                    index_naive_time_as_local=True,
+                   )
+        environ = DummySetupEnviron()
+        environ._should_purge = False
+        adapter = self._getTargetClass()(index, environ)
+        document = parseString(self._XML)
+        adapter._importNode(document.firstChild)
+        self.failIf(index._cleared)
+
+
 class DateRangeIndexNodeAdapterTests(NodeAdapterTestCase):
 
     layer = ExportImportZCMLLayer
@@ -107,7 +189,24 @@
         self._obj = DateRangeIndex('foo_daterange')
         self._XML = _DATERANGE_XML
 
+    def test__importNode_clears_if_change(self):
+        index = DummyDateRangeIndex('qux', 'spam')
+        environ = DummySetupEnviron()
+        adapter = self._getTargetClass()(index, environ)
+        document = parseString(self._XML)
+        adapter._importNode(document.firstChild)
+        self.failUnless(index._cleared)
 
+    def test__importNode_doesnt_clear_if_no_change(self):
+        index = DummyDateRangeIndex('bar', 'baz')
+        environ = DummySetupEnviron()
+        environ._should_purge = False
+        adapter = self._getTargetClass()(index, environ)
+        document = parseString(self._XML)
+        adapter._importNode(document.firstChild)
+        self.failIf(index._cleared)
+
+
 class FieldIndexNodeAdapterTests(NodeAdapterTestCase):
 
     layer = ExportImportZCMLLayer
@@ -128,7 +227,23 @@
         self._obj = FieldIndex('foo_field')
         self._XML = _FIELD_XML
 
+    def test__importNode_clears_if_change(self):
+        index = DummyIndex(indexed_attrs=['foo'])
+        environ = DummySetupEnviron()
+        adapter = self._getTargetClass()(index, environ)
+        document = parseString(self._XML)
+        adapter._importNode(document.firstChild)
+        self.failUnless(index._cleared)
 
+    def test__importNode_doesnt_clear_if_no_change(self):
+        index = DummyIndex(indexed_attrs=['bar'])
+        environ = DummySetupEnviron()
+        environ._should_purge = False
+        adapter = self._getTargetClass()(index, environ)
+        document = parseString(self._XML)
+        adapter._importNode(document.firstChild)
+        self.failIf(index._cleared)
+
 class KeywordIndexNodeAdapterTests(NodeAdapterTestCase):
 
     layer = ExportImportZCMLLayer
@@ -150,7 +265,24 @@
         self._obj = KeywordIndex('foo_keyword')
         self._XML = _KEYWORD_XML
 
+    def test__importNode_clears_if_change(self):
+        index = DummyIndex(indexed_attrs=['foo'])
+        environ = DummySetupEnviron()
+        adapter = self._getTargetClass()(index, environ)
+        document = parseString(self._XML)
+        adapter._importNode(document.firstChild)
+        self.failUnless(index._cleared)
 
+    def test__importNode_doesnt_clear_if_no_change(self):
+        index = DummyIndex(indexed_attrs=['bar'])
+        environ = DummySetupEnviron()
+        environ._should_purge = False
+        adapter = self._getTargetClass()(index, environ)
+        document = parseString(self._XML)
+        adapter._importNode(document.firstChild)
+        self.failIf(index._cleared)
+
+
 class PathIndexNodeAdapterTests(NodeAdapterTestCase):
 
     layer = ExportImportZCMLLayer
@@ -232,7 +364,24 @@
         self._obj = PythonFilteredSet('bar', '')
         self._XML = _SET_XML
 
+    def test__importNode_clears_if_change(self):
+        fste = DummyFilteredSet('o.getId() == "foo"')
+        environ = DummySetupEnviron()
+        adapter = self._getTargetClass()(fste, environ)
+        document = parseString(self._XML)
+        adapter._importNode(document.firstChild)
+        self.failUnless(fste._cleared)
 
+    def test__importNode_doesnt_clear_if_no_change(self):
+        fste = DummyFilteredSet('True')
+        environ = DummySetupEnviron()
+        environ._should_purge = False
+        adapter = self._getTargetClass()(fste, environ)
+        document = parseString(self._XML)
+        adapter._importNode(document.firstChild)
+        self.failIf(fste._cleared)
+
+
 class TopicIndexNodeAdapterTests(NodeAdapterTestCase):
 
     layer = ExportImportZCMLLayer
Index: PluginIndexes/exportimport.py
===================================================================
--- PluginIndexes/exportimport.py	(revision 71431)
+++ PluginIndexes/exportimport.py	(working copy)
@@ -58,8 +58,9 @@
             if child.nodeName == 'indexed_attr':
                 indexed_attrs.append(
                                   child.getAttribute('value').encode('utf-8'))
-        self.context.indexed_attrs = indexed_attrs
-        self.context.clear()
+        if getattr(self.context, 'indexed_attrs', None) != indexed_attrs:
+            self.context.indexed_attrs = indexed_attrs
+            self.context.clear()
 
     node = property(_exportNode, _importNode)
 
@@ -84,9 +85,27 @@
         if self.environ.shouldPurge():
             self._purgeProperties()
 
-        self._initProperties(node)
-        self.context.clear()
+        should_clear = False
+        for p_element in node.getElementsByTagName('property'):
+            p_name = p_element.attributes['name'].value
 
+            p_map = self.context.propdict().get(p_name, None)
+            if p_map is None:
+                should_clear = True
+                break
+
+            p_value = p_element.childNodes[0].data
+            if p_map.get('type') == 'boolean':
+                p_value = self._convertToBoolean(p_value)
+
+            if self.context.getProperty(p_name) != p_value:
+                should_clear = True
+                break
+
+        if should_clear:
+            self._initProperties(node)
+            self.context.clear()
+
     node = property(_exportNode, _importNode)
 
 
@@ -108,9 +127,12 @@
     def _importNode(self, node):
         """Import the object from the DOM node.
         """
-        self.context._edit(node.getAttribute('since_field').encode('utf-8'),
-                           node.getAttribute('until_field').encode('utf-8'))
-        self.context.clear()
+        since_field = node.getAttribute('since_field').encode('utf-8')
+        until_field = node.getAttribute('until_field').encode('utf-8')
+        if (self.context.getSinceField() != since_field or
+            self.context.getUntilField() != until_field):
+            self.context._edit(since_field, until_field)
+            self.context.clear()
 
     node = property(_exportNode, _importNode)
 
@@ -181,9 +203,10 @@
     def _importNode(self, node):
         """Import the object from the DOM node.
         """
-        self.context.setExpression(
-                              node.getAttribute('expression').encode('utf-8'))
-        self.context.clear()
+        new_expr = node.getAttribute('expression').encode('utf-8')
+        if new_expr != self.context.getExpression():
+            self.context.setExpression(new_expr)
+            self.context.clear()
 
     node = property(_exportNode, _importNode)
 
_______________________________________________
Zope-CMF maillist  -  Zope-CMF@lists.zope.org
http://mail.zope.org/mailman/listinfo/zope-cmf

See http://collector.zope.org/CMF for bug reports and feature requests

Reply via email to