configurationengine/source/scripts/report_util.py
changeset 0 2e8eeb919028
--- /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, <data>)' % (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