--- /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