diff -r 87cfa131b535 -r e7e0ae78773e configurationengine/source/plugins/common/ConeTemplatePlugin/templatemlplugin/templatemlplugin.py --- a/configurationengine/source/plugins/common/ConeTemplatePlugin/templatemlplugin/templatemlplugin.py Fri Mar 12 08:30:17 2010 +0200 +++ b/configurationengine/source/plugins/common/ConeTemplatePlugin/templatemlplugin/templatemlplugin.py Tue Aug 10 14:29:28 2010 +0300 @@ -19,11 +19,10 @@ import re import os -import sys import logging import codecs -import xml.parsers.expat -from jinja2 import Environment, PackageLoader, FileSystemLoader, Template, DictLoader +import pkg_resources +from jinja2 import Environment, DictLoader import traceback try: from cElementTree import ElementTree @@ -47,10 +46,8 @@ except ImportError: from xml.etree import ElementInclude -import __init__ -from cone.public import exceptions,plugin,utils,api -from cone.confml import persistentconfml +from cone.public import exceptions,plugin,utils ROOT_PATH = os.path.dirname(os.path.abspath(__file__)) @@ -62,8 +59,7 @@ Implementation class of template plugin. """ - IMPL_TYPE_ID = "templateml" - + IMPL_TYPE_ID = "templateml" def __init__(self,ref,configuration, reader=None): """ @@ -75,24 +71,35 @@ self.reader = reader if self.reader and self.reader.tags: self.set_tags(self.reader.tags) + + def __getstate__(self): + state = super(TemplatemlImpl, self).__getstate__() + state['reader'] = self.reader + return state - def get_context(self): - if TemplatemlImpl.context == None: - TemplatemlImpl.context = self.create_dict() - - return TemplatemlImpl.context + def get_context(self, generation_context): + ddict = generation_context.impl_data_dict + if ddict.get('templateml_context', None) is None: + ddict['templateml_context'] = self.create_dict() + return ddict['templateml_context'] def generate(self, context=None): """ Generate the given implementation. """ - - self.create_output() + self.context = context + self.logger.debug('Generating from %s:%s' % (self.ref, self.lineno)) + self.create_output(context) return - def create_output(self, layers=None): - generator = Generator(self.reader.outputs, self.reader.filters, self.get_context(), self.configuration) - generator.generate(self.output, self.ref) + def create_output(self, generation_context): + templateml_context = self.get_context(generation_context) + templateml_context['gen_context'] = generation_context + if not generation_context.configuration: + generation_context.configuration = self.configuration + self.reader.expand_output_refs_by_default_view() + generator = Generator(self.reader.outputs, self.reader.filters, templateml_context, self) + generator.generate(generation_context, self.ref) return def get_refs(self): @@ -100,6 +107,22 @@ for output in self.reader.outputs: template = output.template.template refs.extend(self._extract_refs_from_template(template)) + refs_oa = self._extract_refs_from_output_attribs(output) + for r in refs_oa: + if refs.count(r) < 1: + refs.append(r) + return refs + + def _extract_refs_from_output_attribs(self, output): + refs = [] + pattern = re.compile(r'\$\{(.*)\}', re.UNICODE) + for key, value in vars(output).iteritems(): + m = pattern.search(str(value)) + if m: + ref = m.group(1) + refs.append(ref) + if key == 'ref': + refs.append(value) return refs @classmethod @@ -132,20 +155,19 @@ for output in self.reader.outputs: if re.search("feat_list.*", output.template.template) != None: return True - - refs_in_templates = self.get_refs() - - for ref in refs: - if ref in refs_in_templates: - return True - return False + return plugin.uses_ref(refs, self.get_refs()) def list_output_files(self): """ Return a list of output files as an array. """ result = [] for output in self.reader.outputs: - result.append(os.path.normpath(os.path.join(self.output, output.path, output.filename))) + filename = "" + if output.fearef != None: + filename = self.configuration.get_default_view().get_feature(output.fearef).value + else: + filename = output.filename + result.append(os.path.normpath(os.path.join(self.output, output.path, filename))) return result def create_dict(self): @@ -158,7 +180,7 @@ if self.configuration: dview = self.configuration.get_default_view() feat_list = [] - feat_tree = {} + feat_tree = FeatureDictProxy(None) def add_feature(feature, feature_dict): fea_dict = FeatureDictProxy(feature) @@ -202,7 +224,10 @@ Parses a single templateml file """ NAMESPACE = 'http://www.s60.com/xml/templateml/1' + NAMESPACE_ID = 'templateml' + ROOT_ELEMENT_NAME = 'templateml' FILE_EXTENSIONS = ['templateml'] + NEWLINE_WIN_PARSE_OPTIONS = ['win', 'windows', 'dos', 'symbian', 'symbianos', 'cr+lf', 'crlf'] def __init__(self, resource_ref=None, configuration=None): self.desc = None @@ -220,6 +245,10 @@ reader.from_elementtree(etree) return TemplatemlImpl(resource_ref, configuration, reader) + @classmethod + def get_schema_data(cls): + return pkg_resources.resource_string('templatemlplugin', 'xsd/templateml.xsd') + def fromstring(self, xml_string): etree = ElementTree.fromstring(xml_string) self.from_elementtree(etree) @@ -289,6 +318,7 @@ logging.getLogger('cone.templateml').warning("In template element file attribute and text defined. Using template found from file attribute.") template_text = _read_relative_file(self.configuration, file, self.resource_ref) tempfile.set_template(template_text) + return tempfile def parse_outputs(self, etree): @@ -297,51 +327,73 @@ for output_elem in output_elems: if output_elem != None: outputfile = OutputFile() + outputfile.set_output_elem(output_elem) if output_elem.get('encoding') != None: encoding = output_elem.get('encoding') - # Check the encoding - try: - codecs.lookup(encoding) - except LookupError: - raise exceptions.ParseError("Invalid output encoding: %s" % encoding) - - if self.configuration != None: - encoding = utils.expand_refs_by_default_view(encoding, self.configuration.get_default_view()) outputfile.set_encoding(encoding) if output_elem.get('file') != None: file = output_elem.get('file') - - if self.configuration != None: - file = utils.expand_refs_by_default_view(file, self.configuration.get_default_view()) outputfile.set_filename(file) if output_elem.get('dir') != None: dir = output_elem.get('dir') - if self.configuration != None: - dir = utils.expand_refs_by_default_view(dir, self.configuration.get_default_view()) outputfile.set_path(dir) if output_elem.get('ref'): # Fetch the output value from a configuration reference - fea = self.configuration.get_default_view().get_feature(output_elem.get('ref')) - outputfile.set_filename(fea.value) + outputfile.set_fearef(output_elem.get('ref')) if output_elem.get('bom'): - outputfile.bom = output_elem.get('bom').lower() in ('1', 'true', 't', 'yes', 'y') + outputfile.set_bom(output_elem.get('bom')) + if output_elem.get('newline', ''): + outputfile.set_newline(output_elem.get('newline', '')) + outputfile.set_template(self.parse_template(output_elem)) outputfile.set_filters(self.parse_filters(output_elem)) outputs.append(outputfile) + return outputs + def expand_output_refs_by_default_view(self): + for output in self.outputs: + if output.encoding: + if self.configuration != None: + output.set_encoding(utils.expand_refs_by_default_view(output.encoding, self.configuration.get_default_view())) + try: + codecs.lookup(output.encoding) + except LookupError: + raise exceptions.ParseError("Invalid output encoding: %s" % output.encoding) + if output.filename: + if self.configuration != None: + output.set_filename(utils.expand_refs_by_default_view(output.filename, self.configuration.get_default_view())) + if output.path: + if self.configuration != None: + output.set_path(utils.expand_refs_by_default_view(output.path, self.configuration.get_default_view())) + if output.newline: + newline = output.newline + if self.configuration != None: + newline = utils.expand_refs_by_default_view(output.newline, self.configuration.get_default_view()) + if newline.lower() in self.NEWLINE_WIN_PARSE_OPTIONS: + output.set_newline(OutputFile.NEWLINE_WIN) + if output.bom: + bom = output.bom + if self.configuration != None: + bom = utils.expand_refs_by_default_view(output.bom, self.configuration.get_default_view()) + output.bom = bom.lower() in ('1', 'true', 't', 'yes', 'y') + if output.fearef: + if self.configuration != None: + fea = self.configuration.get_default_view().get_feature(output.fearef) + output.set_filename(fea.value) + class Generator(object): """ Class that generates """ - def __init__(self, outputs, filters, context, configuration=None): + def __init__(self, outputs, filters, context, implementation=None): self.outputs = outputs self.filters = filters self.context = context - self.configuration = configuration + self.implementation = implementation - def generate(self, output_path, ref): + def generate(self, generation_context, ref): """ Generates output based on templates """ @@ -349,35 +401,37 @@ for output in self.outputs: try: - logging.getLogger('cone.templateml').debug(output) - out_path = os.path.abspath(os.path.join(output_path, output.path)) - if out_path != '': - if not os.path.exists(out_path): - os.makedirs(out_path) + out_path = output.path + out_filepath = os.path.join(out_path, output.filename) + logging.getLogger('cone.templateml').debug("Output file '%s', encoding '%s'" % (out_filepath, output.encoding)) - out_file = open(os.path.join(out_path, output.filename), 'wb') + out_file = generation_context.create_file(out_filepath, implementation=self.implementation) if output.template.path: - output.template.template = _read_relative_file(self.configuration, output.template.path, ref) + output.template.template = _read_relative_file(generation_context.configuration, output.template.path, ref) dict_loader = DictLoader({'template': output.template.template}) - env = Environment(loader=dict_loader) + + if output.newline == OutputFile.NEWLINE_WIN: + env = Environment(loader=dict_loader, newline_sequence='\r\n') + else: + env = Environment(loader=dict_loader) # Common filters for filter in self.filters: if filter.path: - filter.code = _read_relative_file(self.configuration, filter.path, ref) + filter.code = _read_relative_file(generation_context.configuration, filter.path, ref) if not filter.code: logging.getLogger('cone.templateml').warning("Skipping empty filter definition.") else: - env.filters[str(filter.name)] = eval(filter.code) + env.filters[str(filter.name)] = eval(filter.code.replace('\r', '')) # Output file specific filters for filter in output.filters: if filter.path: - filter.code = _read_relative_file(self.configuration, filter.path, ref) + filter.code = _read_relative_file(generation_context.configuration, filter.path, ref) if not filter.code: logging.getLogger('cone.templateml').warning("Skipping empty filter definition.") @@ -391,7 +445,9 @@ out_file.close() except Exception, e: - logging.getLogger('cone.templateml').error('Failed to generate template: %s %s\n%s' % (type(e), e, traceback.format_exc()) ) + utils.log_exception( + logging.getLogger('cone.templateml'), + '%r: Failed to generate output: %s: %s' % (self.implementation, type(e).__name__, e)) else: logging.getLogger('cone.templateml').info('No (valid) templates found.') @@ -426,6 +482,9 @@ class OutputFile(object): + NEWLINE_UNIX = "unix" + NEWLINE_WIN = "win" + def __init__(self): self.filename = '' self.path = '' @@ -433,6 +492,12 @@ self.template = TempFile() self.filters = [] self.bom = None + self.newline = self.NEWLINE_UNIX + self.fearef = None + self.output_elem = None + + def set_newline(self, newline): + self.newline = newline def set_filename(self, filename): self.filename = filename @@ -447,14 +512,24 @@ self.template = template def add_filter(self, filter): - self.filters.append(filters) + self.filters.append(filter) def set_filters(self, filters): self.filters = filters + def set_bom(self, bom): + self.bom = bom + + def set_fearef(self, ref): + self.fearef = ref + + def set_output_elem(self, output_elem): + self.output_elem = output_elem + def __eq__(self, other): - if (self.template == other.template and self.encoding == other.encoding and self.path == other.path and self.filename == other.filename and self.filters == other.filters): - return True + if other: + if (self.template == other.template and self.newline == other.newline and self.encoding == other.encoding and self.path == other.path and self.filename == other.filename and self.filters == other.filters): + return True return False def __repr__(self): @@ -483,16 +558,13 @@ self.filters.append(Filter(name, code)) def __eq__(self, other): - if self.template == other.template and self.filters == other.filters and self.extensions == other.extensions and self.path == other.path: - return True + if other: + if self.template == other.template and self.filters == other.filters and self.extensions == other.extensions and self.path == other.path: + return True return False + class Filter(object): - def __init__(self, name, code): - self.name = name - self.code = code - self.path = None - def __init__(self): self.name = None self.code = None @@ -522,14 +594,15 @@ self._children = {} def _get_dict(self): - result = { - '_name' : self._feature.name, - '_namespace' : self._feature.namespace, - '_value' : self._feature.get_value(), - '_fqr' : self._feature.fqr, - '_type' : self._feature.type} - for ref, obj in self._children.iteritems(): - result[ref] = obj + result = {} + if self._feature is not None: + result.update({ + '_name' : self._feature.name, + '_namespace' : self._feature.namespace, + '_value' : self._feature.get_value(), + '_fqr' : self._feature.fqr, + '_type' : self._feature.type}) + result.update(self._children) return result def items(self): @@ -539,12 +612,21 @@ return self._get_dict().iteritems() def __getitem__(self, name): - if name == '_name': return self._feature.name - elif name == '_namespace': return self._feature.namespace - elif name == '_value': return self._feature.get_value() - elif name == '_fqr': return self._feature.fqr - elif name == '_type': return self._feature.type - else: return self._children[name] + if self._feature is not None: + if name == '_name': return self._feature.name + elif name == '_namespace': return self._feature.namespace + elif name == '_value': return self._feature.get_value() + elif name == '_fqr': return self._feature.fqr + elif name == '_type': return self._feature.type + + try: + return self._children[name] + except KeyError: + if self._feature: + msg = "Feature '%s.%s' not found" % (self._feature.fqr, name) + else: + msg = "Feature '%s' not found" % name + raise exceptions.NotFound(msg) def __setitem__(self, name, value): self._children[name] = value