configurationengine/source/scripts/generation_report.py
changeset 3 e7e0ae78773e
parent 2 87cfa131b535
child 4 0951727b8815
child 6 5b32dc297d05
equal deleted inserted replaced
2:87cfa131b535 3:e7e0ae78773e
     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, logging, pickle
       
    18 import time
       
    19 from time import gmtime, strftime
       
    20 from jinja2 import Environment, PackageLoader, FileSystemLoader, Template
       
    21 from cone.public import api, exceptions, utils, plugin
       
    22 from cone.confml import model
       
    23 import report_util
       
    24 
       
    25 ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
       
    26 
       
    27 def save_report_data(rep_data, file_path):
       
    28     """
       
    29     Save report data into an intermediary report data file.
       
    30     """
       
    31     dir = os.path.dirname(file_path)
       
    32     if dir != '' and not os.path.exists(dir):
       
    33         os.makedirs(dir)
       
    34     
       
    35     pickle_data = pickle.dumps(rep_data)
       
    36     f = open(file_path, 'wb')
       
    37     try:        f.write(pickle_data)
       
    38     finally:    f.close()
       
    39 
       
    40 def load_report_data(file_path):
       
    41     """
       
    42     Load report data from an intermediary report data file.
       
    43     """
       
    44     f = open(file_path, "rb")
       
    45     try:        data = f.read()
       
    46     finally:    f.close()
       
    47     
       
    48     return pickle.loads(data)
       
    49 
       
    50 def _get_parent_sequence_or_self(feature):
       
    51     current = feature._parent
       
    52     while current is not None:
       
    53         if isinstance(current, api.FeatureSequence):
       
    54             return current
       
    55         current = current._parent
       
    56     return feature
       
    57 
       
    58 def collect_report_data(config, options, all_refs, impl_set, rule_exec_results):
       
    59     """
       
    60     Collect data for report generation.
       
    61     """
       
    62     impls = impl_set.get_all_implementations()
       
    63     impls.sort(key=lambda impl: (impl.ref, impl.index))
       
    64     rep_data = ReportData()
       
    65     
       
    66     # Sort the rule results for unit testing purposes
       
    67     rep_data.rule_exec_results = sorted(rule_exec_results, key=lambda e: (e.source, e.index))
       
    68     
       
    69     # Collect a dictionary that maps refs shown in the report to a list of
       
    70     # actual sub-refs used in the generation.
       
    71     # This is done because for sequence settings only an entry for the main
       
    72     # sequence setting is shown, but the actual refs used in generation point
       
    73     # to the individual sub-settings (and possibly even under them).
       
    74     # An example entry in the dictionary could be
       
    75     #   'MyFeature.MySequence' : ['MyFeature.MySequence.Name',
       
    76     #                             'MyFeature.MySequence.File.localPath',
       
    77     #                             'MyFeature.MySequence.File.targetPath']
       
    78     dview = config.get_default_view()
       
    79     refs_dict = {}
       
    80     for ref in all_refs:
       
    81         try:
       
    82             feature = dview.get_feature(ref)
       
    83         except exceptions.NotFound:
       
    84             logging.getLogger('cone.generation_report').warning("Feature for data ref not found: %s" % ref)
       
    85             continue
       
    86         
       
    87         feature = _get_parent_sequence_or_self(feature._obj)
       
    88         ref_to_report = feature.fqr
       
    89         
       
    90         if ref_to_report not in refs_dict:
       
    91             refs_dict[ref_to_report] = []
       
    92         refs_dict[ref_to_report].append(ref)
       
    93     
       
    94 #    msg = []
       
    95 #    for ref, sub_refs in refs_dict.iteritems():
       
    96 #        msg.append("Ref: %s\nSub-refs:\n%s" % (ref, '\n'.join(sub_refs)))
       
    97 #    logging.getLogger('cone').debug('\n--------------------------------------\n'.join(msg))
       
    98     
       
    99     # Go through the refs and create report data entries
       
   100     for ref in sorted(refs_dict.iterkeys()):
       
   101         sub_refs = refs_dict[ref]
       
   102         
       
   103         #print "Ref: %s" % ref
       
   104         try:
       
   105             feat = dview.get_feature(ref)
       
   106             
       
   107             # Skip imaker-internal settings
       
   108             if isinstance(feat._obj, model.ConfmlSetting):
       
   109                 try:
       
   110                     prop = feat.get_property('cone-report-ignore')
       
   111                     if prop.value.lower() in ('1', 'true'):
       
   112                         continue
       
   113                 except exceptions.NotFound:
       
   114                     pass
       
   115             
       
   116             #print "Still %s" % ref
       
   117             
       
   118             found_output = False
       
   119             line = RefLine(ref, feat.get_type())
       
   120             
       
   121             if plugin.is_temp_feature(feat):
       
   122                 line.is_temp_feature = True
       
   123 
       
   124             if feat.get_type() == 'sequence':
       
   125                 for f in feat.list_all_features():
       
   126                     line.add_sequence(feat.get_feature(f).get_name(), feat.get_feature(f).get_value())
       
   127             else:
       
   128                 if isinstance(feat.get_datas(), list): 
       
   129                     for d in feat.get_datas():
       
   130                         line.add_data(d.find_parent(type=api.Configuration).get_full_path(), d.get_value())
       
   131                 else:
       
   132                     line.add_data(feat.get_data().find_parent(type=api.Configuration).get_full_path(), feat.get_value())
       
   133             
       
   134             
       
   135             # Impl and output files
       
   136             has_impl = False
       
   137             for impl in impls:
       
   138                 # Check for implementations using the actual sub-refs
       
   139                 if impl.has_ref(sub_refs):
       
   140                     has_impl = True
       
   141                     line.add_impl(impl.ref, impl.IMPL_TYPE_ID, impl.list_output_files())
       
   142             if has_impl:    rep_data.add_line(line)
       
   143             else:           rep_data.add_ref_noimpl(line)
       
   144                 
       
   145             
       
   146             # For localPath and targetPath, the name should be the one from its parent file/folder setting
       
   147             if isinstance(feat._obj, (model.ConfmlLocalPath, model.ConfmlTargetPath)):
       
   148                 name = feat._obj._parent.name
       
   149             else:
       
   150                 name = feat.name
       
   151             
       
   152             line.set_feat_name(name)
       
   153             line.set_config_path( feat._obj.find_parent(type=api.Configuration).get_full_path())
       
   154             
       
   155         except Exception, e:
       
   156             utils.log_exception(logging.getLogger('cone'), 'Failed to collect data for report. Exception: %s' % e)
       
   157         
       
   158     # create one list of not generated files
       
   159     for myline in rep_data.lines:
       
   160         for myimpl in myline.impls:
       
   161             for output_file in myimpl.outputfiles:
       
   162                 if not output_file.exists and output_file not in rep_data.missing_output_files:
       
   163                     rep_data.missing_output_files.append(output_file)
       
   164     
       
   165     rep_data.set_options(options)
       
   166     rep_data.set_output_dir(options.output)
       
   167     rep_data.update_nbr_of_refs()
       
   168     rep_data.update_nbr_of_refs_noimpl()
       
   169     
       
   170     return rep_data
       
   171 
       
   172 def generate_report(rep_data, report_file_path, template_file_path=None):
       
   173     """
       
   174     Generate a generation report based on the given report data.
       
   175     @param rep_data: The report data.
       
   176     @param report_file_path: Path to the report file to generate.
       
   177     @param template_file_path: Path to the template file to use.
       
   178         If None, the default template is used.
       
   179     """
       
   180     # Determine the template file and directory to use
       
   181     if template_file_path is None:
       
   182         template_file_path = os.path.join(ROOT_PATH, 'gen_report_template.html')
       
   183     
       
   184     report_util.generate_report(template_file_path, report_file_path, {'rep_data' : rep_data})
       
   185 
       
   186 class ReportData(object):
       
   187     """
       
   188     Data object that stores all information used in report generation.
       
   189     """
       
   190     
       
   191     def __init__(self):
       
   192         self.generation_timestamp = time.time()
       
   193         self.generation_time = strftime("%d.%m.%Y %H:%M:%S")
       
   194         self.options = None
       
   195         self.lines = []
       
   196         self.nbr_of_refs = 0
       
   197         self.nbr_of_refs_noimpl = 0
       
   198         self.cwd = os.getcwd()
       
   199         self.ref_noimpl = []
       
   200         self.duration = 0
       
   201         self.output_dir = os.getcwd()
       
   202         self.project_dir = ''
       
   203         self.rule_exec_results = []
       
   204         self.missing_output_files = []    
       
   205     
       
   206     def set_output_dir(self, dir):
       
   207         self.output_dir = os.path.abspath(os.path.normpath(dir))
       
   208     
       
   209     def add_line(self, line):
       
   210         self.lines.append(line)
       
   211     
       
   212     def set_duration(self, duration):
       
   213         self.duration = duration
       
   214     
       
   215     def set_options(self, options):
       
   216         self.options = options
       
   217         self.project_dir = os.path.abspath(options.project)
       
   218         
       
   219     def set_report_filename(self, filename):
       
   220         self.report_filename = filename
       
   221         
       
   222     def add_ref_noimpl(self, ref):
       
   223         self.ref_noimpl.append(ref)
       
   224         
       
   225     def update_nbr_of_refs(self):
       
   226         self.nbr_of_refs = len(self.lines)
       
   227     
       
   228     def update_nbr_of_refs_noimpl(self):
       
   229         self.nbr_of_refs_noimpl = len(self.ref_noimpl)
       
   230     
       
   231     def __repr__(self):
       
   232         return "ReportData(%s)" % [self.generation_timestamp, 
       
   233                                    self.generation_time,
       
   234                                    self.options,
       
   235                                    self.lines,
       
   236                                    self.nbr_of_refs,
       
   237                                    self.nbr_of_refs_noimpl,
       
   238                                    self.cwd,
       
   239                                    self.ref_noimpl,
       
   240                                    self.duration,
       
   241                                    self.output_dir,
       
   242                                    self.project_dir,
       
   243                                    self.rule_exec_results,
       
   244                                    self.missing_output_files]    
       
   245     
       
   246 class RefLine(object):
       
   247     """
       
   248     Data object that stores information for one ref in report generation.
       
   249     """
       
   250     
       
   251     def __init__(self, ref, type):
       
   252         self.ref = ref
       
   253         self.feat_type = type 
       
   254         self.feat_name = None
       
   255         self.feat_value = None
       
   256         self.config_path = None
       
   257         self.impls = []
       
   258         self.output = None
       
   259         self.nbr_impls = 0
       
   260         self.nbr_outputfiles = 0
       
   261         self.datas = []
       
   262         self.nbr_of_datas = 0
       
   263         self.nbr_of_rows = 0
       
   264         self.seq_data = []
       
   265         self.is_temp_feature = False
       
   266         
       
   267     def add_impl(self, impl_file, impl_type, outputfiles):
       
   268         self.impls.append(ImplLine(impl_file, impl_type, outputfiles))
       
   269         self.nbr_impls = len(self.impls)
       
   270         self.nbr_outputfiles = len(outputfiles) + self.nbr_outputfiles
       
   271 
       
   272     def add_data(self, layer, value):
       
   273         self.datas.append(DataLine(layer,value))
       
   274         self.nbr_of_datas = len(self.datas)
       
   275         
       
   276     def add_sequence(self, subsetting, values):
       
   277         self.seq_data.append([subsetting, values])
       
   278         
       
   279     def set_feat_name(self, name):
       
   280         self.feat_name = name
       
   281         
       
   282     def set_feat_value(self, value):
       
   283         self.feat_value = value
       
   284         
       
   285     def set_config_path(self, filename):
       
   286         self.config_path = os.path.normpath(filename)
       
   287         
       
   288 class ImplLine():
       
   289     def __init__(self, impl_file, impl_type, outputfiles, generation_runs=[]):
       
   290         self.name = os.path.normpath(impl_file)
       
   291         self.type = impl_type
       
   292         files = []
       
   293         
       
   294         for outputfile in outputfiles:
       
   295             files.append(Outputfile(outputfile))
       
   296         
       
   297         self.outputfiles = files
       
   298         self.generation_runs = generation_runs
       
   299         
       
   300 class Outputfile():
       
   301     def __init__(self, filename):
       
   302         self.filename = os.path.normpath(filename)
       
   303         self.abs_filename = os.path.abspath(filename)
       
   304         self.exists = os.path.isfile(self.abs_filename)
       
   305     
       
   306     def __eq__(self, other):
       
   307         if type(self) is type(other):
       
   308             return self.filename == other.filename
       
   309         else:
       
   310             return False
       
   311         
       
   312 class DataLine():
       
   313     def __init__(self, layer, value):
       
   314         self.layer = os.path.normpath(layer)
       
   315         self.value = value