[CMF-checkins] SVN: CMF/branches/2.0/CMFCore/exportimport/ * no longer delete all content that isn't explicitly in .preserve unless the

Rob Miller ra at burningman.com
Tue Apr 4 16:13:37 EDT 2006


Log message for revision 66442:
  * no longer delete all content that isn't explicitly in .preserve unless the
    content is to be reimported
  
  * add '.delete' file support
  
  

Changed:
  U   CMF/branches/2.0/CMFCore/exportimport/content.py
  U   CMF/branches/2.0/CMFCore/exportimport/tests/test_content.py

-=-
Modified: CMF/branches/2.0/CMFCore/exportimport/content.py
===================================================================
--- CMF/branches/2.0/CMFCore/exportimport/content.py	2006-04-04 20:13:35 UTC (rev 66441)
+++ CMF/branches/2.0/CMFCore/exportimport/content.py	2006-04-04 20:13:36 UTC (rev 66442)
@@ -14,6 +14,10 @@
 
 $Id$
 """
+try:
+    set = set
+except NameError:
+    from sets import Set as set
 
 from csv import reader
 from csv import register_dialect
@@ -58,6 +62,17 @@
 
     Subobjects themselves are represented as individual files or
     subdirectories within the parent's directory.
+    If the import step finds that any objects specified to be created by the
+    'structure' directory setup already exist, these objects will be deleted
+    and then recreated by the profile.  The existence of a '.preserve' file
+    within the 'structure' hierarchy allows specification of objects that
+    should not be deleted.  '.preserve' files should contain one preserve
+    rule per line, with shell-style globbing supported (i.e. 'b*' will match
+    all objects w/ id starting w/ 'b'.
+
+    Similarly, a '.delete' file can be used to specify the deletion of any
+    objects that exist in the site but are NOT in the 'structure' hierarchy,
+    and thus will not be recreated during the import process.
     """
 
     implements(IFilesystemExporter, IFilesystemImporter)
@@ -115,19 +130,6 @@
         if not root:
             subdir = '%s/%s' % (subdir, context.getId())
 
-        preserve = import_context.readDataFile('.preserve', subdir)
-
-        prior = context.contentIds()
-
-        if not preserve:
-            preserve = []
-        else:
-            preserve = _globtest(preserve, prior)
-
-        for id in prior:
-            if id not in preserve:
-                context._delObject(id)
-
         objects = import_context.readDataFile('.objects', subdir)
         if objects is None:
             return
@@ -136,10 +138,35 @@
         stream = StringIO(objects)
 
         rowiter = reader(stream, dialect)
+        ours = tuple(rowiter)
+        our_ids = set([item[0] for item in ours])
 
+        prior = set(context.contentIds())
+
+        preserve = import_context.readDataFile('.preserve', subdir)
+        if not preserve:
+            preserve = set()
+        else:
+            preservable = prior.intersection(our_ids)
+            preserve = set(_globtest(preserve, preservable))
+
+        delete = import_context.readDataFile('.delete', subdir)
+        if not delete:
+            delete= set()
+        else:
+            deletable = prior.difference(our_ids)
+            delete = set(_globtest(delete, deletable))
+
+        # if it's in our_ids and NOT in preserve, or if it's not in
+        # our_ids but IS in delete, we're gonna delete it
+        delete = our_ids.difference(preserve).union(delete)
+
+        for id in prior.intersection(delete):
+            context._delObject(id)
+
         existing = context.objectIds()
 
-        for object_id, portal_type in rowiter:
+        for object_id, portal_type in ours:
 
             if object_id not in existing:
                 object = self._makeInstance(object_id, portal_type,

Modified: CMF/branches/2.0/CMFCore/exportimport/tests/test_content.py
===================================================================
--- CMF/branches/2.0/CMFCore/exportimport/tests/test_content.py	2006-04-04 20:13:35 UTC (rev 66441)
+++ CMF/branches/2.0/CMFCore/exportimport/tests/test_content.py	2006-04-04 20:13:36 UTC (rev 66442)
@@ -435,7 +435,7 @@
             self.assertEqual(component, 'SFWA')
             self.failUnless(message.startswith("Couldn't make"))
 
-    def test_import_site_with_subitems_and_no_preserve(self):
+    def test_reimport_no_structure_no_delete(self):
         self._setUpAdapters()
         ITEM_IDS = ('foo', 'bar', 'baz')
 
@@ -444,25 +444,59 @@
             site._setObject(id, _makeItem(id))
 
         context = DummyImportContext(site)
-        # We want to add 'baz' to 'foo', without losing 'bar'
+        # no defined structure => no deletion
         context._files['structure/.objects'] = ''
 
         importer = self._getImporter()
         importer(context)
 
-        self.assertEqual(len(site.objectIds()), 0)
+        self.assertEqual(len(site.objectIds()), len(ITEM_IDS))
 
-    def test_import_site_with_subitemss_and_preserve(self):
+    def test_reimport_with_structure_does_delete(self):
         self._setUpAdapters()
         ITEM_IDS = ('foo', 'bar', 'baz')
 
         site = _makeFolder('site', site_folder=True)
         for id in ITEM_IDS:
             site._setObject(id, _makeItem(id))
+            site._getOb(id).before = True
 
         context = DummyImportContext(site)
-        # We want to add 'baz' to 'foo', without losing 'bar'
-        context._files['structure/.objects'] = ''
+        # defined structure => object deleted and recreated
+        context._files['structure/.objects'] = '\n'.join(
+            ['%s,%s' % (x, TEST_INI_AWARE) for x in ITEM_IDS])
+        for index in range(len(ITEM_IDS)):
+            id = ITEM_IDS[index]
+            context._files[
+                    'structure/%s.ini' % id] = KNOWN_INI % ('Title: %s' % id,
+                                                            'xyzzy',
+                                                           )
+
+        importer = self._getImporter()
+        importer(context)
+
+        self.assertEqual(len(site.objectIds()), len(ITEM_IDS))
+        for obj in site.objectValues():
+            self.failIf(hasattr(obj, 'before'))
+
+    def test_reimport_with_structure_and_preserve(self):
+        self._setUpAdapters()
+        ITEM_IDS = ('foo', 'bar', 'baz')
+
+        site = _makeFolder('site', site_folder=True)
+        for id in ITEM_IDS:
+            site._setObject(id, _makeINIAware(id))
+            site._getOb(id).before = True
+
+        context = DummyImportContext(site)
+        context._files['structure/.objects'] = '\n'.join(
+            ['%s,%s' % (x, TEST_INI_AWARE) for x in ITEM_IDS])
+        for index in range(len(ITEM_IDS)):
+            id = ITEM_IDS[index]
+            context._files[
+                    'structure/%s.ini' % id] = KNOWN_INI % ('Title: %s' % id,
+                                                            'xyzzy',
+                                                           )
         context._files['structure/.preserve'] = '*'
 
         importer = self._getImporter()
@@ -472,27 +506,69 @@
         self.assertEqual(len(after), len(ITEM_IDS))
         for i in range(len(ITEM_IDS)):
             self.assertEqual(after[i], ITEM_IDS[i])
+            self.assertEqual(getattr(site._getOb(after[i]), 'before', None),
+                             True)
 
-    def test_import_site_with_subitemss_and_preserve_partial(self):
+    def test_reimport_with_structure_and_preserve_partial(self):
         self._setUpAdapters()
         ITEM_IDS = ('foo', 'bar', 'baz')
 
         site = _makeFolder('site', site_folder=True)
         for id in ITEM_IDS:
-            site._setObject(id, _makeItem(id))
+            site._setObject(id, _makeINIAware(id))
+            site._getOb(id).before = True
 
         context = DummyImportContext(site)
-        # We want to add 'baz' to 'foo', without losing 'bar'
-        context._files['structure/.objects'] = ''
+        context._files['structure/.objects'] = '\n'.join(
+            ['%s,%s' % (x, TEST_INI_AWARE) for x in ITEM_IDS])
+        for index in range(len(ITEM_IDS)):
+            id = ITEM_IDS[index]
+            context._files[
+                    'structure/%s.ini' % id] = KNOWN_INI % ('Title: %s' % id,
+                                                            'xyzzy',
+                                                           )
         context._files['structure/.preserve'] = 'b*'
 
         importer = self._getImporter()
         importer(context)
 
+        after = site.objectValues()
+        self.assertEqual(len(after), len(ITEM_IDS))
+        for obj in after:
+            if obj.getId().startswith('b'):
+                self.assertEqual(getattr(obj, 'before', None), True)
+            else:
+                self.assertEqual(getattr(obj, 'before', None), None)
+
+    def test_reimport_with_structure_partial_preserve_and_delete(self):
+        self._setUpAdapters()
+        ITEM_IDS = ('foo', 'bar', 'baz')
+
+        site = _makeFolder('site', site_folder=True)
+        for id in ITEM_IDS:
+            site._setObject(id, _makeINIAware(id))
+            site._getOb(id).before = True
+
+        context = DummyImportContext(site)
+        context._files['structure/.objects'] = '\n'.join(
+            ['%s,%s' % (x, TEST_INI_AWARE) for x in ITEM_IDS[:-1]])
+        for index in range(len(ITEM_IDS)):
+            id = ITEM_IDS[index]
+            context._files[
+                    'structure/%s.ini' % id] = KNOWN_INI % ('Title: %s' % id,
+                                                            'xyzzy',
+                                                           )
+        context._files['structure/.preserve'] = 'foo'
+        context._files['structure/.delete'] = 'baz'
+
+        importer = self._getImporter()
+        importer(context)
+
         after = site.objectIds()
-        self.assertEqual(len(after), 2)
-        self.assertEqual(after[0], 'bar')
-        self.assertEqual(after[1], 'baz')
+        self.assertEqual(len(after), len(ITEM_IDS) - 1)
+        self.failIf('baz' in after)
+        self.assertEqual(getattr(site.foo, 'before', None), True)
+        self.failIf(hasattr(site.bar, 'before'))
 
     def test_import_site_with_subfolders_and_preserve(self):
         self._setUpAdapters()



More information about the CMF-checkins mailing list