vendor/CMF/1.6.3/CMFCore

view exportimport/content.py @ 0:587011552858

import CMF 1.6.3
author bdelbosc
date Mon, 23 Apr 2007 13:58:01 +0000
parents
children
line source
1 ##############################################################################
2 #
3 # Copyright (c) 2005 Zope Corporation and Contributors. All Rights Reserved.
4 #
5 # This software is subject to the provisions of the Zope Public License,
6 # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
10 # FOR A PARTICULAR PURPOSE.
11 #
12 ##############################################################################
13 """Filesystem exporter / importer adapters.
15 $Id$
16 """
17 try:
18 set = set
19 except NameError:
20 from sets import Set as set
22 from csv import reader
23 from csv import register_dialect
24 from csv import writer
25 from ConfigParser import ConfigParser
26 import re
27 from StringIO import StringIO
29 from zope.interface import implements
30 from zope.interface import directlyProvides
32 from Products.GenericSetup.interfaces import IFilesystemExporter
33 from Products.GenericSetup.interfaces import IFilesystemImporter
34 from Products.GenericSetup.content import _globtest
35 from Products.CMFCore.utils import getToolByName
37 #
38 # setup_tool handlers
39 #
40 def exportSiteStructure(context):
41 IFilesystemExporter(context.getSite()).export(context, 'structure', True)
43 def importSiteStructure(context):
44 IFilesystemImporter(context.getSite()).import_(context, 'structure', True)
47 #
48 # Filesystem export/import adapters
49 #
50 class StructureFolderWalkingAdapter(object):
51 """ Tree-walking exporter for "folderish" types.
53 Folderish instances are mapped to directories within the 'structure'
54 portion of the profile, where the folder's relative path within the site
55 corresponds to the path of its directory under 'structure'.
57 The subobjects of a folderish instance are enumerated in the '.objects'
58 file in the corresponding directory. This file is a CSV file, with one
59 row per subobject, with the following wtructure::
61 "<subobject id>","<subobject portal_type>"
63 Subobjects themselves are represented as individual files or
64 subdirectories within the parent's directory.
66 If the import step finds that any objects specified to be created by the
67 'structure' directory setup already exist, these objects will be deleted
68 and then recreated by the profile. The existence of a '.preserve' file
69 within the 'structure' hierarchy allows specification of objects that
70 should not be deleted. '.preserve' files should contain one preserve
71 rule per line, with shell-style globbing supported (i.e. 'b*' will match
72 all objects w/ id starting w/ 'b'.
74 Similarly, a '.delete' file can be used to specify the deletion of any
75 objects that exist in the site but are NOT in the 'structure' hierarchy,
76 and thus will not be recreated during the import process.
77 """
79 implements(IFilesystemExporter, IFilesystemImporter)
81 def __init__(self, context):
82 self.context = context
84 def export(self, export_context, subdir, root=False):
85 """ See IFilesystemExporter.
86 """
87 # Enumerate exportable children
88 exportable = self.context.contentItems()
89 exportable = [x + (IFilesystemExporter(x, None),) for x in exportable]
90 exportable = [x for x in exportable if x[1] is not None]
92 stream = StringIO()
93 csv_writer = writer(stream)
95 for object_id, object, ignored in exportable:
96 csv_writer.writerow((object_id, object.getPortalTypeName()))
98 if not root:
99 subdir = '%s/%s' % (subdir, self.context.getId())
101 export_context.writeDataFile('.objects',
102 text=stream.getvalue(),
103 content_type='text/comma-separated-values',
104 subdir=subdir,
105 )
107 parser = ConfigParser()
109 parser.set('DEFAULT', 'Title', self.context.Title())
110 parser.set('DEFAULT', 'Description', self.context.Description())
111 stream = StringIO()
112 parser.write(stream)
114 export_context.writeDataFile('.properties',
115 text=stream.getvalue(),
116 content_type='text/plain',
117 subdir=subdir,
118 )
120 for id, object in self.context.objectItems():
122 adapter = IFilesystemExporter(object, None)
124 if adapter is not None:
125 adapter.export(export_context, subdir)
127 def import_(self, import_context, subdir, root=False):
128 """ See IFilesystemImporter.
129 """
130 context = self.context
132 if not root:
133 subdir = '%s/%s' % (subdir, context.getId())
135 objects = import_context.readDataFile('.objects', subdir)
136 if objects is None:
137 return
139 dialect = 'excel'
140 stream = StringIO(objects)
141 rowiter = reader(stream, dialect)
142 ours = tuple(rowiter)
143 our_ids = set([item[0] for item in ours])
145 prior = set(context.contentIds())
147 preserve = import_context.readDataFile('.preserve', subdir)
148 if not preserve:
149 preserve = set()
150 else:
151 preservable = prior.intersection(our_ids)
152 preserve = set(_globtest(preserve, preservable))
154 delete = import_context.readDataFile('.delete', subdir)
155 if not delete:
156 delete= set()
157 else:
158 deletable = prior.difference(our_ids)
159 delete = set(_globtest(delete, deletable))
161 # if it's in our_ids and NOT in preserve, or if it's not in
162 # our_ids but IS in delete, we're gonna delete it
163 delete = our_ids.difference(preserve).union(delete)
165 for id in prior.intersection(delete):
166 context._delObject(id)
168 existing = context.objectIds()
170 for object_id, portal_type in ours:
172 if object_id not in existing:
173 object = self._makeInstance(object_id, portal_type,
174 subdir, import_context)
175 if object is None:
176 logger = import_context.getLogger('SFWA')
177 logger.warning("Couldn't make instance: %s/%s" %
178 (subdir, object_id))
179 continue
181 wrapped = context._getOb(object_id)
183 IFilesystemImporter(wrapped).import_(import_context, subdir)
185 def _makeInstance(self, id, portal_type, subdir, import_context):
187 context = self.context
188 properties = import_context.readDataFile('.properties',
189 '%s/%s' % (subdir, id))
190 tool = getToolByName(context, 'portal_types')
192 try:
193 tool.constructContent(portal_type, context, id)
194 except ValueError: # invalid type
195 return None
197 content = context._getOb(id)
199 if properties is not None:
200 lines = properties.splitlines()
202 stream = StringIO('\n'.join(lines))
203 parser = ConfigParser(defaults={'title': '', 'description': 'NONE'})
204 parser.readfp(stream)
206 title = parser.get('DEFAULT', 'title')
207 description = parser.get('DEFAULT', 'description')
209 content.setTitle(title)
210 content.setDescription(description)
212 return content