configurationengine/source/plugins/symbian/ConeGenconfmlPlugin/genconfmlplugin/genconfmlplugin.py
changeset 0 2e8eeb919028
child 3 e7e0ae78773e
equal deleted inserted replaced
-1:000000000000 0:2e8eeb919028
       
     1 #
       
     2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description: 
       
    15 #
       
    16 '''
       
    17 GenConfml plugin for ConE
       
    18 '''
       
    19 
       
    20 import re
       
    21 import os
       
    22 import sys
       
    23 import logging
       
    24 import xml.parsers.expat
       
    25 import confflattener
       
    26 import xslttransformer
       
    27 import codecs
       
    28 import tempfile
       
    29 import tempfile
       
    30 
       
    31 try:
       
    32     from cElementTree import ElementTree
       
    33 except ImportError:
       
    34     try:    
       
    35         from elementtree import ElementTree
       
    36     except ImportError:
       
    37         try:
       
    38             from xml.etree import cElementTree as ElementTree
       
    39         except ImportError:
       
    40             from xml.etree import ElementTree
       
    41 
       
    42 import __init__
       
    43 
       
    44 from cone.public import exceptions,plugin,utils,api
       
    45 from cone.confml import persistentconfml
       
    46 
       
    47 class GenconfmlImpl(plugin.ImplBase):
       
    48     """
       
    49     GenConfml plugin implementation
       
    50     """
       
    51     
       
    52     IMPL_TYPE_ID = "gcfml"
       
    53     
       
    54     
       
    55     def __init__(self,ref,configuration, output='output', linesep=os.linesep, reader=None):
       
    56         """
       
    57         Overloading the default constructor
       
    58         """
       
    59         plugin.ImplBase.__init__(self,ref,configuration)
       
    60         self.logger = logging.getLogger('cone.gcfml(%s)' % self.ref)
       
    61         self.errors = False
       
    62         self.xstl_etree = None
       
    63         self.xslt_temp_file_name = os.path.join(tempfile.gettempdir(), "genconfml_temp_%i.xslt" % os.getpid())
       
    64         self.set_output_root(output)
       
    65         self.linesep = linesep
       
    66         self._flatconfig = None
       
    67         self.temp_confml_file = os.path.join(tempfile.gettempdir(),'temp_flatted_%i.confml' % os.getpid())
       
    68         self.reader = reader
       
    69 
       
    70     def generate(self, context=None):
       
    71         """
       
    72         Generate the given implementation.
       
    73         """
       
    74         self.create_output()
       
    75         return 
       
    76     
       
    77     def get_refs(self):
       
    78         result = []
       
    79         for ref in self.reader.settings:
       
    80             # Process the reference, so that it will work with has_ref().
       
    81             # E.g. 'MyFeature/MySetting' -> 'MyFeature.MySetting'
       
    82             #      'MyFeature/*          -> 'MyFeature'
       
    83             ref = ref.replace('/', '.')
       
    84             if ref.endswith('.*'):
       
    85                 ref = ref[:-2]
       
    86             result.append(ref)
       
    87         return result
       
    88       
       
    89     def list_output_files(self):
       
    90         """ Return a list of output files as an array. """
       
    91         return [self.get_output_filename()]
       
    92         
       
    93     def get_output_filename(self):
       
    94         """ Return a output file name. """
       
    95         
       
    96         name = self.reader.name
       
    97         if name == None: name = ""
       
    98         target = self.reader.target
       
    99         if target == None: target = ""
       
   100         output = self.output
       
   101         if self.output == None: output = ""
       
   102         
       
   103         # Make sure that target file is generated under output
       
   104         target = utils.resourceref.remove_begin_slash(utils.resourceref.norm(target))
       
   105         subdir = self.reader.subdir
       
   106         if subdir == None: 
       
   107             self.output_subdir = subdir
       
   108         output_file = os.path.normpath(os.path.join(output, target, name))
       
   109         
       
   110         return output_file
       
   111     
       
   112     def create_output(self, layers=None):
       
   113         """ Generate all output """
       
   114         resource = self.configuration.get_resource(self.ref)
       
   115         write_element_enc(self.reader.stylesheet_elem, self.xslt_temp_file_name, self.reader.stylesheet_output_enc)
       
   116         gen = Generator()
       
   117         
       
   118         target = self.reader.target
       
   119         if target == None: target = ""
       
   120         
       
   121         output_file = self.get_output_filename()
       
   122         # Don't create the dirs here, since the output file may be filtered out
       
   123         # if it is empty
       
   124         #if not os.path.exists(os.path.dirname(output_file)):
       
   125         #    os.makedirs(os.path.dirname(output_file))
       
   126         
       
   127         self.logger.info('Generating %s' % output_file)
       
   128         
       
   129         flatted_conf_as_element = persistentconfml.ConfmlWriter().dumps(self.flatconfig)
       
   130         postprocessed_element = self.post_process_flattening(flatted_conf_as_element)
       
   131         write_element_enc(postprocessed_element, self.temp_confml_file, self.reader.stylesheet_output_enc)
       
   132         gen.generate(self.configuration, resource, output_file, self.xslt_temp_file_name, self.reader.settings, self.reader.stylesheet_output_enc)
       
   133       
       
   134     def post_process_flattening(self, element):
       
   135         """
       
   136         Pick just data element and build document out of it
       
   137         """
       
   138         
       
   139         data_element = element.find("data")
       
   140         if data_element == None:
       
   141             self.logger.warning('No data to generate!!')
       
   142             new_doc = "<?xml version=\"1.0\"?><configuration>" + "</configuration>"
       
   143         else:
       
   144             new_doc = "<?xml version=\"1.0\"?><configuration>" + ElementTree.tostring(data_element) + "</configuration>"
       
   145         return ElementTree.fromstring(new_doc)
       
   146 
       
   147     @property
       
   148     def flatconfig(self):
       
   149       """ 
       
   150       Create a flat configuration from the current configuration with the given setting refs.
       
   151       Take the last configuration element, which will contain the data elements
       
   152       """ 
       
   153       if not self._flatconfig:
       
   154           try:
       
   155               cf = confflattener.ConfigurationFlattener()
       
   156               self._flatconfig = api.Configuration()
       
   157               cf.flat(self.configuration, self.reader.settings, self._flatconfig)
       
   158           except (exceptions.ConeException, TypeError, Exception), e:
       
   159               utils.log_exception(self.logger, 'Failed to flat configuration with settings %s. Exception: %s' % (self.reader.settings, e))
       
   160               raise exceptions.ConeException('Failed to flat configuration. Exception: %s' % e)
       
   161       return self._flatconfig
       
   162 
       
   163 
       
   164 def write_element(element, output, linesep=os.linesep):
       
   165     """
       
   166     """
       
   167     if element != None and ElementTree.iselement(element):
       
   168         enc = None
       
   169         
       
   170        
       
   171         try:
       
   172             out_file = open(output, 'w')
       
   173             out_string = ElementTree.tostring(element)
       
   174             out_string = out_string.replace('\r\n', linesep)
       
   175             out_string = out_string.replace('\n', linesep)
       
   176             out_file.write(out_string)
       
   177             out_file.close()
       
   178         except Exception, e:
       
   179             raise exceptions.ConeException('Cannot write Element to file (%s). Exception: %s' % (output, e))
       
   180     else:
       
   181         raise exceptions.ConeException('Cannot write element to file, because None element passed or not Element passed.')
       
   182     
       
   183 def remove_namespace(doc, namespace):
       
   184     """Remove namespace in the passed document in place."""
       
   185     ns = u'{%s}' % namespace
       
   186     nsl = len(ns)
       
   187     for elem in doc.getiterator():
       
   188         if elem.tag.startswith(ns):
       
   189             elem.tag = elem.tag[nsl:]
       
   190 
       
   191 def write_element_enc(element, output, enc, linesep=os.linesep):
       
   192     """
       
   193     Writes element to file
       
   194     """
       
   195     if element != None and ElementTree.iselement(element):
       
   196         enc = None
       
   197         
       
   198        
       
   199         try:
       
   200             remove_namespace(element, 'http://www.s60.com/xml/genconfml/1')
       
   201             
       
   202             
       
   203             out_file = codecs.open(output, 'w', enc)
       
   204             output_string = ElementTree.tostring(element)
       
   205             output_string = output_string.replace('\r\n', linesep)
       
   206             output_string = output_string.replace('\n', linesep)
       
   207             out_file.write(output_string)
       
   208             out_file.close()
       
   209         except Exception, e:
       
   210             raise exceptions.ConeException('Cannot write Element to file (%s). Exception: %s' % (output, e))
       
   211     else:
       
   212         raise exceptions.ConeException('Cannot write element to file, because None element passed or not Element passed.')
       
   213 
       
   214     
       
   215 def write_element_tempfile(element, tempfile):
       
   216     """
       
   217     Writes element to temp file
       
   218     """
       
   219     if element != None and ElementTree.iselement(element):
       
   220         
       
   221         try:
       
   222             tempfile.write(ElementTree.tostring(element))
       
   223         except Exception, e:
       
   224             raise exceptions.ConeException('Cannot write Element to file (%s). Exception: %s' % (output, e))
       
   225     else:
       
   226         raise exceptions.ConeException('Cannot write element to file, because None element passed or not Element passed.')
       
   227     
       
   228 class GenconfmlImplReader(plugin.ReaderBase):
       
   229     """
       
   230     Parses a single gcfml file
       
   231     """ 
       
   232     NAMESPACE = 'http://www.s60.com/xml/genconfml/1'
       
   233     IGNORED_NAMESPACES = ['http://www.w3.org/1999/XSL/Transform', 
       
   234                           'http://www.w3.org/2001/xinclude']
       
   235     FILE_EXTENSIONS = ['gcfml']
       
   236     
       
   237     def __init__(self):
       
   238         self.stylesheet = None
       
   239         self.namespaces = self.IGNORED_NAMESPACES + [self.NAMESPACE]
       
   240         self.settings = None
       
   241         self.name = None
       
   242         self.subdir = None
       
   243         self.target = None
       
   244         self.stylesheet_elem = None
       
   245         self.stylesheet_output_enc = None
       
   246         self.nss = None
       
   247     
       
   248     @classmethod
       
   249     def read_impl(cls, resource_ref, configuration, etree):
       
   250         
       
   251         reader = GenconfmlImplReader()
       
   252         reader.from_etree(etree)
       
   253         return GenconfmlImpl(resource_ref, configuration, reader=reader)
       
   254             
       
   255     def from_etree(self, etree):
       
   256         self.stylesheet = self.parse_stylesheet(etree)
       
   257         self.settings = self.parse_settings(etree)
       
   258         self.name = self.parse_name(etree)
       
   259         self.subdir = self.parse_subdir(etree)        
       
   260         self.target = self.parse_target(etree)
       
   261         self.stylesheet_elem = self.parse_stylesheet_elem(etree)
       
   262         self.stylesheet_output_enc = self.parse_stylesheet_output_enc(etree)
       
   263         self.nss = self.parse_stylesheet_nss(etree)
       
   264         
       
   265         return
       
   266 
       
   267     def parse_target(self, etree):
       
   268         """
       
   269         Parses target from etree
       
   270         """
       
   271         
       
   272         target = ""
       
   273         for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
       
   274           if elem != None:
       
   275               target = elem.get('target')
       
   276         
       
   277         return target
       
   278     
       
   279     def parse_name(self, etree):
       
   280         """
       
   281         Parses name from etree
       
   282         """
       
   283         
       
   284         name = ""
       
   285         for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
       
   286           if elem != None:
       
   287               name = elem.get('name')
       
   288         
       
   289         return name
       
   290 
       
   291     def parse_subdir(self, etree):
       
   292         """
       
   293         Parses subdir from etree
       
   294         """
       
   295         
       
   296         subdir = ""
       
   297         for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
       
   298           if elem != None:
       
   299               subdir = elem.get('subdir')
       
   300         if subdir == None:
       
   301             subdir = ""
       
   302         
       
   303         return subdir
       
   304 
       
   305         
       
   306     def parse_stylesheet(self,etree):
       
   307         """
       
   308         Parses stylesheet from getree
       
   309         """
       
   310         
       
   311         stylesheet = ""
       
   312         stylesheet_elem = etree.find("{%s}stylesheet" % self.namespaces[0])
       
   313         if stylesheet_elem != None:
       
   314             stylesheet = ElementTree.tostring(stylesheet_elem)
       
   315         return stylesheet
       
   316 
       
   317     def parse_stylesheet_output_enc(self, etree):
       
   318         enc = ""
       
   319         ss_elem = etree.find("{%s}stylesheet" % self.namespaces[0])
       
   320         if ss_elem != None:
       
   321             children = ss_elem.getchildren()
       
   322             for child in children:
       
   323                 if child.tag == '{%s}output' % self.namespaces[0]: 
       
   324                     enc = child.attrib.get('encoding')
       
   325         return enc
       
   326 
       
   327     def parse_stylesheet_nss(self, etree):
       
   328         nss = None
       
   329         
       
   330         for elem in etree.getiterator():
       
   331             name = elem.tag
       
   332             if name[0] == "{":
       
   333                 uri, tag = name[1:].split("}")
       
   334                 if tag == "stylesheet":
       
   335                     nss = uri
       
   336         return nss
       
   337 
       
   338     def parse_stylesheet_elem(self,etree):
       
   339         """
       
   340         Parses stylesheet element from getree
       
   341         """
       
   342         
       
   343         return etree.find("{%s}stylesheet" % self.namespaces[0])
       
   344 
       
   345     def parse_settings(self,etree):
       
   346         """
       
   347         Parses settings from etree
       
   348         """
       
   349         
       
   350         settings = []
       
   351         
       
   352         for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
       
   353           if elem != None:
       
   354               setting_elems = elem.findall("{%s}setting" % self.namespaces[2])
       
   355               for setting_elem in setting_elems:
       
   356                   if setting_elem != None:
       
   357                       settings.append(setting_elem.get('ref'))
       
   358         
       
   359         return settings
       
   360     
       
   361 class Generator(object):
       
   362     """
       
   363     Genconfml generator
       
   364     """ 
       
   365     def __init__(self):
       
   366         self.temp_confml_file = os.path.join(tempfile.gettempdir(),'temp_flatted_%i.confml' % os.getpid())
       
   367         pass
       
   368 
       
   369     def post_process_flattening(self, element):
       
   370         """
       
   371         Pick just data element and build document out of it
       
   372         """
       
   373         
       
   374         data_element = element.find("data")
       
   375         if data_element == None:
       
   376             self.logger.warning('No data to generate!!')
       
   377             new_doc = "<?xml version=\"1.0\"?><configuration>" + "</configuration>"
       
   378         else:
       
   379             new_doc = "<?xml version=\"1.0\"?><configuration>" + ElementTree.tostring(data_element) + "</configuration>"
       
   380         return ElementTree.fromstring(new_doc)
       
   381 
       
   382 
       
   383     def generate(self, configuration, input, output, xslt, settings, enc=sys.getdefaultencoding()):
       
   384         """
       
   385         Generates output
       
   386         """
       
   387         self.logger = logging.getLogger('cone.gcfml{%s}' % input.path)
       
   388 
       
   389         
       
   390         try:
       
   391             tf = xslttransformer.XsltTransformer()
       
   392             tf.transform_lxml(os.path.abspath(self.temp_confml_file), os.path.abspath(xslt), output, enc)
       
   393             #tf.transform_4s(os.path.abspath(self.temp_confml_file), os.path.abspath(xslt), output, enc)
       
   394         except (exceptions.ConeException, TypeError, Exception), e:
       
   395             logging.getLogger('cone.gcfml').warning('Failed to do XSLT tranformation. Exception: %s' % e)
       
   396             raise exceptions.ConeException('Failed to do XSLT tranformation. Exception: %s' % e)
       
   397 
       
   398         """ Removes template files """
       
   399         if not logging.getLogger('cone').getEffectiveLevel() != 10:
       
   400             os.remove(os.path.abspath(self.temp_confml_file))
       
   401             os.remove(os.path.abspath(xslt))