diff -r 000000000000 -r 2e8eeb919028 configurationengine/source/scripts/report_util.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/configurationengine/source/scripts/report_util.py Thu Mar 11 17:04:37 2010 +0200 @@ -0,0 +1,190 @@ +# +# 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: +# + +import os +import urllib +import logging +from jinja2 import Environment, FileSystemLoader, Template +from cone.public import utils + +ROOT_PATH = os.path.abspath(os.path.dirname(__file__)) + +log = logging.getLogger('cone.report_util') + +class ReportShortcut(object): + def __init__(self, template_file, report_file, description): + self.template_file = template_file + self.report_file = report_file + self.description = description + +class ReportShortcutContainer(object): + """ + Container for report shortcuts. + + A report shortcut describes a pre-defined report option that + has a default template, report file and description. The shortcut + container holds a set of shortcuts and can be used to generate + + """ + def __init__(self, shortcuts, default_shortcut): + """ + @param shortcuts: The shortcuts, a dictionary mapping shortcut + names to ReportShortcut objects. + @param default_shortcut: The default shortcut name to use + """ + if not isinstance(shortcuts, dict): + raise ValueError("'shortcuts' must a dictionary (%s given)!" % type(shortcuts)) + if default_shortcut is not None and default_shortcut not in shortcuts: + raise ValueError("'default_shortcut' must be either None or exist ing 'shortcuts'!") + self.shortcuts = shortcuts + self.default_shortcut = default_shortcut + + def get_shortcut_help_text(self): + """ + Create the text to append to the option description for the + option used to specify the used shortcut. + """ + shortcuts_text = [] + refs = sorted(self.shortcuts.keys()) + if refs: + for ref in refs: + sc = self.shortcuts[ref] + text = "%s - %s" % (ref, sc.description) + COLUMN_WIDTH = (80 - 25) + space_count = COLUMN_WIDTH - (len(text) % COLUMN_WIDTH) + shortcuts_text.append(text + space_count * ' ') + else: + shortcuts_text.append("None") + shortcuts_text = '\n'.join(shortcuts_text) + return shortcuts_text + + def is_valid_shortcut(self, shortcut): + """ + Return whether the given shortcut is valid within the context + of this container. + """ + return shortcut is None or shortcut in self.shortcuts + + def determine_template_and_report(self, shortcut, template_file, report_file, report_file_name_without_ext): + """ + Determine the actual template and report files based on the shortcuts + and given options. + @param shortcut: The used shortcut or None. + @param template_file: Explicitly given template file or None. + @param report_file: Explicitly given report file or None. + @param report_file_name_without_ext: Prefix used to determine the + report file name if the template was explicitly given, but the + report file was not. E.g. if this is 'test' and the explicitly + given template file is 'my_template.html', the report file would + be 'test.html'. + @return: Tuple (template_file, report_file) specifying the actual + template and report files. + """ + actual_shortcut = None + actual_template_file = None + actual_report_file = None + + # Handle report shortcut (set to default or check the given one) + if not shortcut: + actual_shortcut = self.default_shortcut + else: + actual_shortcut = shortcut + + # Determine template file + if template_file: + actual_template_file = template_file + else: + actual_template_file = self.shortcuts[actual_shortcut].template_file + + # Determine report output file + if report_file: + actual_report_file = report_file + else: + if template_file: + # Determine report file name based on the template file name + # if the template was explicitly given + actual_report_file = report_file_name_without_ext + os.path.splitext(template_file)[1] + else: + actual_report_file = self.shortcuts[actual_shortcut].report_file + + return actual_template_file, actual_report_file + +def generate_report(template_file, report_file, report_data): + """ + Generate a report based on the given template file, report file + and data dictionary. + @param template_file: Path to the template file to use. + @param report_file: Path to the output report file. + @param report_data: The report data dictionary used when rendering + the report from the template. + @return: True if successful, False if not. + """ + log.debug('generate_report(template_file=%r, report_file=%r, )' % (template_file, report_file)) + if not isinstance(report_data, dict): + raise ValueError("report_data must be a dictionary!") + + try: + template_file = os.path.abspath(template_file) + + loader = FileSystemLoader([os.path.dirname(template_file), ROOT_PATH]) + env = Environment(loader=loader) + _set_default_filters(env) + + template = env.get_template(os.path.basename(template_file)) + file_string = template.render(report_data) + + # Create directories for the report + report_dir = os.path.dirname(report_file) + if report_dir != '' and not os.path.exists(report_dir): + os.makedirs(report_dir) + + # Write the rendered report to file + f = open(report_file, 'wb') + try: f.write(file_string.encode('utf-8')) + finally: f.close() + + print "Generated report to '%s'" % report_file + return True + except Exception, e: + utils.log_exception(log, "Failed to generate report: %s %s" % (type(e), e)) + return False + +def _set_default_filters(env): + """ + Set default filters to the given Jinja environment + """ + env.filters['xml_charref_replace'] = lambda value: unicode(value).encode('ascii', 'xmlcharrefreplace') + env.filters['pathname_to_url'] = lambda value: urllib.pathname2url(value) + env.filters['csv_escape'] = _csv_escape + env.filters['csv_escape_partial'] = lambda value: unicode(value).replace('"', '""') + +def _csv_escape(value): + """ + Escape a string value so that it can be used as a field in a CSV file. + """ + value = unicode(value) + + needs_quoting = False + for special_char in '",\n': + if special_char in value: + needs_quoting = True + + if needs_quoting: + if '"' in value: + value = value.replace('"', '""') + value = '"' + value + '"' + + return value