source: products/quintagroup.transmogrifier/trunk/quintagroup/transmogrifier/manifest.py @ 1589

Last change on this file since 1589 was 1414, checked in by piv, 14 years ago

merge plone2.1 branche updates (r2426-2428,2433-2452): manifests with valid xml now, binary files fully dumped, local roles are imported, control characters are handled properly

File size: 5.2 KB
Line 
1import os.path
2from xml.dom import minidom
3
4from zope.interface import classProvides, implements
5from zope.annotation.interfaces import IAnnotations
6
7from collective.transmogrifier.interfaces import ISection, ISectionBlueprint
8from collective.transmogrifier.utils import defaultMatcher
9
10from quintagroup.transmogrifier.logger import VALIDATIONKEY
11
12class ManifestExporterSection(object):
13    classProvides(ISectionBlueprint)
14    implements(ISection)
15
16    def __init__(self, transmogrifier, name, options, previous):
17        self.previous = previous
18        self.context = transmogrifier.context
19
20        self.entrieskey = defaultMatcher(options, 'entries-key', name, 'entries')
21        self.fileskey = options.get('files-key', '_files').strip()
22
23        self.doc = minidom.Document()
24
25    def __iter__(self):
26        for item in self.previous:
27            entrieskey = self.entrieskey(*item.keys())[0]
28            if not entrieskey:
29                yield item; continue
30
31            manifest = self.createManifest(item[entrieskey])
32
33            if manifest:
34                files = item.setdefault('_files', {})
35                item[self.fileskey]['manifest'] = {
36                    'name': '.objects.xml',
37                    'data': manifest,
38                }
39
40            yield item
41
42    def createManifest(self, entries):
43        if not entries:
44            return None
45
46        doc = self.doc
47        root = doc.createElement('manifest')
48
49        for obj_id, obj_type in entries:
50            # create record
51            record = doc.createElement('record')
52
53            # set type attribute
54            attr = doc.createAttribute('type')
55            attr.value = obj_type
56            record.setAttributeNode(attr)
57
58            # add object id
59            text = doc.createTextNode(obj_id)
60            record.appendChild(text)
61
62            root.appendChild(record)
63
64        doc.appendChild(root)
65
66        try:
67            data = doc.toprettyxml(indent='  ', encoding='utf-8')
68        except UnicodeDecodeError, e:
69            # all comments are strings encoded in 'utf-8' and they will properly
70            # saved in xml file, but if we explicitly give 'utf-8' encoding
71            # UnicodeDecodeError will be raised when they have non-ascii chars
72            data = doc.toprettyxml(indent='  ')
73
74        doc.unlink()
75        return data
76
77class ManifestImporterSection(object):
78    classProvides(ISectionBlueprint)
79    implements(ISection)
80
81    def __init__(self, transmogrifier, name, options, previous):
82        self.previous = previous
83        self.context = transmogrifier.context
84
85        self.pathkey = defaultMatcher(options, 'path-key', name, 'path')
86        self.fileskey = defaultMatcher(options, 'files-key', name, 'files')
87        self.typekey = options.get('type-key', '_type').strip()
88        self.enable_source_behaviour = options.get('enable-source-behaviour', 'true') == 'true' and True or False
89
90        # communication with logger
91        self.anno = IAnnotations(transmogrifier)
92        self.storage = self.anno.setdefault(VALIDATIONKEY, [])
93
94        # we need this dictionary to store manifest data, because reader section
95        # uses recursion when walking through content folders
96        self.manifests = {}
97
98    def __iter__(self):
99        for item in self.previous:
100            pathkey = self.pathkey(*item.keys())[0]
101            fileskey = self.fileskey(*item.keys())[0]
102
103            # skip items without path
104            if not pathkey: continue
105
106            path  = item[pathkey]
107
108            if path != '':
109                parent, item_id = os.path.split(path)
110                manifest = self.manifests.get(parent, {})
111
112                # skip that are not listed in their parent's manifest
113                if item_id not in manifest: continue
114
115                item[self.typekey] = manifest.pop(item_id)
116                # remove empty manifest dict
117                if not manifest:
118                    del self.manifests[parent]
119
120            # this item is folderish - parse manifest
121            if fileskey and 'manifest' in item[fileskey]:
122                self.extractManifest(path, item[fileskey]['manifest']['data'])
123
124            yield item
125
126        # now we yield items that were defined in manifests but not generated by
127        # previous sections - it is possible
128        if self.manifests and self.enable_source_behaviour:
129            containers = self.manifests.keys()
130            containers.sort()
131            for i in containers:
132                manifest = self.manifests[i]
133                ids = manifest.keys()
134                ids.sort()
135                for id_ in ids:
136                    if i == '':
137                        path = id_
138                    else:
139                        path = '/'.join([i, id_])
140                    self.storage.append(path)
141                    yield {pathkey: path, self.typekey: manifest[id_]}
142
143        # cleanup
144        if VALIDATIONKEY in self.anno:
145            del self.anno[VALIDATIONKEY]
146
147    def extractManifest(self, path, data):
148        doc = minidom.parseString(data)
149        objects = {}
150        for record in doc.getElementsByTagName('record'):
151            type_ = str(record.getAttribute('type'))
152            object_id = str(record.firstChild.nodeValue.strip())
153            objects[object_id] = type_
154        self.manifests[path] = objects
Note: See TracBrowser for help on using the repository browser.