73 self.logger = logging.getLogger('cone.templateml(%s)' % self.ref) |
69 self.logger = logging.getLogger('cone.templateml(%s)' % self.ref) |
74 self.errors = False |
70 self.errors = False |
75 self.reader = reader |
71 self.reader = reader |
76 if self.reader and self.reader.tags: |
72 if self.reader and self.reader.tags: |
77 self.set_tags(self.reader.tags) |
73 self.set_tags(self.reader.tags) |
78 |
74 |
79 def get_context(self): |
75 def __getstate__(self): |
80 if TemplatemlImpl.context == None: |
76 state = super(TemplatemlImpl, self).__getstate__() |
81 TemplatemlImpl.context = self.create_dict() |
77 state['reader'] = self.reader |
82 |
78 return state |
83 return TemplatemlImpl.context |
79 |
|
80 def get_context(self, generation_context): |
|
81 ddict = generation_context.impl_data_dict |
|
82 if ddict.get('templateml_context', None) is None: |
|
83 ddict['templateml_context'] = self.create_dict() |
|
84 return ddict['templateml_context'] |
84 |
85 |
85 def generate(self, context=None): |
86 def generate(self, context=None): |
86 """ |
87 """ |
87 Generate the given implementation. |
88 Generate the given implementation. |
88 """ |
89 """ |
89 |
90 self.context = context |
90 self.create_output() |
91 self.logger.debug('Generating from %s:%s' % (self.ref, self.lineno)) |
|
92 self.create_output(context) |
91 return |
93 return |
92 |
94 |
93 def create_output(self, layers=None): |
95 def create_output(self, generation_context): |
94 generator = Generator(self.reader.outputs, self.reader.filters, self.get_context(), self.configuration) |
96 templateml_context = self.get_context(generation_context) |
95 generator.generate(self.output, self.ref) |
97 templateml_context['gen_context'] = generation_context |
|
98 if not generation_context.configuration: |
|
99 generation_context.configuration = self.configuration |
|
100 self.reader.expand_output_refs_by_default_view() |
|
101 generator = Generator(self.reader.outputs, self.reader.filters, templateml_context, self) |
|
102 generator.generate(generation_context, self.ref) |
96 return |
103 return |
97 |
104 |
98 def get_refs(self): |
105 def get_refs(self): |
99 refs = [] |
106 refs = [] |
100 for output in self.reader.outputs: |
107 for output in self.reader.outputs: |
101 template = output.template.template |
108 template = output.template.template |
102 refs.extend(self._extract_refs_from_template(template)) |
109 refs.extend(self._extract_refs_from_template(template)) |
|
110 refs_oa = self._extract_refs_from_output_attribs(output) |
|
111 for r in refs_oa: |
|
112 if refs.count(r) < 1: |
|
113 refs.append(r) |
|
114 return refs |
|
115 |
|
116 def _extract_refs_from_output_attribs(self, output): |
|
117 refs = [] |
|
118 pattern = re.compile(r'\$\{(.*)\}', re.UNICODE) |
|
119 for key, value in vars(output).iteritems(): |
|
120 m = pattern.search(str(value)) |
|
121 if m: |
|
122 ref = m.group(1) |
|
123 refs.append(ref) |
|
124 if key == 'ref': |
|
125 refs.append(value) |
103 return refs |
126 return refs |
104 |
127 |
105 @classmethod |
128 @classmethod |
106 def _extract_refs_from_template(cls, template_text): |
129 def _extract_refs_from_template(cls, template_text): |
107 refs = [] |
130 refs = [] |
287 file = template_elem.get('file') |
316 file = template_elem.get('file') |
288 if template_elem.text != None: |
317 if template_elem.text != None: |
289 logging.getLogger('cone.templateml').warning("In template element file attribute and text defined. Using template found from file attribute.") |
318 logging.getLogger('cone.templateml').warning("In template element file attribute and text defined. Using template found from file attribute.") |
290 template_text = _read_relative_file(self.configuration, file, self.resource_ref) |
319 template_text = _read_relative_file(self.configuration, file, self.resource_ref) |
291 tempfile.set_template(template_text) |
320 tempfile.set_template(template_text) |
|
321 |
292 return tempfile |
322 return tempfile |
293 |
323 |
294 def parse_outputs(self, etree): |
324 def parse_outputs(self, etree): |
295 outputs = [] |
325 outputs = [] |
296 output_elems = etree.findall("{%s}output" % self.namespaces[0]) |
326 output_elems = etree.findall("{%s}output" % self.namespaces[0]) |
297 for output_elem in output_elems: |
327 for output_elem in output_elems: |
298 if output_elem != None: |
328 if output_elem != None: |
299 outputfile = OutputFile() |
329 outputfile = OutputFile() |
|
330 outputfile.set_output_elem(output_elem) |
300 if output_elem.get('encoding') != None: |
331 if output_elem.get('encoding') != None: |
301 encoding = output_elem.get('encoding') |
332 encoding = output_elem.get('encoding') |
302 # Check the encoding |
|
303 try: |
|
304 codecs.lookup(encoding) |
|
305 except LookupError: |
|
306 raise exceptions.ParseError("Invalid output encoding: %s" % encoding) |
|
307 |
|
308 if self.configuration != None: |
|
309 encoding = utils.expand_refs_by_default_view(encoding, self.configuration.get_default_view()) |
|
310 outputfile.set_encoding(encoding) |
333 outputfile.set_encoding(encoding) |
311 if output_elem.get('file') != None: |
334 if output_elem.get('file') != None: |
312 file = output_elem.get('file') |
335 file = output_elem.get('file') |
313 |
|
314 if self.configuration != None: |
|
315 file = utils.expand_refs_by_default_view(file, self.configuration.get_default_view()) |
|
316 outputfile.set_filename(file) |
336 outputfile.set_filename(file) |
317 if output_elem.get('dir') != None: |
337 if output_elem.get('dir') != None: |
318 dir = output_elem.get('dir') |
338 dir = output_elem.get('dir') |
319 if self.configuration != None: |
|
320 dir = utils.expand_refs_by_default_view(dir, self.configuration.get_default_view()) |
|
321 outputfile.set_path(dir) |
339 outputfile.set_path(dir) |
322 if output_elem.get('ref'): |
340 if output_elem.get('ref'): |
323 # Fetch the output value from a configuration reference |
341 # Fetch the output value from a configuration reference |
324 fea = self.configuration.get_default_view().get_feature(output_elem.get('ref')) |
342 outputfile.set_fearef(output_elem.get('ref')) |
325 outputfile.set_filename(fea.value) |
|
326 if output_elem.get('bom'): |
343 if output_elem.get('bom'): |
327 outputfile.bom = output_elem.get('bom').lower() in ('1', 'true', 't', 'yes', 'y') |
344 outputfile.set_bom(output_elem.get('bom')) |
|
345 if output_elem.get('newline', ''): |
|
346 outputfile.set_newline(output_elem.get('newline', '')) |
|
347 |
328 outputfile.set_template(self.parse_template(output_elem)) |
348 outputfile.set_template(self.parse_template(output_elem)) |
329 outputfile.set_filters(self.parse_filters(output_elem)) |
349 outputfile.set_filters(self.parse_filters(output_elem)) |
330 outputs.append(outputfile) |
350 outputs.append(outputfile) |
|
351 |
331 return outputs |
352 return outputs |
332 |
353 |
|
354 def expand_output_refs_by_default_view(self): |
|
355 for output in self.outputs: |
|
356 if output.encoding: |
|
357 if self.configuration != None: |
|
358 output.set_encoding(utils.expand_refs_by_default_view(output.encoding, self.configuration.get_default_view())) |
|
359 try: |
|
360 codecs.lookup(output.encoding) |
|
361 except LookupError: |
|
362 raise exceptions.ParseError("Invalid output encoding: %s" % output.encoding) |
|
363 if output.filename: |
|
364 if self.configuration != None: |
|
365 output.set_filename(utils.expand_refs_by_default_view(output.filename, self.configuration.get_default_view())) |
|
366 if output.path: |
|
367 if self.configuration != None: |
|
368 output.set_path(utils.expand_refs_by_default_view(output.path, self.configuration.get_default_view())) |
|
369 if output.newline: |
|
370 newline = output.newline |
|
371 if self.configuration != None: |
|
372 newline = utils.expand_refs_by_default_view(output.newline, self.configuration.get_default_view()) |
|
373 if newline.lower() in self.NEWLINE_WIN_PARSE_OPTIONS: |
|
374 output.set_newline(OutputFile.NEWLINE_WIN) |
|
375 if output.bom: |
|
376 bom = output.bom |
|
377 if self.configuration != None: |
|
378 bom = utils.expand_refs_by_default_view(output.bom, self.configuration.get_default_view()) |
|
379 output.bom = bom.lower() in ('1', 'true', 't', 'yes', 'y') |
|
380 if output.fearef: |
|
381 if self.configuration != None: |
|
382 fea = self.configuration.get_default_view().get_feature(output.fearef) |
|
383 output.set_filename(fea.value) |
|
384 |
333 class Generator(object): |
385 class Generator(object): |
334 """ |
386 """ |
335 Class that generates |
387 Class that generates |
336 """ |
388 """ |
337 |
389 |
338 def __init__(self, outputs, filters, context, configuration=None): |
390 def __init__(self, outputs, filters, context, implementation=None): |
339 self.outputs = outputs |
391 self.outputs = outputs |
340 self.filters = filters |
392 self.filters = filters |
341 self.context = context |
393 self.context = context |
342 self.configuration = configuration |
394 self.implementation = implementation |
343 |
395 |
344 def generate(self, output_path, ref): |
396 def generate(self, generation_context, ref): |
345 """ |
397 """ |
346 Generates output based on templates |
398 Generates output based on templates |
347 """ |
399 """ |
348 if self.outputs != None: |
400 if self.outputs != None: |
349 |
401 |
350 for output in self.outputs: |
402 for output in self.outputs: |
351 try: |
403 try: |
352 logging.getLogger('cone.templateml').debug(output) |
404 out_path = output.path |
353 out_path = os.path.abspath(os.path.join(output_path, output.path)) |
405 out_filepath = os.path.join(out_path, output.filename) |
354 if out_path != '': |
406 logging.getLogger('cone.templateml').debug("Output file '%s', encoding '%s'" % (out_filepath, output.encoding)) |
355 if not os.path.exists(out_path): |
407 |
356 os.makedirs(out_path) |
408 out_file = generation_context.create_file(out_filepath, implementation=self.implementation) |
357 |
|
358 out_file = open(os.path.join(out_path, output.filename), 'wb') |
|
359 |
409 |
360 if output.template.path: |
410 if output.template.path: |
361 output.template.template = _read_relative_file(self.configuration, output.template.path, ref) |
411 output.template.template = _read_relative_file(generation_context.configuration, output.template.path, ref) |
362 |
412 |
363 dict_loader = DictLoader({'template': output.template.template}) |
413 dict_loader = DictLoader({'template': output.template.template}) |
364 env = Environment(loader=dict_loader) |
414 |
|
415 if output.newline == OutputFile.NEWLINE_WIN: |
|
416 env = Environment(loader=dict_loader, newline_sequence='\r\n') |
|
417 else: |
|
418 env = Environment(loader=dict_loader) |
365 |
419 |
366 # Common filters |
420 # Common filters |
367 for filter in self.filters: |
421 for filter in self.filters: |
368 |
422 |
369 if filter.path: |
423 if filter.path: |
370 filter.code = _read_relative_file(self.configuration, filter.path, ref) |
424 filter.code = _read_relative_file(generation_context.configuration, filter.path, ref) |
|
425 |
|
426 if not filter.code: |
|
427 logging.getLogger('cone.templateml').warning("Skipping empty filter definition.") |
|
428 else: |
|
429 env.filters[str(filter.name)] = eval(filter.code.replace('\r', '')) |
|
430 |
|
431 # Output file specific filters |
|
432 for filter in output.filters: |
|
433 if filter.path: |
|
434 filter.code = _read_relative_file(generation_context.configuration, filter.path, ref) |
371 |
435 |
372 if not filter.code: |
436 if not filter.code: |
373 logging.getLogger('cone.templateml').warning("Skipping empty filter definition.") |
437 logging.getLogger('cone.templateml').warning("Skipping empty filter definition.") |
374 else: |
438 else: |
375 env.filters[str(filter.name)] = eval(filter.code) |
439 env.filters[str(filter.name)] = eval(filter.code) |
376 |
440 |
377 # Output file specific filters |
|
378 for filter in output.filters: |
|
379 if filter.path: |
|
380 filter.code = _read_relative_file(self.configuration, filter.path, ref) |
|
381 |
|
382 if not filter.code: |
|
383 logging.getLogger('cone.templateml').warning("Skipping empty filter definition.") |
|
384 else: |
|
385 env.filters[str(filter.name)] = eval(filter.code) |
|
386 |
|
387 template = env.get_template('template') |
441 template = env.get_template('template') |
388 |
442 |
389 file_string = template.render(self.context) |
443 file_string = template.render(self.context) |
390 out_file.write(self._encode_data(file_string, output.encoding, output.bom)) |
444 out_file.write(self._encode_data(file_string, output.encoding, output.bom)) |
391 out_file.close() |
445 out_file.close() |
392 |
446 |
393 except Exception, e: |
447 except Exception, e: |
394 logging.getLogger('cone.templateml').error('Failed to generate template: %s %s\n%s' % (type(e), e, traceback.format_exc()) ) |
448 utils.log_exception( |
|
449 logging.getLogger('cone.templateml'), |
|
450 '%r: Failed to generate output: %s: %s' % (self.implementation, type(e).__name__, e)) |
395 else: |
451 else: |
396 logging.getLogger('cone.templateml').info('No (valid) templates found.') |
452 logging.getLogger('cone.templateml').info('No (valid) templates found.') |
397 |
453 |
398 def _encode_data(self, data, encoding, write_bom): |
454 def _encode_data(self, data, encoding, write_bom): |
399 """ |
455 """ |
520 def __init__(self, feature): |
592 def __init__(self, feature): |
521 self._feature = feature |
593 self._feature = feature |
522 self._children = {} |
594 self._children = {} |
523 |
595 |
524 def _get_dict(self): |
596 def _get_dict(self): |
525 result = { |
597 result = {} |
526 '_name' : self._feature.name, |
598 if self._feature is not None: |
527 '_namespace' : self._feature.namespace, |
599 result.update({ |
528 '_value' : self._feature.get_value(), |
600 '_name' : self._feature.name, |
529 '_fqr' : self._feature.fqr, |
601 '_namespace' : self._feature.namespace, |
530 '_type' : self._feature.type} |
602 '_value' : self._feature.get_value(), |
531 for ref, obj in self._children.iteritems(): |
603 '_fqr' : self._feature.fqr, |
532 result[ref] = obj |
604 '_type' : self._feature.type}) |
|
605 result.update(self._children) |
533 return result |
606 return result |
534 |
607 |
535 def items(self): |
608 def items(self): |
536 return self._get_dict().items() |
609 return self._get_dict().items() |
537 |
610 |
538 def iteritems(self): |
611 def iteritems(self): |
539 return self._get_dict().iteritems() |
612 return self._get_dict().iteritems() |
540 |
613 |
541 def __getitem__(self, name): |
614 def __getitem__(self, name): |
542 if name == '_name': return self._feature.name |
615 if self._feature is not None: |
543 elif name == '_namespace': return self._feature.namespace |
616 if name == '_name': return self._feature.name |
544 elif name == '_value': return self._feature.get_value() |
617 elif name == '_namespace': return self._feature.namespace |
545 elif name == '_fqr': return self._feature.fqr |
618 elif name == '_value': return self._feature.get_value() |
546 elif name == '_type': return self._feature.type |
619 elif name == '_fqr': return self._feature.fqr |
547 else: return self._children[name] |
620 elif name == '_type': return self._feature.type |
|
621 |
|
622 try: |
|
623 return self._children[name] |
|
624 except KeyError: |
|
625 if self._feature: |
|
626 msg = "Feature '%s.%s' not found" % (self._feature.fqr, name) |
|
627 else: |
|
628 msg = "Feature '%s' not found" % name |
|
629 raise exceptions.NotFound(msg) |
548 |
630 |
549 def __setitem__(self, name, value): |
631 def __setitem__(self, name, value): |
550 self._children[name] = value |
632 self._children[name] = value |
551 |
633 |
552 def __len__(self): |
634 def __len__(self): |