Show
Ignore:
Timestamp:
06/29/09 18:05:30 (4 years ago)
Author:
cassiano
Message:

Merged revisions 4909,4930-4932,4934-4935 via svnmerge from
http://svn.umitproject.org/svnroot/umit/trunk

................

r4909 | nopper | 2009-06-22 11:55:24 -0300 (Mon, 22 Jun 2009) | 21 lines


Merged revisions 4781-4783,4908 via svnmerge from
http://svn.umitproject.org/svnroot/umit/branch/UmitPlugins


........

r4781 | nopper | 2009-05-08 21:26:32 +0200 (ven, 08 mag 2009) | 1 line


Switching to new schema see UmitPlugins.xsd in PM branch. Switched also from xml.minidom to sax to speed up things.

........

r4782 | nopper | 2009-05-09 16:11:38 +0200 (sab, 09 mag 2009) | 1 line


Switched update process to new xml schema file.

........

r4783 | nopper | 2009-05-09 17:02:06 +0200 (sab, 09 mag 2009) | 1 line


Updating documentation to the new schema

........

r4908 | nopper | 2009-06-22 16:43:59 +0200 (lun, 22 giu 2009) | 1 line


Fixing a typo

........

................

r4930 | luis | 2009-06-27 11:33:59 -0300 (Sat, 27 Jun 2009) | 1 line


Fixing #334 - import error when umit is installed from package

................

r4931 | luis | 2009-06-27 22:38:54 -0300 (Sat, 27 Jun 2009) | 1 line


Fixed #331 - Permission denied writing umit config file

................

r4932 | luis | 2009-06-27 23:09:05 -0300 (Sat, 27 Jun 2009) | 1 line


Typo in Flow Analyzer plugin

................

r4934 | luis | 2009-06-27 23:30:31 -0300 (Sat, 27 Jun 2009) | 3 lines


Initialized merge tracking via "svnmerge" with revisions "1-4699" from
http://svn.umitproject.org/svnroot/umit/branch/radialnet

................

r4935 | ignotus | 2009-06-27 23:54:28 -0300 (Sat, 27 Jun 2009) | 3 lines


Fix accents problem in header.

................

Location:
branch/QuickScan
Files:
2 modified

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  
    2121import os 
    2222import os.path 
     23import sys 
    2324 
    2425from fnmatch import fnmatch 
    2526from zipfile import ZipFile, BadZipfile, ZIP_DEFLATED 
    26 from xml.dom.minidom import parseString, getDOMImplementation 
     27 
     28from StringIO import StringIO 
     29 
     30from xml.sax import handler, make_parser 
     31from xml.sax.saxutils import XMLGenerator 
     32from xml.sax.xmlreader import AttributesImpl 
     33 
    2734from tempfile import mktemp 
    2835 
     
    5562import shutil 
    5663 
    57 # FIXME: add others fields 
    58 FIELDS = ( 
    59     "url", 
    60     "conflicts", 
    61     "provides", 
    62     "needs", 
    63     "type", 
    64     "start_file", 
    65     "name", 
    66     "version", # only a convenient field 
    67     "description", 
    68     "author", 
    69     "license", 
    70     "artist", 
    71     "copyright", 
    72     "update" 
    73 ) 
    74  
    7564SIGNATURE = "UmitPlugin" 
     65 
     66class 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 
     135class 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 
     196class 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() 
    76283 
    77284class BadPlugin(Exception): 
     
    79286    pass 
    80287 
    81 class PluginReader(object): 
     288class PluginReader(ManifestLoader): 
    82289    def __init__(self, file): 
     290        ManifestLoader.__init__(self) 
     291 
    83292        self.path = file 
    84293        self.enabled = False 
     
    88297        try: 
    89298            self.file = ZipFile(file, "r") 
    90         except BadZipfile: 
     299        except: 
    91300            raise BadPlugin("Not a valid umit plugin format") 
    92          
     301 
    93302        if not self.parse_manifest(): 
    94303            raise BadPlugin("Not a valid umit plugin manifest") 
    95          
     304 
    96305        if not self.check_validity(): 
    97306            raise BadPlugin("Validation phase not passed") 
     
    103312        """ 
    104313        Parse the Manifest.xml inside the zip file and set the fields 
    105          
     314 
    106315        @return 
    107316                False if the Manifest is not in the proper format 
    108317                True if everything is ok 
    109318        """ 
    110          
     319 
    111320        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)) 
    115332            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 
    133334        return True 
    134335 
     
    141342        except Exception, err: 
    142343            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 
    154345    def __repr__(self): 
    155346        #FIXME: that 
     
    161352        try: 
    162353            # TODO: eliminate the mktemp workaround 
    163              
     354 
    164355            name = mktemp('.png') 
    165356            f = open(name, 'wb') 
     
    170361 
    171362            p = gtk.gdk.pixbuf_new_from_file_at_size(name, w, h) 
    172              
     363 
    173364            os.remove(name) 
    174365 
     
    213404 
    214405        return ret 
    215          
     406 
    216407    def extract_file(self, zip_path, keep_path=False): 
    217408        if zip_path not in self.file.namelist(): 
     
    288479        @return a catalog on success or None 
    289480        """ 
    290          
     481 
    291482        # We foreach inside locale dir and find a proper dir 
    292          
     483 
    293484        try: 
    294485            import gettext 
     
    304495        if LANG is None: 
    305496            LANG = "en_US" 
    306          
    307         # FIXME: is the '/' os indipendent? 
     497 
    308498        dir_lst = filter( \ 
    309499            lambda x: x.startswith("locale/") and x.endswith("%s.mo" % mofile), \ 
     
    313503 
    314504        avaiable_langs = [] 
    315          
     505 
    316506        for dirname in dir_lst: 
    317507            t = dirname.split("/") 
     
    319509            if len(t) < 3: 
    320510                continue 
    321              
     511 
    322512            avaiable_langs.append(t[-2]) 
    323513 
     
    331521                    self.file.read("locale/%s/%s.mo" % (req, mofile)) \ 
    332522                )) 
    333              
     523 
    334524        return None 
    335525 
    336 class PluginWriter(object): 
     526class PluginWriter(ManifestObject): 
    337527    def __init__(self, **fields): 
     528        ManifestObject.__init__(self) 
     529 
    338530        # 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 
    343538        for i in fields: 
    344539            if i in FIELDS: 
    345540                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 
    350546        dirs = { 
    351547            'bin'  : '*', 
     
    354550            'locale' : '*' 
    355551        } 
    356          
     552 
    357553        self.file = ZipFile(fields['output'], "w", ZIP_DEFLATED) 
    358554 
     
    363559 
    364560        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()) 
    367564        self.file.close() 
    368          
     565 
    369566        print ">> Plugin %s created." % fields['output'] 
    370      
     567 
    371568    def dir_foreach(self, dir, pattern): 
    372569        "Add files contained in dir and that pass the pattern validation phase." 
     
    375572            if not files: 
    376573                continue 
    377              
     574 
    378575            for file in files: 
    379576                if not fnmatch(file, pattern): 
     
    381578 
    382579                print "Adding file %s %s %s" % (path, file, dir) 
    383                  
     580 
    384581                self.file.write(os.path.join(path, file), 
    385582                                os.path.join(path, file)) 
    386      
     583 
    387584    def create_manifest(self): 
    388585        """ 
    389586        Create a Manifest.xml file 
    390          
     587 
    391588        @return an xml manifest as string 
    392589        """ 
    393590        doc = getDOMImplementation().createDocument(None, SIGNATURE, None) 
    394          
     591 
    395592        for field in FIELDS: 
    396593            node = doc.createElement(field) 
    397594            node.appendChild(doc.createTextNode(getattr(self, field))) 
    398595            doc.documentElement.appendChild(node) 
    399          
     596 
    400597        print "Manifest.xml created" 
    401598        return doc.toxml() 
     
    452649    shutil.rmtree('build') 
    453650    shutil.rmtree('output') 
     651 
     652if __name__ == "__main__": 
     653    parser = make_parser() 
     654    loader = ManifestLoader() 
     655    parser.setContentHandler(loader) 
     656    parser.parse(open('test.xml')) 
     657    loader.dump()