configurationengine/source/scripts/generation_report.py
changeset 0 2e8eeb919028
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/configurationengine/source/scripts/generation_report.py	Thu Mar 11 17:04:37 2010 +0200
@@ -0,0 +1,315 @@
+#
+# 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, logging, pickle
+import time
+from time import gmtime, strftime
+from jinja2 import Environment, PackageLoader, FileSystemLoader, Template
+from cone.public import api, exceptions, utils, plugin
+from cone.confml import model
+import report_util
+
+ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
+
+def save_report_data(rep_data, file_path):
+    """
+    Save report data into an intermediary report data file.
+    """
+    dir = os.path.dirname(file_path)
+    if dir != '' and not os.path.exists(dir):
+        os.makedirs(dir)
+    
+    pickle_data = pickle.dumps(rep_data)
+    f = open(file_path, 'wb')
+    try:        f.write(pickle_data)
+    finally:    f.close()
+
+def load_report_data(file_path):
+    """
+    Load report data from an intermediary report data file.
+    """
+    f = open(file_path, "rb")
+    try:        data = f.read()
+    finally:    f.close()
+    
+    return pickle.loads(data)
+
+def _get_parent_sequence_or_self(feature):
+    current = feature._parent
+    while current is not None:
+        if isinstance(current, api.FeatureSequence):
+            return current
+        current = current._parent
+    return feature
+
+def collect_report_data(config, options, all_refs, impl_set, rule_exec_results):
+    """
+    Collect data for report generation.
+    """
+    impls = impl_set.get_all_implementations()
+    impls.sort(key=lambda impl: (impl.ref, impl.index))
+    rep_data = ReportData()
+    
+    # Sort the rule results for unit testing purposes
+    rep_data.rule_exec_results = sorted(rule_exec_results, key=lambda e: (e.source, e.index))
+    
+    # Collect a dictionary that maps refs shown in the report to a list of
+    # actual sub-refs used in the generation.
+    # This is done because for sequence settings only an entry for the main
+    # sequence setting is shown, but the actual refs used in generation point
+    # to the individual sub-settings (and possibly even under them).
+    # An example entry in the dictionary could be
+    #   'MyFeature.MySequence' : ['MyFeature.MySequence.Name',
+    #                             'MyFeature.MySequence.File.localPath',
+    #                             'MyFeature.MySequence.File.targetPath']
+    dview = config.get_default_view()
+    refs_dict = {}
+    for ref in all_refs:
+        try:
+            feature = dview.get_feature(ref)
+        except exceptions.NotFound:
+            logging.getLogger('cone.generation_report').warning("Feature for data ref not found: %s" % ref)
+            continue
+        
+        feature = _get_parent_sequence_or_self(feature._obj)
+        ref_to_report = feature.fqr
+        
+        if ref_to_report not in refs_dict:
+            refs_dict[ref_to_report] = []
+        refs_dict[ref_to_report].append(ref)
+    
+#    msg = []
+#    for ref, sub_refs in refs_dict.iteritems():
+#        msg.append("Ref: %s\nSub-refs:\n%s" % (ref, '\n'.join(sub_refs)))
+#    logging.getLogger('cone').debug('\n--------------------------------------\n'.join(msg))
+    
+    # Go through the refs and create report data entries
+    for ref in sorted(refs_dict.iterkeys()):
+        sub_refs = refs_dict[ref]
+        
+        #print "Ref: %s" % ref
+        try:
+            feat = dview.get_feature(ref)
+            
+            # Skip imaker-internal settings
+            if isinstance(feat._obj, model.ConfmlSetting):
+                try:
+                    prop = feat.get_property('cone-report-ignore')
+                    if prop.value.lower() in ('1', 'true'):
+                        continue
+                except exceptions.NotFound:
+                    pass
+            
+            #print "Still %s" % ref
+            
+            found_output = False
+            line = RefLine(ref, feat.get_type())
+            
+            if plugin.is_temp_feature(feat):
+                line.is_temp_feature = True
+
+            if feat.get_type() == 'sequence':
+                for f in feat.list_all_features():
+                    line.add_sequence(feat.get_feature(f).get_name(), feat.get_feature(f).get_value())
+            else:
+                if isinstance(feat.get_datas(), list): 
+                    for d in feat.get_datas():
+                        line.add_data(d.find_parent(type=api.Configuration).get_full_path(), d.get_value())
+                else:
+                    line.add_data(feat.get_data().find_parent(type=api.Configuration).get_full_path(), feat.get_value())
+            
+            
+            # Impl and output files
+            has_impl = False
+            for impl in impls:
+                # Check for implementations using the actual sub-refs
+                if impl.has_ref(sub_refs):
+                    has_impl = True
+                    line.add_impl(impl.ref, impl.IMPL_TYPE_ID, impl.list_output_files())
+            if has_impl:    rep_data.add_line(line)
+            else:           rep_data.add_ref_noimpl(line)
+                
+            
+            # For localPath and targetPath, the name should be the one from its parent file/folder setting
+            if isinstance(feat._obj, (model.ConfmlLocalPath, model.ConfmlTargetPath)):
+                name = feat._obj._parent.name
+            else:
+                name = feat.name
+            
+            line.set_feat_name(name)
+            line.set_config_path( feat._obj.find_parent(type=api.Configuration).get_full_path())
+            
+        except Exception, e:
+            utils.log_exception(logging.getLogger('cone'), 'Failed to collect data for report. Exception: %s' % e)
+        
+    # create one list of not generated files
+    for myline in rep_data.lines:
+        for myimpl in myline.impls:
+            for output_file in myimpl.outputfiles:
+                if not output_file.exists and output_file not in rep_data.missing_output_files:
+                    rep_data.missing_output_files.append(output_file)
+    
+    rep_data.set_options(options)
+    rep_data.set_output_dir(options.output)
+    rep_data.update_nbr_of_refs()
+    rep_data.update_nbr_of_refs_noimpl()
+    
+    return rep_data
+
+def generate_report(rep_data, report_file_path, template_file_path=None):
+    """
+    Generate a generation report based on the given report data.
+    @param rep_data: The report data.
+    @param report_file_path: Path to the report file to generate.
+    @param template_file_path: Path to the template file to use.
+        If None, the default template is used.
+    """
+    # Determine the template file and directory to use
+    if template_file_path is None:
+        template_file_path = os.path.join(ROOT_PATH, 'gen_report_template.html')
+    
+    report_util.generate_report(template_file_path, report_file_path, {'rep_data' : rep_data})
+
+class ReportData(object):
+    """
+    Data object that stores all information used in report generation.
+    """
+    
+    def __init__(self):
+        self.generation_timestamp = time.time()
+        self.generation_time = strftime("%d.%m.%Y %H:%M:%S")
+        self.options = None
+        self.lines = []
+        self.nbr_of_refs = 0
+        self.nbr_of_refs_noimpl = 0
+        self.cwd = os.getcwd()
+        self.ref_noimpl = []
+        self.duration = 0
+        self.output_dir = os.getcwd()
+        self.project_dir = ''
+        self.rule_exec_results = []
+        self.missing_output_files = []    
+    
+    def set_output_dir(self, dir):
+        self.output_dir = os.path.abspath(os.path.normpath(dir))
+    
+    def add_line(self, line):
+        self.lines.append(line)
+    
+    def set_duration(self, duration):
+        self.duration = duration
+    
+    def set_options(self, options):
+        self.options = options
+        self.project_dir = os.path.abspath(options.project)
+        
+    def set_report_filename(self, filename):
+        self.report_filename = filename
+        
+    def add_ref_noimpl(self, ref):
+        self.ref_noimpl.append(ref)
+        
+    def update_nbr_of_refs(self):
+        self.nbr_of_refs = len(self.lines)
+    
+    def update_nbr_of_refs_noimpl(self):
+        self.nbr_of_refs_noimpl = len(self.ref_noimpl)
+    
+    def __repr__(self):
+        return "ReportData(%s)" % [self.generation_timestamp, 
+                                   self.generation_time,
+                                   self.options,
+                                   self.lines,
+                                   self.nbr_of_refs,
+                                   self.nbr_of_refs_noimpl,
+                                   self.cwd,
+                                   self.ref_noimpl,
+                                   self.duration,
+                                   self.output_dir,
+                                   self.project_dir,
+                                   self.rule_exec_results,
+                                   self.missing_output_files]    
+    
+class RefLine(object):
+    """
+    Data object that stores information for one ref in report generation.
+    """
+    
+    def __init__(self, ref, type):
+        self.ref = ref
+        self.feat_type = type 
+        self.feat_name = None
+        self.feat_value = None
+        self.config_path = None
+        self.impls = []
+        self.output = None
+        self.nbr_impls = 0
+        self.nbr_outputfiles = 0
+        self.datas = []
+        self.nbr_of_datas = 0
+        self.nbr_of_rows = 0
+        self.seq_data = []
+        self.is_temp_feature = False
+        
+    def add_impl(self, impl_file, impl_type, outputfiles):
+        self.impls.append(ImplLine(impl_file, impl_type, outputfiles))
+        self.nbr_impls = len(self.impls)
+        self.nbr_outputfiles = len(outputfiles) + self.nbr_outputfiles
+
+    def add_data(self, layer, value):
+        self.datas.append(DataLine(layer,value))
+        self.nbr_of_datas = len(self.datas)
+        
+    def add_sequence(self, subsetting, values):
+        self.seq_data.append([subsetting, values])
+        
+    def set_feat_name(self, name):
+        self.feat_name = name
+        
+    def set_feat_value(self, value):
+        self.feat_value = value
+        
+    def set_config_path(self, filename):
+        self.config_path = os.path.normpath(filename)
+        
+class ImplLine():
+    def __init__(self, impl_file, impl_type, outputfiles, generation_runs=[]):
+        self.name = os.path.normpath(impl_file)
+        self.type = impl_type
+        files = []
+        
+        for outputfile in outputfiles:
+            files.append(Outputfile(outputfile))
+        
+        self.outputfiles = files
+        self.generation_runs = generation_runs
+        
+class Outputfile():
+    def __init__(self, filename):
+        self.filename = os.path.normpath(filename)
+        self.abs_filename = os.path.abspath(filename)
+        self.exists = os.path.isfile(self.abs_filename)
+    
+    def __eq__(self, other):
+        if type(self) is type(other):
+            return self.filename == other.filename
+        else:
+            return False
+        
+class DataLine():
+    def __init__(self, layer, value):
+        self.layer = os.path.normpath(layer)
+        self.value = value
\ No newline at end of file