configurationengine/source/scripts/report_util.py
changeset 0 2e8eeb919028
equal deleted inserted replaced
-1:000000000000 0:2e8eeb919028
       
     1 #
       
     2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description:
       
    15 #
       
    16 
       
    17 import os
       
    18 import urllib
       
    19 import logging
       
    20 from jinja2 import Environment, FileSystemLoader, Template
       
    21 from cone.public import utils
       
    22 
       
    23 ROOT_PATH = os.path.abspath(os.path.dirname(__file__))
       
    24 
       
    25 log = logging.getLogger('cone.report_util')
       
    26 
       
    27 class ReportShortcut(object):
       
    28     def __init__(self, template_file, report_file, description):
       
    29         self.template_file = template_file
       
    30         self.report_file = report_file
       
    31         self.description = description
       
    32 
       
    33 class ReportShortcutContainer(object):
       
    34     """
       
    35     Container for report shortcuts.
       
    36     
       
    37     A report shortcut describes a pre-defined report option that
       
    38     has a default template, report file and description. The shortcut
       
    39     container holds a set of shortcuts and can be used to generate
       
    40     
       
    41     """
       
    42     def __init__(self, shortcuts, default_shortcut):
       
    43         """
       
    44         @param shortcuts: The shortcuts, a dictionary mapping shortcut
       
    45             names to ReportShortcut objects.
       
    46         @param default_shortcut: The default shortcut name to use
       
    47         """
       
    48         if not isinstance(shortcuts, dict):
       
    49             raise ValueError("'shortcuts' must a dictionary (%s given)!" % type(shortcuts))
       
    50         if default_shortcut is not None and default_shortcut not in shortcuts:
       
    51             raise ValueError("'default_shortcut' must be either None or exist ing 'shortcuts'!")
       
    52         self.shortcuts = shortcuts
       
    53         self.default_shortcut = default_shortcut
       
    54     
       
    55     def get_shortcut_help_text(self):
       
    56         """
       
    57         Create the text to append to the option description for the
       
    58         option used to specify the used shortcut.
       
    59         """
       
    60         shortcuts_text = []
       
    61         refs = sorted(self.shortcuts.keys())
       
    62         if refs:
       
    63             for ref in refs:
       
    64                 sc = self.shortcuts[ref]
       
    65                 text = "%s - %s" % (ref, sc.description)
       
    66                 COLUMN_WIDTH = (80 - 25)
       
    67                 space_count = COLUMN_WIDTH - (len(text) % COLUMN_WIDTH)
       
    68                 shortcuts_text.append(text + space_count * ' ')
       
    69         else:
       
    70             shortcuts_text.append("None")
       
    71         shortcuts_text = '\n'.join(shortcuts_text)
       
    72         return shortcuts_text
       
    73     
       
    74     def is_valid_shortcut(self, shortcut):
       
    75         """
       
    76         Return whether the given shortcut is valid within the context
       
    77         of this container.
       
    78         """
       
    79         return shortcut is None or shortcut in self.shortcuts
       
    80     
       
    81     def determine_template_and_report(self, shortcut, template_file, report_file, report_file_name_without_ext):
       
    82         """
       
    83         Determine the actual template and report files based on the shortcuts
       
    84         and given options.
       
    85         @param shortcut: The used shortcut or None.
       
    86         @param template_file: Explicitly given template file or None.
       
    87         @param report_file: Explicitly given report file or None.
       
    88         @param report_file_name_without_ext: Prefix used to determine the
       
    89             report file name if the template was explicitly given, but the
       
    90             report file was not. E.g. if this is 'test' and the explicitly
       
    91             given template file is 'my_template.html', the report file would
       
    92             be 'test.html'.
       
    93         @return: Tuple (template_file, report_file) specifying the actual
       
    94             template and report files.
       
    95         """
       
    96         actual_shortcut      = None
       
    97         actual_template_file = None
       
    98         actual_report_file   = None
       
    99         
       
   100         # Handle report shortcut (set to default or check the given one)
       
   101         if not shortcut:
       
   102             actual_shortcut = self.default_shortcut
       
   103         else:
       
   104             actual_shortcut = shortcut
       
   105         
       
   106         # Determine template file
       
   107         if template_file:
       
   108             actual_template_file = template_file
       
   109         else:
       
   110             actual_template_file = self.shortcuts[actual_shortcut].template_file
       
   111         
       
   112         # Determine report output file
       
   113         if report_file:
       
   114             actual_report_file = report_file
       
   115         else:
       
   116             if template_file:
       
   117                 # Determine report file name based on the template file name
       
   118                 # if the template was explicitly given
       
   119                 actual_report_file = report_file_name_without_ext + os.path.splitext(template_file)[1]
       
   120             else:
       
   121                 actual_report_file = self.shortcuts[actual_shortcut].report_file
       
   122         
       
   123         return actual_template_file, actual_report_file
       
   124 
       
   125 def generate_report(template_file, report_file, report_data):
       
   126     """
       
   127     Generate a report based on the given template file, report file
       
   128     and data dictionary.
       
   129     @param template_file: Path to the template file to use.
       
   130     @param report_file: Path to the output report file.
       
   131     @param report_data: The report data dictionary used when rendering
       
   132         the report from the template.
       
   133     @return: True if successful, False if not.
       
   134     """
       
   135     log.debug('generate_report(template_file=%r, report_file=%r, <data>)' % (template_file, report_file))
       
   136     if not isinstance(report_data, dict):
       
   137         raise ValueError("report_data must be a dictionary!")
       
   138     
       
   139     try:
       
   140         template_file = os.path.abspath(template_file)
       
   141         
       
   142         loader = FileSystemLoader([os.path.dirname(template_file), ROOT_PATH])
       
   143         env = Environment(loader=loader)
       
   144         _set_default_filters(env)
       
   145         
       
   146         template = env.get_template(os.path.basename(template_file))
       
   147         file_string = template.render(report_data)
       
   148         
       
   149         # Create directories for the report
       
   150         report_dir = os.path.dirname(report_file)
       
   151         if report_dir != '' and not os.path.exists(report_dir):
       
   152             os.makedirs(report_dir)
       
   153         
       
   154         # Write the rendered report to file
       
   155         f = open(report_file, 'wb')
       
   156         try:        f.write(file_string.encode('utf-8'))
       
   157         finally:    f.close()
       
   158         
       
   159         print "Generated report to '%s'" % report_file
       
   160         return True
       
   161     except Exception, e:
       
   162         utils.log_exception(log, "Failed to generate report: %s %s" % (type(e), e))
       
   163         return False
       
   164 
       
   165 def _set_default_filters(env):
       
   166     """
       
   167     Set default filters to the given Jinja environment
       
   168     """
       
   169     env.filters['xml_charref_replace'] = lambda value: unicode(value).encode('ascii', 'xmlcharrefreplace')
       
   170     env.filters['pathname_to_url'] = lambda value: urllib.pathname2url(value)
       
   171     env.filters['csv_escape'] = _csv_escape
       
   172     env.filters['csv_escape_partial'] = lambda value: unicode(value).replace('"', '""')
       
   173 
       
   174 def _csv_escape(value):
       
   175     """
       
   176     Escape a string value so that it can be used as a field in a CSV file.
       
   177     """
       
   178     value = unicode(value)
       
   179     
       
   180     needs_quoting = False
       
   181     for special_char in '",\n':
       
   182         if special_char in value:
       
   183             needs_quoting = True
       
   184     
       
   185     if needs_quoting:
       
   186         if '"' in value:
       
   187             value = value.replace('"', '""')
       
   188         value = '"' + value + '"'
       
   189     
       
   190     return value