configurationengine/source/plugins/symbian/ConeGenconfmlPlugin/genconfmlplugin/genconfmlplugin.py
changeset 3 e7e0ae78773e
parent 0 2e8eeb919028
equal deleted inserted replaced
2:87cfa131b535 3:e7e0ae78773e
    24 import xml.parsers.expat
    24 import xml.parsers.expat
    25 import confflattener
    25 import confflattener
    26 import xslttransformer
    26 import xslttransformer
    27 import codecs
    27 import codecs
    28 import tempfile
    28 import tempfile
       
    29 import pkg_resources
    29 import tempfile
    30 import tempfile
    30 
    31 
    31 try:
    32 try:
    32     from cElementTree import ElementTree
    33     from cElementTree import ElementTree
    33 except ImportError:
    34 except ImportError:
    37         try:
    38         try:
    38             from xml.etree import cElementTree as ElementTree
    39             from xml.etree import cElementTree as ElementTree
    39         except ImportError:
    40         except ImportError:
    40             from xml.etree import ElementTree
    41             from xml.etree import ElementTree
    41 
    42 
    42 import __init__
       
    43 
    43 
    44 from cone.public import exceptions,plugin,utils,api
    44 from cone.public import exceptions,plugin,utils,api
    45 from cone.confml import persistentconfml
    45 from cone.confml import persistentconfml
    46 
    46 
    47 class GenconfmlImpl(plugin.ImplBase):
    47 class GenconfmlImpl(plugin.ImplBase):
    50     """
    50     """
    51     
    51     
    52     IMPL_TYPE_ID = "gcfml"
    52     IMPL_TYPE_ID = "gcfml"
    53     
    53     
    54     
    54     
    55     def __init__(self,ref,configuration, output='output', linesep=os.linesep, reader=None):
    55     def __init__(self,ref,configuration, output='', linesep=os.linesep, reader=None):
    56         """
    56         """
    57         Overloading the default constructor
    57         Overloading the default constructor
    58         """
    58         """
    59         plugin.ImplBase.__init__(self,ref,configuration)
    59         plugin.ImplBase.__init__(self,ref,configuration)
    60         self.logger = logging.getLogger('cone.gcfml(%s)' % self.ref)
    60         self.logger = logging.getLogger('cone.gcfml(%s)' % self.ref)
    61         self.errors = False
    61         self.errors = False
    62         self.xstl_etree = None
    62         self.xstl_etree = None
    63         self.xslt_temp_file_name = os.path.join(tempfile.gettempdir(), "genconfml_temp_%i.xslt" % os.getpid())
    63         self.xslt_temp_file_name = os.path.join(tempfile.gettempdir(), "genconfml_temp_%i.xslt" % os.getpid())
    64         self.set_output_root(output)
    64         self.set_output_root(output)
    65         self.linesep = linesep
    65         self.linesep = linesep
    66         self._flatconfig = None
    66         self.flatconfig = None
    67         self.temp_confml_file = os.path.join(tempfile.gettempdir(),'temp_flatted_%i.confml' % os.getpid())
    67         self.temp_confml_file = os.path.join(tempfile.gettempdir(),'temp_flatted_%i.confml' % os.getpid())
    68         self.reader = reader
    68         self.reader = reader
    69 
    69 
    70     def generate(self, context=None):
    70     def generate(self, context=None):
    71         """
    71         """
    72         Generate the given implementation.
    72         Generate the given implementation.
    73         """
    73         """
       
    74         self.context = context
    74         self.create_output()
    75         self.create_output()
    75         return 
    76         return 
    76     
    77     
    77     def get_refs(self):
    78     def get_refs(self):
       
    79         """
       
    80         Get the list of references used inside this gcfml object.
       
    81         """
    78         result = []
    82         result = []
       
    83         refs = []
    79         for ref in self.reader.settings:
    84         for ref in self.reader.settings:
    80             # Process the reference, so that it will work with has_ref().
    85             # Process the reference, so that it will work with has_ref().
    81             # E.g. 'MyFeature/MySetting' -> 'MyFeature.MySetting'
    86             # E.g. 'MyFeature/MySetting' -> 'MyFeature.MySetting'
    82             #      'MyFeature/*          -> 'MyFeature'
    87             #      'MyFeature/*          -> 'MyFeature'
    83             ref = ref.replace('/', '.')
    88             ref = ref.replace('/', '.')
    84             if ref.endswith('.*'):
    89             refs.append(ref)
    85                 ref = ref[:-2]
    90             
    86             result.append(ref)
    91         # Traverse through actual features in the default view, to get a full list 
       
    92         # of refs in case of wildcard usage
       
    93         dview = self.configuration.get_default_view()
       
    94         for fea in dview.get_features(refs):
       
    95             result.append(fea.fqr)
    87         return result
    96         return result
    88       
    97       
    89     def list_output_files(self):
    98     def list_output_files(self):
    90         """ Return a list of output files as an array. """
    99         """ Return a list of output files as an array. """
    91         return [self.get_output_filename()]
   100         return [self.get_output_filename()]
   111     
   120     
   112     def create_output(self, layers=None):
   121     def create_output(self, layers=None):
   113         """ Generate all output """
   122         """ Generate all output """
   114         resource = self.configuration.get_resource(self.ref)
   123         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)
   124         write_element_enc(self.reader.stylesheet_elem, self.xslt_temp_file_name, self.reader.stylesheet_output_enc)
   116         gen = Generator()
   125         gen = Generator(self)
   117         
   126         
   118         target = self.reader.target
   127         target = self.reader.target
   119         if target == None: target = ""
   128         if target == None: target = ""
   120         
   129         
   121         output_file = self.get_output_filename()
   130         output_file = self.get_output_filename()
   124         #if not os.path.exists(os.path.dirname(output_file)):
   133         #if not os.path.exists(os.path.dirname(output_file)):
   125         #    os.makedirs(os.path.dirname(output_file))
   134         #    os.makedirs(os.path.dirname(output_file))
   126         
   135         
   127         self.logger.info('Generating %s' % output_file)
   136         self.logger.info('Generating %s' % output_file)
   128         
   137         
   129         flatted_conf_as_element = persistentconfml.ConfmlWriter().dumps(self.flatconfig)
   138         flatted_conf_as_element = persistentconfml.ConfmlWriter().dumps(self.get_flatconfig())
   130         postprocessed_element = self.post_process_flattening(flatted_conf_as_element)
   139         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)
   140         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)
   141         gen.generate(self.context, resource, output_file, self.xslt_temp_file_name, self.reader.settings, self.reader.stylesheet_output_enc,
       
   142                      line_ending_style = self.reader.line_ending_style)
       
   143 
   133       
   144       
   134     def post_process_flattening(self, element):
   145     def post_process_flattening(self, element):
   135         """
   146         """
   136         Pick just data element and build document out of it
   147         Pick just data element and build document out of it
   137         """
   148         """
   142             new_doc = "<?xml version=\"1.0\"?><configuration>" + "</configuration>"
   153             new_doc = "<?xml version=\"1.0\"?><configuration>" + "</configuration>"
   143         else:
   154         else:
   144             new_doc = "<?xml version=\"1.0\"?><configuration>" + ElementTree.tostring(data_element) + "</configuration>"
   155             new_doc = "<?xml version=\"1.0\"?><configuration>" + ElementTree.tostring(data_element) + "</configuration>"
   145         return ElementTree.fromstring(new_doc)
   156         return ElementTree.fromstring(new_doc)
   146 
   157 
   147     @property
   158     def get_flatconfig(self):
   148     def flatconfig(self):
   159         """ 
   149       """ 
   160         Create a flat configuration from the current configuration with the given setting refs.
   150       Create a flat configuration from the current configuration with the given setting refs.
   161         Take the last configuration element, which will contain the data elements
   151       Take the last configuration element, which will contain the data elements
   162         """ 
   152       """ 
   163         if not self.flatconfig:
   153       if not self._flatconfig:
   164             try:
   154           try:
   165                 cf = confflattener.ConfigurationFlattener()
   155               cf = confflattener.ConfigurationFlattener()
   166                 self.flatconfig = api.Configuration()
   156               self._flatconfig = api.Configuration()
   167                 cf.flat(self.configuration, self.reader.settings, self.flatconfig)
   157               cf.flat(self.configuration, self.reader.settings, self._flatconfig)
   168             except (exceptions.ConeException, TypeError, Exception), e:
   158           except (exceptions.ConeException, TypeError, Exception), e:
   169                 utils.log_exception(self.logger, 'Failed to flat configuration with settings %s. Exception: %s' % (self.reader.settings, e))
   159               utils.log_exception(self.logger, 'Failed to flat configuration with settings %s. Exception: %s' % (self.reader.settings, e))
   170                 raise exceptions.ConeException('Failed to flat configuration. Exception: %s' % e)
   160               raise exceptions.ConeException('Failed to flat configuration. Exception: %s' % e)
   171         return self.flatconfig
   161       return self._flatconfig
       
   162 
   172 
   163 
   173 
   164 def write_element(element, output, linesep=os.linesep):
   174 def write_element(element, output, linesep=os.linesep):
   165     """
   175     """
   166     """
   176     """
   219     if element != None and ElementTree.iselement(element):
   229     if element != None and ElementTree.iselement(element):
   220         
   230         
   221         try:
   231         try:
   222             tempfile.write(ElementTree.tostring(element))
   232             tempfile.write(ElementTree.tostring(element))
   223         except Exception, e:
   233         except Exception, e:
   224             raise exceptions.ConeException('Cannot write Element to file (%s). Exception: %s' % (output, e))
   234             raise exceptions.ConeException('Cannot write Element to file (%s). Exception: %s' % (tempfile, e))
   225     else:
   235     else:
   226         raise exceptions.ConeException('Cannot write element to file, because None element passed or not Element passed.')
   236         raise exceptions.ConeException('Cannot write element to file, because None element passed or not Element passed.')
   227     
   237     
   228 class GenconfmlImplReader(plugin.ReaderBase):
   238 class GenconfmlImplReader(plugin.ReaderBase):
   229     """
   239     """
   230     Parses a single gcfml file
   240     Parses a single gcfml file
   231     """ 
   241     """ 
   232     NAMESPACE = 'http://www.s60.com/xml/genconfml/1'
   242     NAMESPACE = 'http://www.s60.com/xml/genconfml/1'
       
   243     NAMESPACE_ID = 'gcfml'
       
   244     ROOT_ELEMENT_NAME = 'file'
   233     IGNORED_NAMESPACES = ['http://www.w3.org/1999/XSL/Transform', 
   245     IGNORED_NAMESPACES = ['http://www.w3.org/1999/XSL/Transform', 
   234                           'http://www.w3.org/2001/xinclude']
   246                           'http://www.w3.org/2001/xinclude']
   235     FILE_EXTENSIONS = ['gcfml']
   247     FILE_EXTENSIONS = ['gcfml']
   236     
   248     
   237     def __init__(self):
   249     def __init__(self):
   249     def read_impl(cls, resource_ref, configuration, etree):
   261     def read_impl(cls, resource_ref, configuration, etree):
   250         
   262         
   251         reader = GenconfmlImplReader()
   263         reader = GenconfmlImplReader()
   252         reader.from_etree(etree)
   264         reader.from_etree(etree)
   253         return GenconfmlImpl(resource_ref, configuration, reader=reader)
   265         return GenconfmlImpl(resource_ref, configuration, reader=reader)
   254             
   266     
       
   267     @classmethod
       
   268     def get_schema_data(cls):
       
   269         return pkg_resources.resource_string('genconfmlplugin', 'xsd/gcfml.xsd')
       
   270         
   255     def from_etree(self, etree):
   271     def from_etree(self, etree):
   256         self.stylesheet = self.parse_stylesheet(etree)
   272         self.stylesheet = self.parse_stylesheet(etree)
   257         self.settings = self.parse_settings(etree)
   273         self.settings = self.parse_settings(etree)
   258         self.name = self.parse_name(etree)
   274         self.target = etree.get('target', '')
   259         self.subdir = self.parse_subdir(etree)        
   275         self.name = etree.get('name', '')
   260         self.target = self.parse_target(etree)
   276         self.subdir = etree.get('subdir', '')
       
   277         self.line_ending_style = etree.get('lineEndingStyle')
   261         self.stylesheet_elem = self.parse_stylesheet_elem(etree)
   278         self.stylesheet_elem = self.parse_stylesheet_elem(etree)
   262         self.stylesheet_output_enc = self.parse_stylesheet_output_enc(etree)
   279         self.stylesheet_output_enc = self.parse_stylesheet_output_enc(etree)
   263         self.nss = self.parse_stylesheet_nss(etree)
   280         self.nss = self.parse_stylesheet_nss(etree)
   264         
   281         
       
   282         if self.line_ending_style not in (None, 'CRLF', 'LF'):
       
   283             raise exceptions.ImplmlParseError(
       
   284                 "Invalid line ending style '%s' (should be omitted or one "
       
   285                 "of ['CRLF', 'LF'])" % self.line_ending_style)
       
   286         
   265         return
   287         return
   266 
   288 
   267     def parse_target(self, etree):
   289     def parse_target(self, etree):
   268         """
   290         """
   269         Parses target from etree
   291         Parses target from etree
   270         """
   292         """
   271         
   293         
   272         target = ""
   294         target = ""
   273         for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
   295         for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
   274           if elem != None:
   296             if elem != None:
   275               target = elem.get('target')
   297                 target = elem.get('target')
   276         
   298         
   277         return target
   299         return target
   278     
   300     
   279     def parse_name(self, etree):
   301     def parse_name(self, etree):
   280         """
   302         """
   281         Parses name from etree
   303         Parses name from etree
   282         """
   304         """
   283         
   305         
   284         name = ""
   306         name = ""
   285         for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
   307         for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
   286           if elem != None:
   308             if elem != None:
   287               name = elem.get('name')
   309                 name = elem.get('name')
   288         
   310         
   289         return name
   311         return name
   290 
   312 
   291     def parse_subdir(self, etree):
   313     def parse_subdir(self, etree):
   292         """
   314         """
   293         Parses subdir from etree
   315         Parses subdir from etree
   294         """
   316         """
   295         
   317         
   296         subdir = ""
   318         subdir = ""
   297         for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
   319         for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
   298           if elem != None:
   320             if elem != None:
   299               subdir = elem.get('subdir')
   321                 subdir = elem.get('subdir')
   300         if subdir == None:
   322         if subdir == None:
   301             subdir = ""
   323             subdir = ""
   302         
   324         
   303         return subdir
   325         return subdir
   304 
   326 
   348         """
   370         """
   349         
   371         
   350         settings = []
   372         settings = []
   351         
   373         
   352         for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
   374         for elem in etree.getiterator("{%s}file" % self.namespaces[2]):
   353           if elem != None:
   375             if elem != None:
   354               setting_elems = elem.findall("{%s}setting" % self.namespaces[2])
   376                 setting_elems = elem.findall("{%s}setting" % self.namespaces[2])
   355               for setting_elem in setting_elems:
   377                 for setting_elem in setting_elems:
   356                   if setting_elem != None:
   378                     if setting_elem != None:
   357                       settings.append(setting_elem.get('ref'))
   379                         settings.append(setting_elem.get('ref'))
   358         
       
   359         return settings
   380         return settings
   360     
   381     
   361 class Generator(object):
   382 class Generator(object):
   362     """
   383     """
   363     Genconfml generator
   384     Genconfml generator
   364     """ 
   385     """ 
   365     def __init__(self):
   386     def __init__(self, implml):
   366         self.temp_confml_file = os.path.join(tempfile.gettempdir(),'temp_flatted_%i.confml' % os.getpid())
   387         self.temp_confml_file = os.path.join(tempfile.gettempdir(),'temp_flatted_%i.confml' % os.getpid())
   367         pass
   388         self.context = None
       
   389         self.implml = implml
   368 
   390 
   369     def post_process_flattening(self, element):
   391     def post_process_flattening(self, element):
   370         """
   392         """
   371         Pick just data element and build document out of it
   393         Pick just data element and build document out of it
   372         """
   394         """
   378         else:
   400         else:
   379             new_doc = "<?xml version=\"1.0\"?><configuration>" + ElementTree.tostring(data_element) + "</configuration>"
   401             new_doc = "<?xml version=\"1.0\"?><configuration>" + ElementTree.tostring(data_element) + "</configuration>"
   380         return ElementTree.fromstring(new_doc)
   402         return ElementTree.fromstring(new_doc)
   381 
   403 
   382 
   404 
   383     def generate(self, configuration, input, output, xslt, settings, enc=sys.getdefaultencoding()):
   405     def generate(self, context, input, output, xslt, settings, enc=sys.getdefaultencoding(),
       
   406                  line_ending_style=None):
   384         """
   407         """
   385         Generates output
   408         Generates output
   386         """
   409         """
       
   410         self.context = context
   387         self.logger = logging.getLogger('cone.gcfml{%s}' % input.path)
   411         self.logger = logging.getLogger('cone.gcfml{%s}' % input.path)
   388 
   412 
       
   413         if line_ending_style == 'LF':
       
   414             linesep = '\n'
       
   415         else:
       
   416             linesep = '\r\n'
   389         
   417         
   390         try:
   418         try:
   391             tf = xslttransformer.XsltTransformer()
   419             tf = xslttransformer.XsltTransformer()
   392             tf.transform_lxml(os.path.abspath(self.temp_confml_file), os.path.abspath(xslt), output, enc)
   420             result = tf.transform_lxml(os.path.abspath(self.temp_confml_file), os.path.abspath(xslt), enc, linesep)
   393             #tf.transform_4s(os.path.abspath(self.temp_confml_file), os.path.abspath(xslt), output, enc)
   421             if not self.filter_file_writing(result):
       
   422                 self.write_string_to_file(result, output, enc)
       
   423 
   394         except (exceptions.ConeException, TypeError, Exception), e:
   424         except (exceptions.ConeException, TypeError, Exception), e:
   395             logging.getLogger('cone.gcfml').warning('Failed to do XSLT tranformation. Exception: %s' % e)
   425             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)
   426             raise exceptions.ConeException('Failed to do XSLT tranformation. Exception: %s' % e)
   397 
   427 
   398         """ Removes template files """
   428         """ Removes template files """
   399         if not logging.getLogger('cone').getEffectiveLevel() != 10:
   429         if not logging.getLogger('cone').getEffectiveLevel() != 10:
   400             os.remove(os.path.abspath(self.temp_confml_file))
   430             os.remove(os.path.abspath(self.temp_confml_file))
   401             os.remove(os.path.abspath(xslt))
   431             os.remove(os.path.abspath(xslt))
       
   432 
       
   433     def filter_file_writing(self, string):
       
   434         """
       
   435         Returns True if writing result file should be ignored.
       
   436         """
       
   437         string = string.rstrip('\n\r')
       
   438         if string == '' or string == '<?xml version="1.0" encoding="UTF-16"?>' or \
       
   439             string == '<?xml version="1.0" encoding="UTF-8"?>':
       
   440             return True
       
   441         
       
   442         return False
       
   443 
       
   444     def write_string_to_file(self, string, output, enc):
       
   445         """
       
   446         Writes string to file
       
   447         """
       
   448         try:
       
   449             
       
   450             #fl = codecs.open(outfile, 'w', enc)
       
   451             fl = self.context.create_file(output, 
       
   452                                           implementation=self.implml,
       
   453                                           mode='w',
       
   454                                           encoding=enc)
       
   455             fl.write(string)
       
   456             fl.close()
       
   457             
       
   458         except Exception, e:
       
   459             logging.getLogger('cone.gcfml').error('Cannot write Element to file (%s). Exception: %s' % (output, e))
       
   460             raise exceptions.ConeException('Cannot write Element to file (%s). Exception: %s' % (output, e))