diff -r 000000000000 -r 2e8eeb919028 configurationengine/source/plugins/symbian/ConeGenconfmlPlugin/genconfmlplugin/genconfmlplugin.py --- /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 = "" + "" + else: + new_doc = "" + ElementTree.tostring(data_element) + "" + 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 = "" + "" + else: + new_doc = "" + ElementTree.tostring(data_element) + "" + 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))