configurationengine/source/plugins/symbian/ConeGenconfmlPlugin/genconfmlplugin/genconfmlplugin.py
changeset 0 2e8eeb919028
child 3 e7e0ae78773e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/configurationengine/source/plugins/symbian/ConeGenconfmlPlugin/genconfmlplugin/genconfmlplugin.py	Thu Mar 11 17:04:37 2010 +0200
@@ -0,0 +1,401 @@
+#
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description: 
+#
+'''
+GenConfml plugin for ConE
+'''
+
+import re
+import os
+import sys
+import logging
+import xml.parsers.expat
+import confflattener
+import xslttransformer
+import codecs
+import tempfile
+import tempfile
+
+try:
+    from cElementTree import ElementTree
+except ImportError:
+    try:    
+        from elementtree import ElementTree
+    except ImportError:
+        try:
+            from xml.etree import cElementTree as ElementTree
+        except ImportError:
+            from xml.etree import ElementTree
+
+import __init__
+
+from cone.public import exceptions,plugin,utils,api
+from cone.confml import persistentconfml
+
+class GenconfmlImpl(plugin.ImplBase):
+    """
+    GenConfml plugin implementation
+    """
+    
+    IMPL_TYPE_ID = "gcfml"
+    
+    
+    def __init__(self,ref,configuration, output='output', linesep=os.linesep, reader=None):
+        """
+        Overloading the default constructor
+        """
+        plugin.ImplBase.__init__(self,ref,configuration)
+        self.logger = logging.getLogger('cone.gcfml(%s)' % self.ref)
+        self.errors = False
+        self.xstl_etree = None
+        self.xslt_temp_file_name = os.path.join(tempfile.gettempdir(), "genconfml_temp_%i.xslt" % os.getpid())
+        self.set_output_root(output)
+        self.linesep = linesep
+        self._flatconfig = None
+        self.temp_confml_file = os.path.join(tempfile.gettempdir(),'temp_flatted_%i.confml' % os.getpid())
+        self.reader = reader
+
+    def generate(self, context=None):
+        """
+        Generate the given implementation.
+        """
+        self.create_output()
+        return 
+    
+    def get_refs(self):
+        result = []
+        for ref in self.reader.settings:
+            # Process the reference, so that it will work with has_ref().
+            # E.g. 'MyFeature/MySetting' -> 'MyFeature.MySetting'
+            #      'MyFeature/*          -> 'MyFeature'
+            ref = ref.replace('/', '.')
+            if ref.endswith('.*'):
+                ref = ref[:-2]
+            result.append(ref)
+        return result
+      
+    def list_output_files(self):
+        """ Return a list of output files as an array. """
+        return [self.get_output_filename()]
+        
+    def get_output_filename(self):
+        """ Return a output file name. """
+        
+        name = self.reader.name
+        if name == None: name = ""
+        target = self.reader.target
+        if target == None: target = ""
+        output = self.output
+        if self.output == None: output = ""
+        
+        # Make sure that target file is generated under output
+        target = utils.resourceref.remove_begin_slash(utils.resourceref.norm(target))
+        subdir = self.reader.subdir
+        if subdir == None: 
+            self.output_subdir = subdir
+        output_file = os.path.normpath(os.path.join(output, target, name))
+        
+        return output_file
+    
+    def create_output(self, layers=None):
+        """ Generate all output """
+        resource = self.configuration.get_resource(self.ref)
+        write_element_enc(self.reader.stylesheet_elem, self.xslt_temp_file_name, self.reader.stylesheet_output_enc)
+        gen = Generator()
+        
+        target = self.reader.target
+        if target == None: target = ""
+        
+        output_file = self.get_output_filename()
+        # Don't create the dirs here, since the output file may be filtered out
+        # if it is empty
+        #if not os.path.exists(os.path.dirname(output_file)):
+        #    os.makedirs(os.path.dirname(output_file))
+        
+        self.logger.info('Generating %s' % output_file)
+        
+        flatted_conf_as_element = persistentconfml.ConfmlWriter().dumps(self.flatconfig)
+        postprocessed_element = self.post_process_flattening(flatted_conf_as_element)
+        write_element_enc(postprocessed_element, self.temp_confml_file, self.reader.stylesheet_output_enc)
+        gen.generate(self.configuration, resource, output_file, self.xslt_temp_file_name, self.reader.settings, self.reader.stylesheet_output_enc)
+      
+    def post_process_flattening(self, element):
+        """
+        Pick just data element and build document out of it
+        """
+        
+        data_element = element.find("data")
+        if data_element == None:
+            self.logger.warning('No data to generate!!')
+            new_doc = "<?xml version=\"1.0\"?><configuration>" + "</configuration>"
+        else:
+            new_doc = "<?xml version=\"1.0\"?><configuration>" + ElementTree.tostring(data_element) + "</configuration>"
+        return ElementTree.fromstring(new_doc)
+
+    @property
+    def flatconfig(self):
+      """ 
+      Create a flat configuration from the current configuration with the given setting refs.
+      Take the last configuration element, which will contain the data elements
+      """ 
+      if not self._flatconfig:
+          try:
+              cf = confflattener.ConfigurationFlattener()
+              self._flatconfig = api.Configuration()
+              cf.flat(self.configuration, self.reader.settings, self._flatconfig)
+          except (exceptions.ConeException, TypeError, Exception), e:
+              utils.log_exception(self.logger, 'Failed to flat configuration with settings %s. Exception: %s' % (self.reader.settings, e))
+              raise exceptions.ConeException('Failed to flat configuration. Exception: %s' % e)
+      return self._flatconfig
+
+
+def write_element(element, output, linesep=os.linesep):
+    """
+    """
+    if element != None and ElementTree.iselement(element):
+        enc = None
+        
+       
+        try:
+            out_file = open(output, 'w')
+            out_string = ElementTree.tostring(element)
+            out_string = out_string.replace('\r\n', linesep)
+            out_string = out_string.replace('\n', linesep)
+            out_file.write(out_string)
+            out_file.close()
+        except Exception, e:
+            raise exceptions.ConeException('Cannot write Element to file (%s). Exception: %s' % (output, e))
+    else:
+        raise exceptions.ConeException('Cannot write element to file, because None element passed or not Element passed.')
+    
+def remove_namespace(doc, namespace):
+    """Remove namespace in the passed document in place."""
+    ns = u'{%s}' % namespace
+    nsl = len(ns)
+    for elem in doc.getiterator():
+        if elem.tag.startswith(ns):
+            elem.tag = elem.tag[nsl:]
+
+def write_element_enc(element, output, enc, linesep=os.linesep):
+    """
+    Writes element to file
+    """
+    if element != None and ElementTree.iselement(element):
+        enc = None
+        
+       
+        try:
+            remove_namespace(element, 'http://www.s60.com/xml/genconfml/1')
+            
+            
+            out_file = codecs.open(output, 'w', enc)
+            output_string = ElementTree.tostring(element)
+            output_string = output_string.replace('\r\n', linesep)
+            output_string = output_string.replace('\n', linesep)
+            out_file.write(output_string)
+            out_file.close()
+        except Exception, e:
+            raise exceptions.ConeException('Cannot write Element to file (%s). Exception: %s' % (output, e))
+    else:
+        raise exceptions.ConeException('Cannot write element to file, because None element passed or not Element passed.')
+
+    
+def write_element_tempfile(element, tempfile):
+    """
+    Writes element to temp file
+    """
+    if element != None and ElementTree.iselement(element):
+        
+        try:
+            tempfile.write(ElementTree.tostring(element))
+        except Exception, e:
+            raise exceptions.ConeException('Cannot write Element to file (%s). Exception: %s' % (output, e))
+    else:
+        raise exceptions.ConeException('Cannot write element to file, because None element passed or not Element passed.')
+    
+class GenconfmlImplReader(plugin.ReaderBase):
+    """
+    Parses a single gcfml file
+    """ 
+    NAMESPACE = 'http://www.s60.com/xml/genconfml/1'
+    IGNORED_NAMESPACES = ['http://www.w3.org/1999/XSL/Transform', 
+                          'http://www.w3.org/2001/xinclude']
+    FILE_EXTENSIONS = ['gcfml']
+    
+    def __init__(self):
+        self.stylesheet = None
+        self.namespaces = self.IGNORED_NAMESPACES + [self.NAMESPACE]
+        self.settings = None
+        self.name = None
+        self.subdir = None
+        self.target = None
+        self.stylesheet_elem = None
+        self.stylesheet_output_enc = None
+        self.nss = None
+    
+    @classmethod
+    def read_impl(cls, resource_ref, configuration, etree):
+        
+        reader = GenconfmlImplReader()
+        reader.from_etree(etree)
+        return GenconfmlImpl(resource_ref, configuration, reader=reader)
+            
+    def from_etree(self, etree):
+        self.stylesheet = self.parse_stylesheet(etree)
+        self.settings = self.parse_settings(etree)
+        self.name = self.parse_name(etree)
+        self.subdir = self.parse_subdir(etree)        
+        self.target = self.parse_target(etree)
+        self.stylesheet_elem = self.parse_stylesheet_elem(etree)
+        self.stylesheet_output_enc = self.parse_stylesheet_output_enc(etree)
+        self.nss = self.parse_stylesheet_nss(etree)
+        
+        return
+
+    def parse_target(self, etree):
+        """
+        Parses target from etree
+        """
+        
+        target = ""
+        for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
+          if elem != None:
+              target = elem.get('target')
+        
+        return target
+    
+    def parse_name(self, etree):
+        """
+        Parses name from etree
+        """
+        
+        name = ""
+        for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
+          if elem != None:
+              name = elem.get('name')
+        
+        return name
+
+    def parse_subdir(self, etree):
+        """
+        Parses subdir from etree
+        """
+        
+        subdir = ""
+        for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
+          if elem != None:
+              subdir = elem.get('subdir')
+        if subdir == None:
+            subdir = ""
+        
+        return subdir
+
+        
+    def parse_stylesheet(self,etree):
+        """
+        Parses stylesheet from getree
+        """
+        
+        stylesheet = ""
+        stylesheet_elem = etree.find("{%s}stylesheet" % self.namespaces[0])
+        if stylesheet_elem != None:
+            stylesheet = ElementTree.tostring(stylesheet_elem)
+        return stylesheet
+
+    def parse_stylesheet_output_enc(self, etree):
+        enc = ""
+        ss_elem = etree.find("{%s}stylesheet" % self.namespaces[0])
+        if ss_elem != None:
+            children = ss_elem.getchildren()
+            for child in children:
+                if child.tag == '{%s}output' % self.namespaces[0]: 
+                    enc = child.attrib.get('encoding')
+        return enc
+
+    def parse_stylesheet_nss(self, etree):
+        nss = None
+        
+        for elem in etree.getiterator():
+            name = elem.tag
+            if name[0] == "{":
+                uri, tag = name[1:].split("}")
+                if tag == "stylesheet":
+                    nss = uri
+        return nss
+
+    def parse_stylesheet_elem(self,etree):
+        """
+        Parses stylesheet element from getree
+        """
+        
+        return etree.find("{%s}stylesheet" % self.namespaces[0])
+
+    def parse_settings(self,etree):
+        """
+        Parses settings from etree
+        """
+        
+        settings = []
+        
+        for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
+          if elem != None:
+              setting_elems = elem.findall("{%s}setting" % self.namespaces[2])
+              for setting_elem in setting_elems:
+                  if setting_elem != None:
+                      settings.append(setting_elem.get('ref'))
+        
+        return settings
+    
+class Generator(object):
+    """
+    Genconfml generator
+    """ 
+    def __init__(self):
+        self.temp_confml_file = os.path.join(tempfile.gettempdir(),'temp_flatted_%i.confml' % os.getpid())
+        pass
+
+    def post_process_flattening(self, element):
+        """
+        Pick just data element and build document out of it
+        """
+        
+        data_element = element.find("data")
+        if data_element == None:
+            self.logger.warning('No data to generate!!')
+            new_doc = "<?xml version=\"1.0\"?><configuration>" + "</configuration>"
+        else:
+            new_doc = "<?xml version=\"1.0\"?><configuration>" + ElementTree.tostring(data_element) + "</configuration>"
+        return ElementTree.fromstring(new_doc)
+
+
+    def generate(self, configuration, input, output, xslt, settings, enc=sys.getdefaultencoding()):
+        """
+        Generates output
+        """
+        self.logger = logging.getLogger('cone.gcfml{%s}' % input.path)
+
+        
+        try:
+            tf = xslttransformer.XsltTransformer()
+            tf.transform_lxml(os.path.abspath(self.temp_confml_file), os.path.abspath(xslt), output, enc)
+            #tf.transform_4s(os.path.abspath(self.temp_confml_file), os.path.abspath(xslt), output, enc)
+        except (exceptions.ConeException, TypeError, Exception), e:
+            logging.getLogger('cone.gcfml').warning('Failed to do XSLT tranformation. Exception: %s' % e)
+            raise exceptions.ConeException('Failed to do XSLT tranformation. Exception: %s' % e)
+
+        """ Removes template files """
+        if not logging.getLogger('cone').getEffectiveLevel() != 10:
+            os.remove(os.path.abspath(self.temp_confml_file))
+            os.remove(os.path.abspath(xslt))