Changeset 4946 for branch/QuickScan/umit/plugin/Containers.py
- Timestamp:
- 06/29/09 18:05:30 (4 years ago)
- Location:
- branch/QuickScan
- Files:
-
- 2 modified
-
. (modified) (1 prop)
-
umit/plugin/Containers.py (modified) (19 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branch/QuickScan
- Property svnmerge-integrated changed from /trunk:1-4792 to /trunk:1-4937
-
branch/QuickScan/umit/plugin/Containers.py
r4746 r4946 21 21 import os 22 22 import os.path 23 import sys 23 24 24 25 from fnmatch import fnmatch 25 26 from zipfile import ZipFile, BadZipfile, ZIP_DEFLATED 26 from xml.dom.minidom import parseString, getDOMImplementation 27 28 from StringIO import StringIO 29 30 from xml.sax import handler, make_parser 31 from xml.sax.saxutils import XMLGenerator 32 from xml.sax.xmlreader import AttributesImpl 33 27 34 from tempfile import mktemp 28 35 … … 55 62 import shutil 56 63 57 # FIXME: add others fields58 FIELDS = (59 "url",60 "conflicts",61 "provides",62 "needs",63 "type",64 "start_file",65 "name",66 "version", # only a convenient field67 "description",68 "author",69 "license",70 "artist",71 "copyright",72 "update"73 )74 75 64 SIGNATURE = "UmitPlugin" 65 66 class ManifestObject(object): 67 def __init__(self): 68 69 # Ok here we're using list object because py2.5 seems to not support 70 # index() for tuple. Stupid 2.5 :) 71 72 self.elements = [ 73 ['name', 'version', 'description', 'url'], 74 ['start_file', 'update'], 75 ['provide', 'need', 'conflict'], 76 ['license', 'copyright', 'author', 77 'contributor', 'translator', 'artist'] 78 ] 79 80 self.containers = [SIGNATURE, 'runtime', 'deptree', 'credits'] 81 82 self.name = '' 83 self.version = '' 84 self.description = '' 85 self.url = '' 86 87 self.start_file = '' 88 self.update = [] 89 90 self.provide = [] 91 self.need = [] 92 self.conflict = [] 93 94 self.license = [] 95 self.copyright = [] 96 self.author = [] 97 self.contributor = [] 98 self.translator = [] 99 self.artist = [] 100 101 self.attr_type = '' 102 103 def check_validity(self, use_print=False): 104 """ 105 Checks the fields presents and validity 106 107 @return True if it's ok 108 """ 109 110 # This fields should be present and not null 111 fields = ('name', 'version', 'description', 'url', 'start_file', 112 'license', 'copyright', 'author') 113 114 for element in fields: 115 if not getattr(self, element, None): 116 txt = 'Element named %s should not be null.' % (element) 117 118 if use_print: 119 print txt 120 else: 121 log.warning(txt) 122 123 return False 124 125 return True 126 127 def get_provides(self): return self.provide 128 def get_conflicts(self): return self.conflict 129 def get_needs(self): return self.need 130 131 provides = property(get_provides) 132 conflicts = property(get_conflicts) 133 needs = property(get_needs) 134 135 class ManifestLoader(handler.ContentHandler, ManifestObject): 136 def __init__(self): 137 ManifestObject.__init__(self) 138 139 self.element_idx = 0 140 self.parsing_pass = -1 141 self.current_element = None 142 self.data = None 143 144 def startElement(self, name, attrs): 145 try: 146 self.element_idx = self.elements[self.parsing_pass].index(name) 147 self.current_element = \ 148 self.elements[self.parsing_pass][self.element_idx] 149 150 except IndexError: 151 log.debug('Element named `%s` is not in %s' % \ 152 (name, self.elements[self.parsing_pass])) 153 154 except ValueError: 155 try: 156 idx = self.containers.index(name) 157 158 if self.parsing_pass < idx: 159 self.parsing_pass = idx 160 else: 161 log.warning('Element `%s` is not valid at this point. ' \ 162 'Should compare before %s' % (name, 163 self.containers[self.parsing_pass])) 164 165 if self.parsing_pass == 0: 166 if type in attrs.keys(): 167 self.attr_type = attrs.get('type') 168 else: 169 self.attr_type = 'ui' 170 171 except ValueError: 172 log.debug('Element named `%s` not excepted.' % name) 173 174 def characters(self, ch): 175 if not self.current_element: 176 return 177 178 if not self.data: 179 self.data = ch 180 else: 181 self.data += ch 182 183 def endElement(self, name): 184 if self.current_element == name: 185 try: 186 attr = getattr(self, name) 187 188 if isinstance(attr, basestring): 189 setattr(self, name, self.data) 190 elif isinstance(attr, list): 191 attr.append(self.data) 192 finally: 193 self.current_element = None 194 self.data = None 195 196 class ManifestWriter(object): 197 def startElement(self, names, attrs): 198 self.depth_idx += 1 199 self.writer.characters(' ' * self.depth_idx) 200 self.writer.startElement(names, attrs) 201 202 def endElement(self, name): 203 self.writer.endElement(name) 204 self.writer.characters('\n') 205 self.depth_idx -= 1 206 207 def __init__(self, manifest): 208 assert isinstance(manifest, ManifestObject) 209 210 self.output = StringIO() 211 self.depth_idx = -1 212 self.manifest = manifest 213 self.writer = XMLGenerator(self.output, 'utf-8') 214 self.writer.startDocument() 215 216 attr_vals = { 217 'xmlns' : 'http://www.umitproject.org', 218 'xsi:schemaLocation' : 'http://www.umitproject.org UmitPlugins.xsd', 219 'xmlns:xsi' : 'http://www.w3.org/2001/XMLSchema-instance', 220 'type' : manifest.attr_type or 'ui' 221 } 222 223 self.startElement('UmitPlugin', AttributesImpl(attr_vals)), 224 self.writer.characters('\n') 225 226 # First phase saving 227 for elem in manifest.elements[0]: 228 self.add_element(elem) 229 230 # Runtime block 231 self.startElement('runtime', {}) 232 self.writer.characters('\n') 233 234 self.add_element('start_file') 235 self.add_element('update') 236 237 self.writer.characters(' ' * self.depth_idx) 238 self.endElement('runtime') 239 240 # Deptree block 241 if manifest.provide or manifest.need or manifest.conflict: 242 self.startElement('deptree', {}) 243 self.writer.characters('\n') 244 245 self.add_element('provide') 246 self.add_element('need') 247 self.add_element('conflict') 248 249 self.writer.characters(' ' * self.depth_idx) 250 self.endElement('deptree') 251 252 # Credits block 253 self.startElement('credits', {}) 254 self.writer.characters('\n') 255 256 for elem in manifest.elements[3]: 257 self.add_element(elem) 258 259 self.writer.characters(' ' * self.depth_idx) 260 self.endElement('credits') 261 262 self.endElement('UmitPlugin') 263 self.writer.endDocument() 264 265 def add_element(self, name): 266 value = getattr(self.manifest, name, None) 267 268 if not value: 269 return 270 271 if isinstance(value, basestring): 272 self.startElement(name, {}) 273 self.writer.characters(value) 274 self.endElement(name) 275 elif isinstance(value, list): 276 for item in value: 277 self.startElement(name, {}) 278 self.writer.characters(item) 279 self.endElement(name) 280 281 def get_output(self): 282 return self.output.getvalue() 76 283 77 284 class BadPlugin(Exception): … … 79 286 pass 80 287 81 class PluginReader( object):288 class PluginReader(ManifestLoader): 82 289 def __init__(self, file): 290 ManifestLoader.__init__(self) 291 83 292 self.path = file 84 293 self.enabled = False … … 88 297 try: 89 298 self.file = ZipFile(file, "r") 90 except BadZipfile:299 except: 91 300 raise BadPlugin("Not a valid umit plugin format") 92 301 93 302 if not self.parse_manifest(): 94 303 raise BadPlugin("Not a valid umit plugin manifest") 95 304 96 305 if not self.check_validity(): 97 306 raise BadPlugin("Validation phase not passed") … … 103 312 """ 104 313 Parse the Manifest.xml inside the zip file and set the fields 105 314 106 315 @return 107 316 False if the Manifest is not in the proper format 108 317 True if everything is ok 109 318 """ 110 319 111 320 try: 112 data = self.file.read("Manifest.xml") 113 doc = parseString(data) 114 except Exception: 321 # TODO: add validation of the manifest 322 323 # Py2.5 doesn't have open on ZipFile object 324 fileobj = StringIO(self.file.read('Manifest.xml')) 325 326 parser = make_parser() 327 parser.setContentHandler(self) 328 329 parser.parse(fileobj) 330 except Exception, err: 331 log.debug('Exception in parse_manifest(): %s' % str(err)) 115 332 return False 116 117 if doc.documentElement.tagName != SIGNATURE: 118 return False 119 120 for field in FIELDS: 121 setattr(self, field, "") 122 123 for node in doc.documentElement.childNodes: 124 if node.nodeName in FIELDS and node.firstChild: 125 if node.nodeName in ('needs', 'provides', 'conflicts'): 126 # Convert to list 127 data = node.firstChild.data 128 setattr(self, node.nodeName, \ 129 data.replace(" ", "").split(",")) 130 else: 131 setattr(self, node.nodeName, node.firstChild.data) 132 333 133 334 return True 134 335 … … 141 342 except Exception, err: 142 343 return 143 144 def check_validity(self): 145 """ 146 Checks the fields presents and validity 147 148 @return True if it's ok 149 """ 150 # TODO: implement me! 151 152 return True 153 344 154 345 def __repr__(self): 155 346 #FIXME: that … … 161 352 try: 162 353 # TODO: eliminate the mktemp workaround 163 354 164 355 name = mktemp('.png') 165 356 f = open(name, 'wb') … … 170 361 171 362 p = gtk.gdk.pixbuf_new_from_file_at_size(name, w, h) 172 363 173 364 os.remove(name) 174 365 … … 213 404 214 405 return ret 215 406 216 407 def extract_file(self, zip_path, keep_path=False): 217 408 if zip_path not in self.file.namelist(): … … 288 479 @return a catalog on success or None 289 480 """ 290 481 291 482 # We foreach inside locale dir and find a proper dir 292 483 293 484 try: 294 485 import gettext … … 304 495 if LANG is None: 305 496 LANG = "en_US" 306 307 # FIXME: is the '/' os indipendent? 497 308 498 dir_lst = filter( \ 309 499 lambda x: x.startswith("locale/") and x.endswith("%s.mo" % mofile), \ … … 313 503 314 504 avaiable_langs = [] 315 505 316 506 for dirname in dir_lst: 317 507 t = dirname.split("/") … … 319 509 if len(t) < 3: 320 510 continue 321 511 322 512 avaiable_langs.append(t[-2]) 323 513 … … 331 521 self.file.read("locale/%s/%s.mo" % (req, mofile)) \ 332 522 )) 333 523 334 524 return None 335 525 336 class PluginWriter( object):526 class PluginWriter(ManifestObject): 337 527 def __init__(self, **fields): 528 ManifestObject.__init__(self) 529 338 530 # Set to None and filter out the unused fields 339 340 for i in FIELDS: 341 setattr(self, i, "") 342 531 532 FIELDS = ('name', 'version', 'description', 'url', 'start_file', 533 'update', 'provide', 'need', 'conflict', 'license', 534 'copyright', 'author', 'contributor', 'translator', 'artist') 535 536 # Filter out fields that are not related to the schema 537 343 538 for i in fields: 344 539 if i in FIELDS: 345 540 setattr(self, i, fields[i]) 346 347 for i in FIELDS: 348 print "Field %s setted to %s" % (i, getattr(self, i)) 349 541 542 if not self.check_validity(use_print=True): 543 print "!! Manifest could not be created." 544 sys.exit(-1) 545 350 546 dirs = { 351 547 'bin' : '*', … … 354 550 'locale' : '*' 355 551 } 356 552 357 553 self.file = ZipFile(fields['output'], "w", ZIP_DEFLATED) 358 554 … … 363 559 364 560 os.chdir("..") 365 366 self.file.writestr("Manifest.xml", self.create_manifest()) 561 562 writer = ManifestWriter(self) 563 self.file.writestr('Manifest.xml', writer.get_output()) 367 564 self.file.close() 368 565 369 566 print ">> Plugin %s created." % fields['output'] 370 567 371 568 def dir_foreach(self, dir, pattern): 372 569 "Add files contained in dir and that pass the pattern validation phase." … … 375 572 if not files: 376 573 continue 377 574 378 575 for file in files: 379 576 if not fnmatch(file, pattern): … … 381 578 382 579 print "Adding file %s %s %s" % (path, file, dir) 383 580 384 581 self.file.write(os.path.join(path, file), 385 582 os.path.join(path, file)) 386 583 387 584 def create_manifest(self): 388 585 """ 389 586 Create a Manifest.xml file 390 587 391 588 @return an xml manifest as string 392 589 """ 393 590 doc = getDOMImplementation().createDocument(None, SIGNATURE, None) 394 591 395 592 for field in FIELDS: 396 593 node = doc.createElement(field) 397 594 node.appendChild(doc.createTextNode(getattr(self, field))) 398 595 doc.documentElement.appendChild(node) 399 596 400 597 print "Manifest.xml created" 401 598 return doc.toxml() … … 452 649 shutil.rmtree('build') 453 650 shutil.rmtree('output') 651 652 if __name__ == "__main__": 653 parser = make_parser() 654 loader = ManifestLoader() 655 parser.setContentHandler(loader) 656 parser.parse(open('test.xml')) 657 loader.dump()
