configurationengine/source/cone/public/plugin.py
changeset 3 e7e0ae78773e
parent 0 2e8eeb919028
child 4 0951727b8815
equal deleted inserted replaced
2:87cfa131b535 3:e7e0ae78773e
    16 ## 
    16 ## 
    17 # @author Teemu Rytkonen
    17 # @author Teemu Rytkonen
    18 
    18 
    19 import sys
    19 import sys
    20 import os
    20 import os
       
    21 import logging
       
    22 import inspect
    21 import re
    23 import re
    22 import logging
    24 import codecs
    23 import sets
    25 
    24 import inspect
    26 from cone.public import exceptions, utils, api, settings, rules, parsecontext
    25 import xml.parsers.expat
       
    26 
       
    27 from cone.public import exceptions, utils, api, container, settings, rules
       
    28 import _plugin_reader
    27 import _plugin_reader
    29 
    28 
    30 debug = 0
    29 debug = 0
    31 """
    30 """
    32 Implementation specific settings can be overriden in the global impl_settings variable
    31 Implementation specific settings can be overriden in the global impl_settings variable
    67     """
    66     """
    68     Return whether the given feature is a temporary feature.
    67     Return whether the given feature is a temporary feature.
    69     """
    68     """
    70     return hasattr(feature, _plugin_reader.TEMP_FEATURE_MARKER_VARNAME)
    69     return hasattr(feature, _plugin_reader.TEMP_FEATURE_MARKER_VARNAME)
    71 
    70 
    72 class GenerationContext(object):
    71 def uses_ref(refs, impl_refs):
       
    72     """
       
    73     Compare two lists of setting references and return whether any of the
       
    74     references in ``refs`` is used in ``impl_refs``.
       
    75     """
       
    76     for ref in refs:
       
    77         for impl_ref in impl_refs:
       
    78             if ref.startswith(impl_ref):
       
    79                 if len(ref) == len(impl_ref):
       
    80                     return True
       
    81                 elif ref[len(impl_ref)] == '.':
       
    82                     return True
       
    83     return False
       
    84 
       
    85 class GenerationContext(rules.DefaultContext):
    73     """
    86     """
    74     Context object that can be used for passing generation-scope
    87     Context object that can be used for passing generation-scope
    75     data to implementation instances.
    88     data to implementation instances.
    76     """
    89     """
    77     
    90     
    78     def __init__(self, tags={}):
    91     def __init__(self, **kwargs):
    79         #: The tags used in this generation context
    92         #: The tags used in this generation context
    80         #: (i.e. the tags passed from command line)
    93         #: (i.e. the tags passed from command line)
    81         self.tags = tags
    94         self.tags = kwargs.get('tags', {})
    82         
    95         
    83         #: The tags policy used in this generation context
    96         #: The tags policy used in this generation context
    84         self.tags_policy = "OR"
    97         self.tags_policy = kwargs.get('tags_policy', "OR")
    85         
    98         
    86         #: A dictionary that implementation instances can use to
    99         #: A dictionary that implementation instances can use to
    87         #: pass any data between each other
   100         #: pass any data between each other
    88         self.impl_data_dict = {}
   101         self.impl_data_dict = {}
    89         
   102         
    90         #: A string for the phase of the generation
   103         #: A string for the phase of the generation.
    91         self.phase = ""
   104         #: If None, no filtering based on phase is done when
       
   105         #: running the implementations
       
   106         self.phase = kwargs.get('phase', None)
    92         
   107         
    93         #: a list of rule results
   108         #: a list of rule results
    94         self.results = []
   109         self.results = []
    95         
   110         
    96         #: a pointer to the configuration 
   111         #: a pointer to the configuration 
    97         self.configuration = None
   112         self.configuration = kwargs.get('configuration', None)
    98 
   113         
    99     def eval(self, ast, expression, value):
   114         #: If True, then all implementation filtering done by
       
   115         #: should_run() is disabled, and it always returns True.
       
   116         self.filtering_disabled = False
       
   117         
       
   118         #: if True, then the execution flow should normal except 
       
   119         #: no output files are actually generated
       
   120         self.dry_run= kwargs.get('dry_run', None)
       
   121         
       
   122         #: the output folder for generation
       
   123         #: ensure already here that the output exists
       
   124         self.output= kwargs.get('output', 'output')
       
   125         
       
   126         #: List of references of the settings that have been modified in 
       
   127         #: listed layers and should trigger an implementation to be executed.
       
   128         #: None if ref filtering is not used
       
   129         self.changed_refs = kwargs.get('changed_refs', None)
       
   130         
       
   131         
       
   132         #: A boolean flag to determine whether to use ref filtering or not
       
   133         self.filter_by_refs = kwargs.get('filter_by_refs', False)
       
   134         
       
   135         #: Temp features
       
   136         self.temp_features = kwargs.get('temp_features', [])
       
   137         
       
   138         #: Executed implementation objects. This is a set so that a 
       
   139         #: implementation would exist only once in it. Even if it executed 
       
   140         #: more than once. The generation_output will show the actual 
       
   141         #: output several times if a implementation is executed several times.
       
   142         self.executed = set()
       
   143         
       
   144         #: Set of all implementation objects in the configuration context 
       
   145         self.impl_set = kwargs.get('impl_set', ImplSet())
       
   146         
       
   147         #: Generation output elements as a list 
       
   148         self.generation_output = []
       
   149 
       
   150         #: possible log elemement 
       
   151         self.log = []
       
   152         self.log_file = ""
       
   153 
       
   154     def __getstate__(self):
       
   155         state = self.__dict__
       
   156         state['impl_data_dict'] = {}
       
   157         return state
       
   158     
       
   159     def eval(self, ast, expression, value, **kwargs):
   100         """
   160         """
   101         eval for rule evaluation against the context
   161         eval for rule evaluation against the context
   102         """
   162         """
   103         pass
   163         pass
   104 
   164 
   105     def handle_terminal(self, expression):
   165     def handle_terminal(self, expression):
   106         """
   166         """
   107         Handle a terminal object 
   167         Handle a terminal object 
   108         """
   168         """
   109         try:
   169         try:
   110             if isinstance(expression, str): 
   170             if isinstance(expression, basestring): 
   111                 m = re.match("\${(.*)}", expression)
   171                 try:
   112                 if m:
   172                     dview = self.configuration.get_default_view()
   113                     try:
   173                     return dview.get_feature(expression).value
   114                         dview = self.configuration.get_default_view()
   174                 except Exception, e:
   115                         return dview.get_feature(m.group(1)).value
   175                     logging.getLogger('cone').error("Could not dereference feature %s. Exception %s" % (expression, e))
   116                     except Exception, e:
   176                     raise e
   117                         logging.getLogger('cone').error("Could not dereference feature %s. Exception %s" % (expression, e))
       
   118                         raise e
       
   119                 elif expression in ['true','1','True']:
       
   120                     return True
       
   121                 elif expression in ['false','0','False']:
       
   122                     return False
       
   123                 else:
       
   124                     try:
       
   125                         return eval(expression)
       
   126                     except NameError:
       
   127                         # If the expression is a string in it self it can be returned
       
   128                         return expression
       
   129             else:
       
   130                 return expression
       
   131         except Exception,e:
   177         except Exception,e:
   132             logging.getLogger('cone').error("Exception with expression %s: %s" % (expression, e))
   178             logging.getLogger('cone').error("Exception with expression %s: %s" % (expression, e))
   133             raise e
   179             raise e
   134 
   180     
       
   181     def convert_value(self, value):
       
   182         try:
       
   183             # Handle some special literals
       
   184             if value == 'true':     return True
       
   185             if value == 'false':    return False
       
   186             if value == 'none':     return None
       
   187             
       
   188             # Values can be any Python literals, so eval() the string to
       
   189             # get the value
       
   190             return eval(value)
       
   191         except Exception:
       
   192             ref_regex = re.compile('^[\w\.\*]*$', re.UNICODE) 
       
   193             if ref_regex.match(value) is None:
       
   194                 raise RuntimeError("Could not evaluate '%s'" % value)
       
   195             else:
       
   196                 raise RuntimeError("Could not evaluate '%s'. Did you mean a setting reference and forgot to use ${}?" % value)
       
   197     
       
   198     def set(self, expression, value, **kwargs):
       
   199         log = logging.getLogger('cone.ruleml')
       
   200         try:
       
   201             feature = self.configuration.get_default_view().get_feature(expression)
       
   202             feature.set_value(value)
       
   203             
       
   204             relation = kwargs.get('relation')
       
   205             if relation:
       
   206                 log.info("Set %s = %r from %r" % (expression, value, relation))
       
   207             else:
       
   208                 log.info("Set %s = %r" % (expression, value))
       
   209             
       
   210             refs = [feature.fqr]
       
   211             if feature.is_sequence():
       
   212                 refs = ["%s.%s" % (feature.fqr,subref) for subref in feature.list_features()]
       
   213                 
       
   214             self.add_changed_refs(refs, relation)
       
   215 
       
   216             if relation:
       
   217                 self.generation_output.append(GenerationOutput(expression, 
       
   218                                                                relation,
       
   219                                                                type='ref'))
       
   220             return True
       
   221         except exceptions.NotFound,e:
       
   222             log.error('Set operation for %s failed, because feature with that reference was not found! Exception %s', expression, e) 
       
   223             raise e
       
   224     
       
   225     def should_run(self, impl, log_debug_message=True):
       
   226         """
       
   227         Return True if the given implementation should be run (generated).
       
   228         
       
   229         Also optionally log a message that the implementation is
       
   230         filtered out based on phase, tags or setting references.
       
   231         
       
   232         Calling this method also affects the output of executed_impls. Every
       
   233         implementation for which a call to this method has returned True
       
   234         will also be in that list.
       
   235         
       
   236         @param impl: The implementation to check.
       
   237         @param log_debug_message: If True, a debug message will be logged
       
   238             if the implementation is filtered out based on phase, tags
       
   239             or setting references.
       
   240         """
       
   241         if self.filtering_disabled:
       
   242             return True
       
   243         
       
   244         if isinstance(impl, ImplContainer):
       
   245             # Don't perform any filtering on containers
       
   246             return True
       
   247         
       
   248         impl_phases = impl.invocation_phase()
       
   249         if isinstance(impl_phases, basestring):
       
   250             impl_phases = [impl_phases]
       
   251         
       
   252         if self.phase is not None and self.phase not in impl_phases:
       
   253             # Don't log a debug message for phase-based filtering to
       
   254             # avoid unnecessary spamming (uncomment if necessary
       
   255             # during development)
       
   256             #logging.getLogger('cone').debug('Filtered out based on phase: %r (%r not in %r)' % (impl, self.phase, impl_phases))
       
   257             return False
       
   258         if self.tags and not impl.has_tag(self.tags, self.tags_policy):
       
   259             if log_debug_message:
       
   260                 logging.getLogger('cone').debug('Filtered out based on tags: %r' % impl)
       
   261             return False
       
   262         if self.filter_by_refs and self.changed_refs and impl.has_ref(self.changed_refs) == False:
       
   263             if log_debug_message:
       
   264                 logging.getLogger('cone').debug('Filtered out based on refs: %r' % impl)
       
   265             return False
       
   266         
       
   267         # Assumption is that when a implementation should be run it is added to the executed pile
       
   268         self.executed.add(impl)
       
   269         return True
       
   270     
       
   271     def have_run(self, impl):
       
   272         """
       
   273         This function will add the given implementation 
       
   274         outputs to the list of generation_outputs.
       
   275         """
       
   276         # Add outputs only from actual leaf implementations
       
   277         # not from ImplContainers
       
   278         if not isinstance(impl, ImplContainer):
       
   279             self.generation_output += impl.get_outputs()
       
   280     
       
   281     def create_file(self, filename, **kwargs):
       
   282         """
       
   283         Create a file handle under the output folder. Also adds the output file to the generation outputs list.
       
   284         @param filename: the filename with path, that is created under the output folder of the generation context.
       
   285         @param **kwargs: the keyword arguments that can provide essential information for the GenerationOutput 
       
   286         object creation. They should at least contain the implementation argument for the GenerationObject.
       
   287           @param **kwargs implementation: the implementation object that created this output
       
   288           @param **kwargs mode: the mode of the output file created 
       
   289           @param **kwargs encoding: the possible encoding of the output file. When this parameter is given the create_file will 
       
   290           use codecs.open method to create the file. 
       
   291         @return: the filehandle of the new file. 
       
   292         """
       
   293         
       
   294         implml   = kwargs.get('implementation', None)
       
   295         mode     = kwargs.get('mode', 'wb')
       
   296         encoding = kwargs.get('encoding', None)
       
   297         targetfile = os.path.normpath(os.path.join(self.output, filename))
       
   298         
       
   299         if not os.path.exists(os.path.dirname(targetfile)):
       
   300             os.makedirs(os.path.dirname(targetfile))
       
   301         
       
   302         if not encoding:
       
   303             outfile = open(targetfile, mode)
       
   304         else: 
       
   305             outfile = codecs.open(targetfile, mode, encoding)
       
   306         # Add the generation output
       
   307         self.generation_output.append(GenerationOutput(utils.resourceref.norm(targetfile), 
       
   308                                                        implml, 
       
   309                                                        phase=self.phase,
       
   310                                                        type='file',
       
   311                                                        output=self.output))
       
   312         return outfile
       
   313     
       
   314     def add_file(self, filename, **kwargs):
       
   315         """
       
   316         Add a file to the generation outputs list.
       
   317         @param filename: the filename with path, that is added. If the path is a relative path
       
   318         the path is added under the output folder of the generation context. Absolute path is added as such and not manipulated.
       
   319         @param **kwargs: the keyword arguments that can provide essential information for the GenerationOutput 
       
   320         object creation. They should at least contain the implementation argument for the GenerationObject.
       
   321         @return: None 
       
   322         """
       
   323         if not os.path.isabs(filename):
       
   324             targetfile = os.path.join(self.output, filename)
       
   325         else:
       
   326             targetfile = filename
       
   327         # Add the generation output
       
   328         self.generation_output.append(GenerationOutput(utils.resourceref.norm(targetfile), 
       
   329                                                        kwargs.get('implementation'), 
       
   330                                                        phase=self.phase,
       
   331                                                        type='file',
       
   332                                                        output=self.output))
       
   333 
       
   334     def get_output(self, **kwargs):
       
   335         """
       
   336         Get a output object from the generation_output list.
       
   337         @param **kwargs: the keyword arguments. 
       
   338             @param implml_type: a filter for generation outputs to filter generation outputs only with given implementation type. 
       
   339         @return: list of generation output objects
       
   340         """
       
   341         filters = []
       
   342         if kwargs.get('implml_type'):
       
   343             filters.append(lambda x: x.implementation and x.implementation.IMPL_TYPE_ID == kwargs.get('implml_type'))
       
   344              
       
   345         outputs = []
       
   346         # go through all the generation_output items with all provided filters
       
   347         # if the item passes all filters add it to the outputs list 
       
   348         for item in self.generation_output:
       
   349             passed = True
       
   350             for filter in filters:
       
   351                 if not filter(item):
       
   352                     passed = False
       
   353                     continue
       
   354             if passed:
       
   355                 outputs.append(item)
       
   356         return outputs
       
   357 
       
   358     def add_changed_refs(self, refs, implml=None):
       
   359         """
       
   360         Add changed refs to the current set of changed refs if necessary.
       
   361         
       
   362         If there are new refs and they are added, log also a debug message.
       
   363         """
       
   364         if self.changed_refs is None:
       
   365             return
       
   366         for ref in refs:
       
   367             self.add_changed_ref(ref, implml)
       
   368     
       
   369     def add_changed_ref(self, ref, implml=None):
       
   370         """
       
   371         Add changed ref to the current set of changed refs if necessary.
       
   372         
       
   373         If there are new refs and they are added, log also a debug message.
       
   374         """
       
   375         if self.changed_refs is None:
       
   376             return
       
   377         
       
   378         if ref not in self.changed_refs:
       
   379             self.changed_refs.append(ref)
       
   380             logging.getLogger('cone').debug('Added ref %s from implml %s' % (ref, implml))
       
   381 
       
   382     def get_refs_with_no_output(self, refs=None):
       
   383         if not refs:
       
   384             refs = self.changed_refs
       
   385         if refs:
       
   386             # create a set from the changed refs 
       
   387             # then remove the refs that have a generation output
       
   388             # and return the remaining refs as a list
       
   389             refsset = set(refs)
       
   390             implrefs = set()
       
   391             for output in self.generation_output:
       
   392                 if output.implementation:
       
   393                     implrefs |= set(output.implementation.get_refs() or [])
       
   394                     if output.type == 'ref':
       
   395                         implrefs.add(output.name)
       
   396             # Add all sequence subfeatures to the list of implementation references
       
   397             dview = self.configuration.get_default_view()
       
   398             for fea in dview.get_features(list(implrefs)):
       
   399                 if fea.is_sequence():
       
   400                     seqfeas = ["%s.%s" % (fea.fqr,fearef) for fearef in fea.get_sequence_parent().list_features()] 
       
   401                     implrefs |= set(seqfeas)
       
   402             
       
   403             refsset = refsset - implrefs
       
   404             return sorted(list(refsset))
       
   405         else:
       
   406             return []
       
   407 
       
   408     def get_refs_with_no_implementation(self, refs=None):
       
   409         if not refs:
       
   410             refs = self.changed_refs
       
   411         if refs:
       
   412             # create a set from the changed refs 
       
   413             # then remove the refs that have a generation output
       
   414             # and return the remaining refs as a list
       
   415             refsset = set(refs)
       
   416             implrefs = set(self.impl_set.get_implemented_refs())
       
   417             logging.getLogger('cone').debug("changed_refs: %s" % refsset)
       
   418             logging.getLogger('cone').debug("implrefs: %s" % implrefs)
       
   419             # Add all sequence subfeatures to the list of implementation references
       
   420             dview = self.configuration.get_default_view()
       
   421             for fea in dview.get_features(list(implrefs)):
       
   422                 if fea.is_sequence():
       
   423                     seqfeas = ["%s.%s" % (fea.fqr,fearef) for fearef in fea.get_sequence_parent().list_features()] 
       
   424                     implrefs |= set(seqfeas)
       
   425             
       
   426             refsset = refsset - implrefs
       
   427             return sorted(list(refsset))
       
   428         else:
       
   429             return []
       
   430 
       
   431     @property
       
   432     def executed_impls(self):
       
   433         """
       
   434         List of all executed implementations (implementations for which
       
   435         a call to should_run() has returned True).
       
   436         """
       
   437         return list(self.executed)
       
   438 
       
   439     @property
       
   440     def features(self):
       
   441         """
       
   442         return the default view of the context configuration to access all features of the configuration.
       
   443         """
       
   444         return self.configuration.get_default_view()
       
   445 
       
   446     def grep_log(self, entry):
       
   447         """
       
   448         Grep the self.log entries for given entry and return a list of tuples with line (index, entry) 
       
   449         """
       
   450         return utils.grep_tuple(entry, self.log)
       
   451 
       
   452 class MergedContext(GenerationContext):
       
   453     def __init__(self, contexts):
       
   454         self.contexts = contexts
       
   455         self.configuration = None
       
   456         self.changed_refs = []
       
   457         self.temp_features = []
       
   458         self.executed = set()
       
   459         self.impl_set = ImplSet()
       
   460         self.impl_dict = {}
       
   461         self.generation_output = []
       
   462         self.log = []
       
   463         self.log_files = []
       
   464         self.outputs = {}
       
   465         for context in contexts:
       
   466             self.changed_refs += context.changed_refs
       
   467             self.temp_features += context.temp_features
       
   468             self.configuration = context.configuration
       
   469             self.executed |= context.executed
       
   470             self.generation_output += context.generation_output
       
   471             self.log += context.log
       
   472             self.log_files.append(context.log_file)
       
   473             for output in context.generation_output:
       
   474                 self.outputs[output.name] = output
       
   475             for impl in context.impl_set:
       
   476                 self.impl_dict[impl.ref] = impl
       
   477         self.impl_set = ImplSet(self.impl_dict.values())
       
   478 
       
   479     def get_changed_refs(self, **kwargs):
       
   480         changed_refs = set()
       
   481         operation = kwargs.get('operation', 'union')
       
   482         for context in self.contexts:
       
   483             if not changed_refs:
       
   484                 # set the base set from the first context
       
   485                 changed_refs = set(context.changed_refs)
       
   486             else:
       
   487                 if operation == 'union':
       
   488                     changed_refs |= set(context.changed_refs)
       
   489                 elif operation == 'intersection':
       
   490                     changed_refs &= set(context.changed_refs)
       
   491                 elif operation == 'difference':
       
   492                     changed_refs -= set(context.changed_refs)
       
   493                 elif operation == 'symmetric_difference':
       
   494                     changed_refs ^= set(context.changed_refs)
       
   495                 else:
       
   496                     raise exceptions.NotSupportedException('Illegal opration %s for get_changed_refs!' % operation)
       
   497         #remove temp features
       
   498         if kwargs.get('ignore_temps'):
       
   499             changed_refs = changed_refs - set(self.temp_features)
       
   500         return list(changed_refs)
       
   501 
       
   502 class GenerationOutput(object):
       
   503     """
       
   504     A GenerationOutput object that is intended to be part of GenerationContext.generation_outputs.
       
   505     The data should hold information about
       
   506     """
       
   507     TYPES = ['file', 'ref']
       
   508     
       
   509     def __init__(self, name, implementation, **kwargs):
       
   510         """
       
   511         @param name: the name of the output as string
       
   512         @param implementation: the implementation object that generated this output
       
   513         @param type: the type of the output that could be file|ref
       
   514         """
       
   515         
       
   516         """ The name of the output """
       
   517         self.name = name
       
   518         
       
   519         """ The implementation object that generated the output """
       
   520         self.implementation = implementation
       
   521         
       
   522         """ The type of the output """
       
   523         self.type = kwargs.get('type', None)
       
   524 
       
   525         """ phase of the generation """
       
   526         self.phase = kwargs.get('phase', None)
       
   527 
       
   528         """ the context output path of the generation """
       
   529         self.output = kwargs.get('output', None)
       
   530         
       
   531         """ the possible exception """
       
   532         self.exception = kwargs.get('exception', None)
       
   533          
       
   534     def __str__(self):
       
   535         return "%s(%s, %s)" % (self.__class__.__name__, self.name, self.implementation)
       
   536 
       
   537     @property
       
   538     def filename(self):
       
   539         """
       
   540         return the filename part of the the output name. Valid only if the output name is a path.
       
   541         """
       
   542         return os.path.basename(self.name)
       
   543 
       
   544     @property
       
   545     def relpath(self):
       
   546         """
       
   547         return the relative name part of the the output name, with relation to the context output path. 
       
   548         """
       
   549         return utils.relpath(self.name, self.output)
       
   550         
       
   551     @property
       
   552     def abspath(self):
       
   553         """
       
   554         return the relative name part of the the output name, with relation to the context output path. 
       
   555         """
       
   556         if os.path.isabs(self.name):
       
   557             return os.path.normpath(self.name)
       
   558         else:
       
   559             return os.path.abspath(os.path.normpath(self.name))
   135 
   560 
   136 class FlatComparisonResultEntry(object):
   561 class FlatComparisonResultEntry(object):
   137     """
   562     """
   138     Class representing a result entry for a flat implementation
   563     Class representing a result entry for a flat implementation
   139     comparison.
   564     comparison.
   314         configuration data.
   739         configuration data.
   315         """
   740         """
   316         self._settings = None
   741         self._settings = None
   317         self.ref = ref
   742         self.ref = ref
   318         self.index = None
   743         self.index = None
       
   744         self.lineno = None
   319         self.configuration = configuration
   745         self.configuration = configuration
   320         self._output_root = self.settings.get('output_root','output')
   746         self._output_root = self.settings.get('output_root','')
   321         self.output_subdir = self.settings.get('output_subdir','')
   747         self.output_subdir = self.settings.get('output_subdir','')
   322         self.plugin_output = self.settings.get('plugin_output','')
   748         self.plugin_output = self.settings.get('plugin_output','')
   323         
   749         
   324         self.generation_context = None
   750         self.generation_context = None
   325         self._tags = None
   751         self._tags = None
   326         self._invocation_phase = None
   752         self._invocation_phase = None
   327         self._tempvar_defs = []
   753         self._tempvar_defs = []
   328         self.condition = None
   754         self.condition = None
   329         self._output_root_override = None
   755         self._output_root_override = None
   330 
   756 
   331     def _eval_context(self, context):
   757     def __reduce_ex__(self, protocol_version):
   332         """
   758         config = self.configuration
   333         This is a internal function that returns True when the context matches to the 
   759         if protocol_version == 2:
   334         context of this implementation. For example phase, tags, etc are evaluated.
   760             tpl =  (read_impl_from_location,
   335         """
   761                     (self.ref, config, self.lineno),
   336         if context.tags and not self.has_tag(context.tags, context.tags_policy):
   762                     None,
   337             return False
   763                     None,
   338         if context.phase and not context.phase in self.invocation_phase():
   764                     None)
   339             return False
   765             return tpl
   340         if self.condition and not self.condition.eval(context):
   766         else:
   341             return False 
   767             return (read_impl_from_location,
   342         
   768                     (self.ref, config, self.lineno))
   343         return True
   769             
   344 
   770 
   345     def _dereference(self, ref):
   771     def _dereference(self, ref):
   346         """
   772         """
   347         Function for dereferencing a configuration ref to a value in the Implementation configuration context. 
   773         Function for dereferencing a configuration ref to a value in the Implementation configuration context. 
   348         """
   774         """
   349         return configuration.get_default_view().get_feature(ref).value
   775         return self.configuration.get_default_view().get_feature(ref).value
   350 
   776 
   351     def _compare(self, other, dict_keys=None):
   777     def _compare(self, other, dict_keys=None):
   352         """ 
   778         """ 
   353         The plugin instance against another plugin instance
   779         The plugin instance against another plugin instance
   354         """
   780         """
   355         raise exceptions.NotSupportedException()
   781         raise exceptions.NotSupportedException()
   356 
   782     
   357     def generate(self, context=None):
   783     def generate(self, context=None):
   358         """
   784         """
   359         Generate the given implementation.
   785         Generate the given implementation.
   360         @param context: The generation context can be given as a parameter. 
   786         @param context: The generation context can be given as a parameter. 
   361         The context can contain generation specific parameters for the 
   787         The context can contain generation specific parameters for the 
   381         """
   807         """
   382         Return a list of output files as an array. 
   808         Return a list of output files as an array. 
   383         """
   809         """
   384         return []
   810         return []
   385     
   811     
       
   812     def get_outputs(self):
       
   813         """
       
   814         Return a list of GenerationOutput objets as a list. 
       
   815         """
       
   816         outputs = []
       
   817         phase = None 
       
   818         if self.generation_context: phase = self.generation_context.phase
       
   819         for outfile in self.list_output_files():
       
   820             outputs.append(GenerationOutput(outfile,self,type='file', phase=phase) )
       
   821         return outputs
       
   822     
       
   823     
   386     def get_refs(self):
   824     def get_refs(self):
   387         """
   825         """
   388         Return a list of all ConfML setting references that affect this
   826         Return a list of all ConfML setting references that affect this
   389         implementation. May also return None if references are not relevant
   827         implementation. May also return None if references are not relevant
   390         for the implementation.
   828         for the implementation.
   402             return None
   840             return None
   403         
   841         
   404         if isinstance(refs, basestring):
   842         if isinstance(refs, basestring):
   405             refs = [refs]
   843             refs = [refs]
   406         
   844         
   407         for ref in refs:
   845         return uses_ref(refs, impl_refs)
   408             for impl_ref in impl_refs:
       
   409                 if ref.startswith(impl_ref):
       
   410                     if len(ref) == len(impl_ref):
       
   411                         return True
       
   412                     elif ref[len(impl_ref)] == '.':
       
   413                         return True
       
   414         return False
       
   415 
   846 
   416     def flat_compare(self, other):
   847     def flat_compare(self, other):
   417         """
   848         """
   418         Return a flat comparison result for two implementations.
   849         Return a flat comparison result for two implementations.
   419         @param other: The target implementation to compare against.
   850         @param other: The target implementation to compare against.
   455         """
   886         """
   456         raise exceptions.NotSupportedException()
   887         raise exceptions.NotSupportedException()
   457 
   888 
   458     @property
   889     @property
   459     def settings(self):
   890     def settings(self):
       
   891         """
       
   892         return the plugin specific settings object.
       
   893         """
   460         if not self._settings:
   894         if not self._settings:
   461             parser = settings.SettingsFactory.cone_parser()
   895             parser = settings.SettingsFactory.cone_parser()
   462             if self.IMPL_TYPE_ID is not None:
   896             if self.IMPL_TYPE_ID is not None:
   463                 section = self.IMPL_TYPE_ID.upper()
   897                 section = self.IMPL_TYPE_ID.upper()
   464             else:
   898             else:
   466             self._settings = settings.ConeSettings(parser, section)
   900             self._settings = settings.ConeSettings(parser, section)
   467         return self._settings
   901         return self._settings
   468 
   902 
   469     @property
   903     @property
   470     def output(self):
   904     def output(self):
       
   905         """
       
   906         return the output folder for this plugin instance.
       
   907         """
   471         vars = {'output_root': self.output_root,'output_subdir': self.output_subdir,'plugin_output': self.plugin_output}
   908         vars = {'output_root': self.output_root,'output_subdir': self.output_subdir,'plugin_output': self.plugin_output}
   472         default_format = '%(output_root)s/%(output_subdir)s/%(plugin_output)s'
   909         default_format = '%(output_root)s/%(output_subdir)s/%(plugin_output)s'
   473         return utils.resourceref.norm(self.settings.get('output',default_format,vars))
   910         output = utils.resourceref.remove_begin_slash(utils.resourceref.norm(self.settings.get('output',default_format,vars)))
       
   911         if os.path.isabs(self.output_root):
       
   912             output = utils.resourceref.insert_begin_slash(output) 
       
   913         return output
   474     
   914     
   475     def _get_output_root(self):
   915     def _get_output_root(self):
   476         if self._output_root_override is not None:
   916         if self._output_root_override is not None:
   477             return self._output_root_override
   917             return self._output_root_override
   478         else:
   918         else:
   614         return a list of all actual implementation which is for ImplBase object self. 
  1054         return a list of all actual implementation which is for ImplBase object self. 
   615         """
  1055         """
   616         return [self]
  1056         return [self]
   617     
  1057     
   618     def __repr__(self):
  1058     def __repr__(self):
   619         return "%s(ref=%r, type=%r, index=%r)" % (self.__class__.__name__, self.ref, self.IMPL_TYPE_ID, self.index)
  1059         return "%s(ref=%r, type=%r, lineno=%r)" % (self.__class__.__name__, self.ref, self.IMPL_TYPE_ID, self.lineno)
   620 
  1060 
       
  1061     @property
       
  1062     def path(self):
       
  1063         """
       
  1064         return path relative to the Configuration projec root
       
  1065         """
       
  1066         return self.ref
       
  1067 
       
  1068     @property
       
  1069     def abspath(self):
       
  1070         """
       
  1071         return absolute system path to the implementation
       
  1072         """
       
  1073         return os.path.abspath(os.path.join(self.configuration.storage.path,self.ref))
       
  1074     
       
  1075     def uses_layers(self, layers, context):
       
  1076         """
       
  1077         Return whether this implementation uses any of the given layers
       
  1078         in the given context, i.e., whether the layers contain anything that would
       
  1079         affect generation output.
       
  1080         """
       
  1081         # The default implementation checks against refs changed in the layers
       
  1082         refs = []
       
  1083         for l in layers: refs.extend(l.list_leaf_datas())
       
  1084         return self.has_ref(refs)
   621 
  1085 
   622 class ImplContainer(ImplBase):
  1086 class ImplContainer(ImplBase):
   623     """
  1087     """
   624     Acts as a container object with list functionality.  
  1088     Acts as a container object with list functionality.  
   625     """
  1089     """
   653         @param context: The generation context can be given as a parameter. The container
  1117         @param context: The generation context can be given as a parameter. The container
   654         passes the context to its sub implementations.
  1118         passes the context to its sub implementations.
   655          
  1119          
   656         @return: 
  1120         @return: 
   657         """
  1121         """
   658         if context:
  1122         log = logging.getLogger('cone')
   659             if not self._eval_context(context):
  1123         
   660                 # should we report something if we exit here?
  1124         if self.condition and not self.condition.eval(context):
   661                 return
  1125             log.debug('Filtered out based on condition %s: %r' % (self.condition, self))
   662             
  1126             return
       
  1127         
   663         # run generate on sub impls
  1128         # run generate on sub impls
   664         for impl in self.impls:
  1129         for impl in self.impls:
   665             impl.generate(context)
  1130             if context:
       
  1131                 # 1. Check should the implementation be run from context
       
  1132                 # 2. Run ImplContainer if should
       
  1133                 # 3. run other ImplBase objects if this is not a dry_run                      
       
  1134                 if context.should_run(impl):
       
  1135                     if isinstance(impl, ImplContainer) or \
       
  1136                         not context.dry_run:
       
  1137                         impl.generate(context)
       
  1138                         # context.have_run(impl)
       
  1139             else:
       
  1140                 impl.generate(context)
   666 
  1141 
   667     def get_refs(self):
  1142     def get_refs(self):
   668         """
  1143         # Containers always return None, because the ref-based filtering
   669         Return a list of all ConfML setting references that affect this
  1144         # happens only on the actual implementations
   670         implementation. May also return None if references are not relevant
  1145         return None
   671         for the implementation.
  1146     
       
  1147     def get_child_refs(self):
       
  1148         """
       
  1149         ImplContainer always None with get_refs so it one wants to get the references from all 
       
  1150         leaf child objects, one can use this get_child_refs function
       
  1151         @return: a list of references.
   672         """
  1152         """
   673         refs = []
  1153         refs = []
   674         for impl in self.impls:
  1154         for impl in self.impls:
   675             subrefs = impl.get_refs()
  1155             if isinstance(impl, ImplContainer):
   676             if subrefs:
  1156                 refs += impl.get_child_refs()
   677                 refs += subrefs
  1157             else:
   678         if refs:
  1158                 refs += impl.get_refs() or []
   679             return utils.distinct_array(refs)
  1159         return utils.distinct_array(refs)
   680         else:
  1160 
   681             return None 
  1161     def has_tag(self, tags, policy=None):
   682 
  1162         # Container always returns True
       
  1163         return True
       
  1164     
   683     def get_tags(self):
  1165     def get_tags(self):
   684         """
  1166         # Containers always return None, because the tag-based filtering
   685         overloading the get_tags function in ImplContainer to create sum of 
  1167         # happens only on the actual implementations
   686         tags of all subelements of the Container
  1168         return None
   687         @return: dictionary of tags
  1169 
   688         """
  1170     def get_child_tags(self):
   689         tags = ImplBase.get_tags(self)
  1171         """
       
  1172         ImplContainer always None with get_tags so it one wants to get the teags from all 
       
  1173         leaf child objects, one can use this get_child_tags function
       
  1174         @return: a list of references.
       
  1175         """
       
  1176         tags = {}
   690         for impl in self.impls:
  1177         for impl in self.impls:
   691             # Update the dict by appending new elements to the values instead 
  1178             if isinstance(impl, ImplContainer):
   692             # of overriding
  1179                 utils.update_dict(tags, impl.get_child_tags())
   693             for key,value in impl.get_tags().iteritems():
  1180             else:
   694                 tags[key] = tags.get(key,[]) + value 
  1181                 utils.update_dict(tags, impl.get_tags())
   695         return tags
  1182         return tags
   696 
  1183 
   697     def list_output_files(self):
  1184     def list_output_files(self):
   698         """
  1185         """
   699         Return a list of output files as an array. 
  1186         Return a list of output files as an array. 
   701         files = []
  1188         files = []
   702         for impl in self.impls:
  1189         for impl in self.impls:
   703             files += impl.list_output_files()
  1190             files += impl.list_output_files()
   704         return utils.distinct_array(files)
  1191         return utils.distinct_array(files)
   705 
  1192 
       
  1193     def get_outputs(self):
       
  1194         """
       
  1195         Return a list of GenerationOutput objets as a list. 
       
  1196         """
       
  1197         outputs = []
       
  1198         for impl in self.impls:
       
  1199             outputs += impl.get_outputs()
       
  1200         return outputs
       
  1201     
   706     def set_output_root(self,output):
  1202     def set_output_root(self,output):
   707         """
  1203         """
   708         Set the root directory for the output files. The output
  1204         Set the root directory for the output files. The output
   709         @param output : path to output dir.
  1205         @param output : path to output dir.
   710         """
  1206         """
   711         self.output_root = output
  1207         self.output_root = output
   712         for impl in self.impls:
  1208         for impl in self.impls:
   713             impl.set_output_root(output) 
  1209             impl.set_output_root(output) 
   714 
  1210 
   715     def invocation_phase(self):
       
   716         """
       
   717         @return: the list of phase names in which phases this container wants to be executed. 
       
   718         """
       
   719         # use a dictionary to store phases only once 
       
   720         phases = {}
       
   721         phases[ImplBase.invocation_phase(self)] = 1
       
   722         for impl in self.impls:
       
   723             # for now only get the phases from sub ImplContainer objects 
       
   724             # this is needed until the plugin phase can be overridden with the common elems
       
   725             if isinstance(impl, ImplContainer):
       
   726                 subphases = impl.invocation_phase()
       
   727                 if isinstance(subphases, list):
       
   728                     # join the two lists as one
       
   729                     phases = phases.fromkeys(phases.keys() + subphases, 1)
       
   730                 else:
       
   731                     phases[subphases] = 1
       
   732         return phases.keys()
       
   733     
       
   734     def get_temp_variable_definitions(self):
  1211     def get_temp_variable_definitions(self):
   735         tempvars = self._tempvar_defs[:]
  1212         tempvars = self._tempvar_defs[:]
   736         for impl in self.impls:
  1213         for impl in self.impls:
   737             tempvars += impl.get_temp_variable_definitions()
  1214             tempvars += impl.get_temp_variable_definitions()
   738         return tempvars
  1215         return tempvars
   755         """
  1232         """
   756         actual_impls = []
  1233         actual_impls = []
   757         for subimpl in self.impls:
  1234         for subimpl in self.impls:
   758             actual_impls += subimpl.get_all_implementations()
  1235             actual_impls += subimpl.get_all_implementations()
   759         return actual_impls
  1236         return actual_impls
   760 
  1237     
   761 
  1238     def uses_layers(self, layers, context):
       
  1239         #log = logging.getLogger('uses_layers(%r)' % self)
       
  1240         
       
  1241         # If no sub-implementation has matching tags, the implementations would
       
  1242         # never be run in this context, so there's no need to go further in that case
       
  1243         if not self._have_impls_matching_tags(context.tags, context.tags_policy):
       
  1244             #log.debug("No impls have matching tags, returning False")
       
  1245             return False
       
  1246         
       
  1247         # If the container has a condition depending on any of the changed refs,
       
  1248         # it means that the refs can affect generation output
       
  1249         if self.condition:
       
  1250             refs = []
       
  1251             for l in layers: refs.extend(l.list_leaf_datas())
       
  1252             if uses_ref(refs, self.condition.get_refs()):
       
  1253                 #log.debug("Refs affect condition, returning True")
       
  1254                 return True
       
  1255         
       
  1256         # If the condition evaluates to False (and doesn't depend on the
       
  1257         # changed refs), the implementations won't be run, and thus they
       
  1258         # don't use the layers in this context
       
  1259         if self.condition and not self.condition.eval(context):
       
  1260             #log.debug("Condition evaluates to False, returning False")
       
  1261             return False
       
  1262         
       
  1263         for impl in self.impls:
       
  1264             # Filter out based on tags if the implementation is not
       
  1265             # a container (using ImplBase.has_tag() here since RuleML v2
       
  1266             # overrides has_tag() to always return True)
       
  1267             if not isinstance(impl, ImplContainer):
       
  1268                 if not ImplBase.has_tag(impl, context.tags, context.tags_policy):
       
  1269                     continue
       
  1270             
       
  1271             if impl.uses_layers(layers, context):
       
  1272                 #log.debug("%r uses layer, returning True" % impl)
       
  1273                 return True
       
  1274         
       
  1275         #log.debug("Returning False")
       
  1276         return False
       
  1277     
       
  1278     def _have_impls_matching_tags(self, tags, tags_policy):
       
  1279         """
       
  1280         Return if any of the container's leaf implementations use the given tags.
       
  1281         """
       
  1282         for impl in self.impls:
       
  1283             if isinstance(impl, ImplContainer):
       
  1284                 if impl._have_impls_matching_tags(tags, tags_policy):
       
  1285                     return True
       
  1286             elif ImplBase.has_tag(impl, tags, tags_policy):
       
  1287                 return True
       
  1288         return False
       
  1289         
   762 class ReaderBase(object):
  1290 class ReaderBase(object):
   763     """
  1291     """
   764     Base class for implementation readers.
  1292     Base class for implementation readers.
   765     
  1293     
   766     Each reader class supports one XML namespace, from which it reads an implementation
  1294     Each reader class supports one XML namespace, from which it reads an implementation
   777     #: Can also be None, in which case the reader will not be used
  1305     #: Can also be None, in which case the reader will not be used
   778     #: (this can be useful for defining base classes for e.g. readers
  1306     #: (this can be useful for defining base classes for e.g. readers
   779     #: for different versions of an implementation).
  1307     #: for different versions of an implementation).
   780     NAMESPACE = None
  1308     NAMESPACE = None
   781     
  1309     
       
  1310     #: ID for the namespace used in the generated XML schema files.
       
  1311     #: Must be unique, and something simple like 'someml'. 
       
  1312     NAMESPACE_ID = None
       
  1313     
       
  1314     #: Sub-ID for schema problems for this ImplML namespace.
       
  1315     #: This is used as part of the problem type for schema validation
       
  1316     #: problems. E.g. if the sub-ID is 'someml', then a schema validation
       
  1317     #: problem would have the problem type 'schema.implml.someml'.
       
  1318     #: If this is not given, then the problem type will simply be
       
  1319     #: 'schema.implml'.
       
  1320     SCHEMA_PROBLEM_SUB_ID = None
       
  1321     
       
  1322     #: The root element name of the implementation langauge supported by
       
  1323     #: the reader. This is also used in the generate XML schema files, and
       
  1324     #: must correspond to the root element name specified in the schema data.
       
  1325     #: If get_schema_data() returns None, then this determines the name of
       
  1326     #: the root element in the automatically generated default schema.
       
  1327     ROOT_ELEMENT_NAME = None
       
  1328     
   782     #: Any extra XML namespaces that should be ignored by the
  1329     #: Any extra XML namespaces that should be ignored by the
   783     #: implementation parsing machinery. This is useful for specifying
  1330     #: implementation parsing machinery. This is useful for specifying
   784     #: namespaces that are not actual ImplML namespaces, but are used
  1331     #: namespaces that are not actual ImplML namespaces, but are used
   785     #: inside an implementation (e.g. XInclude)
  1332     #: inside an implementation (e.g. XInclude)
   786     IGNORED_NAMESPACES = []
  1333     IGNORED_NAMESPACES = []
   802         @param configuration: The configuration used.
  1349         @param configuration: The configuration used.
   803         @param doc_root: The document root from which to parse the implementation.
  1350         @param doc_root: The document root from which to parse the implementation.
   804         @return: The read implementation instance, or None.
  1351         @return: The read implementation instance, or None.
   805         """
  1352         """
   806         raise exceptions.NotSupportedException()
  1353         raise exceptions.NotSupportedException()
       
  1354     
       
  1355     @classmethod
       
  1356     def read_impl_from_location(cls, resource_ref, configuration, lineno):
       
  1357         """
       
  1358         Read an implementation instance from the given resource at the given line number.
       
  1359         
       
  1360         @param resource_ref: Reference to the resource in the configuration in
       
  1361             which the given document root resides.
       
  1362         @param configuration: The configuration used.
       
  1363         @param lineno: the line number where the root node for this particular element is searched from.
       
  1364         @return: The read implementation instance, or None.
       
  1365         """
       
  1366         root =  cls._read_xml_doc_from_resource(resource_ref, configuration)
       
  1367         elemroot = utils.etree.get_elem_from_lineno(root, lineno)
       
  1368         ns, tag = utils.xml.split_tag_namespace(elemroot.tag)
       
  1369         reader = cls.get_reader_for_namespace(ns)
       
  1370         implml = reader.read_impl(resource_ref, configuration, elemroot)
       
  1371         implml.lineno = lineno
       
  1372         return implml
       
  1373 
       
  1374     @classmethod
       
  1375     def get_reader_for_namespace(cls, namespace):
       
  1376         return ImplFactory.get_reader_dict().get(namespace, None)
       
  1377     
       
  1378     @classmethod
       
  1379     def get_schema_data(cls):
       
  1380         """
       
  1381         Return the XML schema data used for validating the ImplML supported by this reader.
       
  1382         @return: The schema data as a string, or None if not available.
       
  1383         """
       
  1384         return None
   807     
  1385     
   808     @classmethod
  1386     @classmethod
   809     def _read_xml_doc_from_resource(cls, resource_ref, configuration):
  1387     def _read_xml_doc_from_resource(cls, resource_ref, configuration):
   810         """
  1388         """
   811         Parse an ElementTree instance from the given resource.
  1389         Parse an ElementTree instance from the given resource.
   845         cls.__reader_classes = ImplFactory.get_reader_dict()
  1423         cls.__reader_classes = ImplFactory.get_reader_dict()
   846         return cls.__reader_classes
  1424         return cls.__reader_classes
   847     
  1425     
   848     @classmethod
  1426     @classmethod
   849     def read_impl(cls, resource_ref, configuration, doc_root, read_impl_count=None):
  1427     def read_impl(cls, resource_ref, configuration, doc_root, read_impl_count=None):
       
  1428         on_top_level = read_impl_count == None
   850         # The variable read_impl_count is used to keep track of the number of
  1429         # The variable read_impl_count is used to keep track of the number of
   851         # currently read actual implementations. It is a list so that it can be used
  1430         # currently read actual implementations. It is a list so that it can be used
   852         # like a pointer, i.e. functions called from here can modify the number
  1431         # like a pointer, i.e. functions called from here can modify the number
   853         # inside it. A more elegant solution is not done here, since this is temporary
  1432         # inside it. A more elegant solution is not done here, since this is temporary
   854         # and the index variable in implementation instances will be changed to line_number,
  1433         # and the index variable in implementation instances will be changed to line_number,
   855         # which specifies the actual line on which the implementation is specified in the file
  1434         # which specifies the actual line on which the implementation is specified in the file
   856         if read_impl_count is None: read_impl_count = [0]
  1435         if read_impl_count is None: read_impl_count = [0]
   857         
  1436         
   858         ns, tag = utils.xml.split_tag_namespace(doc_root.tag)
  1437         ns, tag = utils.xml.split_tag_namespace(doc_root.tag)
   859         if tag != "container":
  1438         if tag != "container":
   860             logging.getLogger('cone').error("Error: The root element must be a container in %s" % (ns, resource_ref))
  1439             logging.getLogger('cone').error("Error: The root element must be a container in %s, %s" % (ns, resource_ref))
   861             
  1440             
   862         impls = []
       
   863         reader_classes = cls.get_reader_classes()
  1441         reader_classes = cls.get_reader_classes()
   864         namespaces = reader_classes.keys()
  1442         namespaces = reader_classes.keys()
   865         # Read first the root container object with attributes 
  1443         # Read first the root container object with attributes 
   866         # and then traverse through possible child containers 
  1444         # and then traverse through possible child containers 
   867         containerobj = ImplContainer(resource_ref, configuration)
  1445         containerobj = ImplContainer(resource_ref, configuration)
   868         containerobj.condition = cls.get_condition(doc_root)
  1446         containerobj.condition = cls.get_condition(doc_root)
   869         
  1447         
   870         common_data = _plugin_reader.CommonImplmlDataReader.read_data(doc_root)
  1448         containerobj._common_data = _plugin_reader.CommonImplmlDataReader.read_data(doc_root)
   871         
  1449         
   872         # traverse through the subelements
  1450         # traverse through the subelements
   873         for elem in doc_root:
  1451         for elem in doc_root:
   874             ns, tag = utils.xml.split_tag_namespace(elem.tag)
  1452             ns, tag = utils.xml.split_tag_namespace(elem.tag)
   875             if ns == cls.NAMESPACE:
  1453             if ns == cls.NAMESPACE:
   876                 # Read a sub-container from the common namespace (all other
  1454                 # Read a sub-container from the common namespace (all other
   877                 # common namespace elements were handled earlier)
  1455                 # common namespace elements were handled earlier)
   878                 if tag == "container":
  1456                 if tag == "container":
   879                     subcontainer = cls.read_impl(resource_ref, configuration, elem, read_impl_count=read_impl_count)
  1457                     subcontainer = cls.read_impl(resource_ref, configuration, elem, read_impl_count=read_impl_count)
       
  1458                     subcontainer.lineno = utils.etree.get_lineno(elem)
   880                     containerobj.append(subcontainer)
  1459                     containerobj.append(subcontainer)
   881                     subcontainer.index = None # For now all sub-containers have index = None
  1460                     subcontainer.index = None # For now all sub-containers have index = None
   882             else:
  1461             else:
   883                 # Try to read the sub implementation object from some other namespace 
  1462                 # Try to read the sub implementation object from some other namespace 
   884                 if ns not in namespaces:
  1463                 if ns not in namespaces:
   885                     logging.getLogger('cone').error("Error: no reader for namespace '%s' in %s" % (ns, resource_ref))
  1464                     logging.getLogger('cone').error("Error: no reader for namespace '%s' in %s" % (ns, resource_ref))
   886                 else:
  1465                 else:
   887                     reader = reader_classes[ns]
  1466                     reader = reader_classes[ns]
   888                     subelem = reader.read_impl(resource_ref, configuration, elem)
  1467                     subelem = reader.read_impl(resource_ref, configuration, elem)
   889                     if common_data: common_data.apply(subelem)
  1468                     subelem.lineno = utils.etree.get_lineno(elem)
   890                     containerobj.append(subelem)
  1469                     containerobj.append(subelem)
   891                     subelem.index = read_impl_count[0]
  1470                     subelem.index = read_impl_count[0]
   892                     read_impl_count[0] = read_impl_count[0] +  1
  1471                     read_impl_count[0] = read_impl_count[0] +  1
   893             
  1472         
   894         if common_data:
  1473         containerobj._tempvar_defs = containerobj._common_data.tempvar_defs
   895             common_data.apply(containerobj)
  1474         
   896             containerobj._tempvar_defs = common_data.tempvar_defs + containerobj._tempvar_defs
  1475         if on_top_level:
       
  1476             def inherit_common_data(container):
       
  1477                 for impl in container.impls:
       
  1478                     if isinstance(impl, ImplContainer):
       
  1479                         new_common_data = container._common_data.copy()
       
  1480                         new_common_data.extend(impl._common_data)
       
  1481                         impl._common_data = new_common_data
       
  1482                         inherit_common_data(impl)
       
  1483             def apply_common_data(container):
       
  1484                 for impl in container.impls:
       
  1485                     if isinstance(impl, ImplContainer):
       
  1486                         apply_common_data(impl)
       
  1487                     else:
       
  1488                         container._common_data.apply(impl)
       
  1489             inherit_common_data(containerobj)
       
  1490             apply_common_data(containerobj)
       
  1491         
   897         return containerobj
  1492         return containerobj
   898 
  1493 
   899     @classmethod
  1494     @classmethod
   900     def read_implementation(cls, xml_data):
  1495     def read_implementation(cls, xml_data):
   901         """
  1496         """
   911             right = root.get('value', 'true')
  1506             right = root.get('value', 'true')
   912             return rules.SimpleCondition(left, right)
  1507             return rules.SimpleCondition(left, right)
   913         else:
  1508         else:
   914             return None
  1509             return None
   915 
  1510 
   916 class ImplSet(sets.Set):
  1511 class ImplSet(set):
   917     """
  1512     """
   918     Implementation set class that can hold a set of ImplBase instances. 
  1513     Implementation set class that can hold a set of ImplBase instances. 
   919     """
  1514     """
   920 
  1515 
   921     """ 
  1516     """ 
   923     Each plugin instance can tell in which phase it needs to be executed. 
  1518     Each plugin instance can tell in which phase it needs to be executed. 
   924     """ 
  1519     """ 
   925     INVOCATION_PHASES = ['pre','normal','post']
  1520     INVOCATION_PHASES = ['pre','normal','post']
   926 
  1521 
   927     def __init__(self,implementations=None, generation_context=None):
  1522     def __init__(self,implementations=None, generation_context=None):
   928         super(ImplSet,self).__init__(implementations)
  1523         super(ImplSet,self).__init__(implementations or [])
   929         self.output = 'output'
  1524         self.output = 'output'
   930         if generation_context:
  1525         self.generation_context = generation_context
   931             self.generation_context = generation_context
  1526         self.ref_to_impl = {}
   932         else:
  1527     
   933             self.generation_context = GenerationContext()
  1528     def _create_ref_dict(self):
   934 
  1529         for impl in self:
       
  1530             for ref in impl.get_refs() or []:
       
  1531                 self.ref_to_impl.setdefault(ref, []).append(impl)
       
  1532  
   935     def invocation_phases(self):
  1533     def invocation_phases(self):
   936         """
  1534         """
   937         @return: A list of possible invocation phases
  1535         @return: A list of possible invocation phases
   938         """
  1536         """
   939         return self.INVOCATION_PHASES
  1537         return self.INVOCATION_PHASES
   955         """
  1553         """
   956         #for impl in self.impls:
  1554         #for impl in self.impls:
   957         #    impl.generation_context = self.generation_context
  1555         #    impl.generation_context = self.generation_context
   958         if not context:
  1556         if not context:
   959             context =  self.generation_context
  1557             context =  self.generation_context
   960         self.execute(self, 'generate', context)
  1558         else:
       
  1559             self.generation_context = context
       
  1560         # Sort by file name so that execution order is always the same
       
  1561         # (easier to compare logs)
       
  1562         sorted_impls = sorted(self, key=lambda impl: impl.ref)
       
  1563 
       
  1564         for impl in sorted_impls:
       
  1565             # 1. Check should the implementation be run from context
       
  1566             # 2. Run ImplContainer if should  
       
  1567             # 3. run other ImplBase objects if this is not a dry_run                      
       
  1568             if context.should_run(impl):
       
  1569                 if isinstance(impl, ImplContainer) or \
       
  1570                     not context.dry_run:
       
  1571                     self.execute([impl], 'generate', context)
       
  1572                     # context.have_run(impl)
   961     
  1573     
   962     def post_generate(self, context=None):
  1574     def post_generate(self, context=None):
   963         """
  1575         """
   964         @attention: This is a temporary method used for implementing cenrep_rfs.txt generation.
  1576         @attention: This is a temporary method used for implementing cenrep_rfs.txt generation.
   965         """
  1577         """
   966         if not context:
  1578         if not context:
   967             context =  self.generation_context
  1579             context =  self.generation_context
   968         self.execute(self, 'post_generate', context)
  1580         
       
  1581         impls = []
       
  1582         # Sort by file name so that execution order is always the same
       
  1583         # (easier to compare logs)
       
  1584         sorted_impls = sorted(self, key=lambda impl: impl.ref)
       
  1585         for impl in sorted_impls:
       
  1586             if context.should_run(impl, log_debug_message=False):
       
  1587                 impls.append(impl)
       
  1588         
       
  1589         self.execute(impls, 'post_generate', context)
   969 
  1590 
   970     def execute(self, implementations, methodname, *args):
  1591     def execute(self, implementations, methodname, *args):
   971         """
  1592         """
   972         Internal function for executing a function to a list of implementations.
  1593         Internal function for executing a function to a list of implementations.
   973         
  1594         
   976         specified in the file.
  1597         specified in the file.
   977         
  1598         
   978         @param implementations:
  1599         @param implementations:
   979         @param methodname: the name of the function to execute  
  1600         @param methodname: the name of the function to execute  
   980         """
  1601         """
   981         # Sort by (file_name, index_in_file) to ensure the correct execution order
  1602         for impl in implementations:
   982         impls = sorted(implementations, key=lambda impl: (impl.ref, impl.index))
       
   983         for impl in impls:
       
   984             try:
  1603             try:
   985                 impl.set_output_root(self.output)
       
   986                 if hasattr(impl, methodname): 
  1604                 if hasattr(impl, methodname): 
   987                     _member = getattr(impl, methodname)
  1605                     _member = getattr(impl, methodname)
   988                     _member(*args)
  1606                     _member(*args)
   989                 else:
  1607                 else:
   990                     logging.getLogger('cone').error('Impl %r has no method %s' % (impl, methodname))
  1608                     logging.getLogger('cone').error('Impl %r has no method %s' % (impl, methodname))
   991             except Exception, e:
  1609             except Exception, e:
       
  1610                 if self.generation_context:
       
  1611                     self.generation_context.generation_output.append(GenerationOutput('exception from %s' % impl.ref, 
       
  1612                                                                                       impl, 
       
  1613                                                                                       phase=self.generation_context.phase,              
       
  1614                                                                                       type='exception',
       
  1615                                                                                       output=self.generation_context.output,
       
  1616                                                                                       exception=e))
   992                 utils.log_exception(logging.getLogger('cone'), 'Impl %r raised an exception: %s' % (impl, repr(e)))
  1617                 utils.log_exception(logging.getLogger('cone'), 'Impl %r raised an exception: %s' % (impl, repr(e)))
   993         
  1618         
   994     
  1619     
   995     def add_implementation(self,impl):
  1620     def add_implementation(self,impl):
   996         """
  1621         """
  1057                     break
  1682                     break
  1058             if pass_filters:
  1683             if pass_filters:
  1059                 impls.append(impl)
  1684                 impls.append(impl)
  1060         return ImplSet(impls)
  1685         return ImplSet(impls)
  1061     
  1686     
       
  1687     def find_implementations(self,**kwargs):
       
  1688         """
       
  1689         Find any implementation with certain parameters.
       
  1690         All arguments are given as dict, so they must be given with name. E.g. copy(phase='normal')
       
  1691         @param phase: name of the phase
       
  1692         @param refs: A list of refs that are filtered with function has_refs
       
  1693         @param tags: A dictionary of tags that are filtered with function has_tags
       
  1694         @return: a new ImplSet object with the filtered items.
       
  1695         """
       
  1696         impls = []
       
  1697         """ Create a list of filter functions for each argument """ 
       
  1698         filters=[]
       
  1699         filters.append(lambda x: x != None)
       
  1700         if kwargs.get('phase', None) != None:
       
  1701             filters.append(lambda x: kwargs.get('phase') in x.invocation_phase())
       
  1702         if kwargs.get('refs',None) != None:
       
  1703             # Changed has_ref usage to allow not supporting refs (meaning that non supported wont be filtered with refs)
       
  1704             filters.append(lambda x: x.has_ref(kwargs.get('refs')) == True)
       
  1705         if kwargs.get('tags', None) != None:
       
  1706             filters.append(lambda x: x.has_tag(kwargs.get('tags'),kwargs.get('policy')))
       
  1707             
       
  1708         """ Go through the implementations and add all to resultset that pass all filters """ 
       
  1709         for impl in self:
       
  1710             pass_filters = True
       
  1711             for filter in filters:
       
  1712                 if not filter(impl):
       
  1713                     pass_filters = False
       
  1714                     break
       
  1715             if pass_filters:
       
  1716                 impls.append(impl)
       
  1717         return ImplSet(impls)
       
  1718 
  1062     def flat_compare(self, other):
  1719     def flat_compare(self, other):
  1063         """
  1720         """
  1064         Perform a flat comparison between this implementation container and another one.
  1721         Perform a flat comparison between this implementation container and another one.
  1065         @return: @return: A FlatComparisonResult object.
  1722         @return: @return: A FlatComparisonResult object.
  1066         """
  1723         """
  1199         
  1856         
  1200         @param configuration: The configuration where the temporary features are
  1857         @param configuration: The configuration where the temporary features are
  1201             to be created.
  1858             to be created.
  1202         @return: A list containing the references of all created temporary features.
  1859         @return: A list containing the references of all created temporary features.
  1203         
  1860         
  1204         @raise exceptions.AlreadyExists: Any of the temporary features already exists
  1861         @raise exceptions.AlreadyExists: There are duplicate temporary features defined
  1205             in the configuration, or there are duplicate temporary features defined.
  1862             in the configuration. Redefinitions of the temporaty features are only ignored.
  1206         """
  1863         """
  1207         # ----------------------------------------------------
  1864         # ----------------------------------------------------
  1208         # Collect a list of all temporary variable definitions
  1865         # Collect a list of all temporary variable definitions
  1209         # and check for duplicates and already existing
  1866         # and check for duplicates and already existing
  1210         # features at the same time
  1867         # features at the same time
  1216         for impl in self:
  1873         for impl in self:
  1217             for fea_def in impl.get_temp_variable_definitions():
  1874             for fea_def in impl.get_temp_variable_definitions():
  1218                 # Check if already exists
  1875                 # Check if already exists
  1219                 try:
  1876                 try:
  1220                     dview.get_feature(fea_def.ref)
  1877                     dview.get_feature(fea_def.ref)
  1221                     raise exceptions.AlreadyExists(
  1878                     #raise exceptions.AlreadyExists(
  1222                         "Temporary variable '%s' defined in file '%s' already exists in the configuration!" \
  1879                     #    "Temporary variable '%s' defined in file '%s' already exists in the configuration!" \
  1223                         % (fea_def.ref, impl.ref))
  1880                     #    % (fea_def.ref, impl.ref))
       
  1881                     logging.getLogger('cone').warning("Temporary variable '%s' re-definition ignored." % fea_def.ref)
       
  1882                     continue
  1224                 except exceptions.NotFound:
  1883                 except exceptions.NotFound:
  1225                     pass
  1884                     pass
  1226                 
  1885                 
  1227                 # Add to temporary dictionary for duplicate checking
  1886                 # Add to temporary dictionary for duplicate checking
  1228                 if fea_def.ref not in files_by_refs:
  1887                 if fea_def.ref not in files_by_refs:
  1244         # ------------------------------
  1903         # ------------------------------
  1245         # Create the temporary variables
  1904         # Create the temporary variables
  1246         # ------------------------------
  1905         # ------------------------------
  1247         refs = []
  1906         refs = []
  1248         if tempvar_defs:
  1907         if tempvar_defs:
  1249             logging.getLogger('cone').debug('Creating %d temporary variable(s)' % len(tempvar_defs))
  1908             logging.getLogger('cone').debug('Creating %d temporary variable(s) %r' % (len(tempvar_defs), tempvar_defs))
  1250             autoconfig = get_autoconfig(configuration)
  1909             autoconfig = get_autoconfig(configuration)
  1251             for fea_def in tempvar_defs:
  1910             for fea_def in tempvar_defs:
  1252                 fea_def.create_feature(autoconfig)
  1911                 fea_def.create_feature(autoconfig)
  1253                 refs.append(fea_def.ref)
  1912                 refs.append(fea_def.ref)
  1254             
  1913             
  1283         result = []
  1942         result = []
  1284         for impl in impl_list:
  1943         for impl in impl_list:
  1285             result += impl.get_all_implementations()
  1944             result += impl.get_all_implementations()
  1286         return result
  1945         return result
  1287 
  1946 
  1288 
  1947     def get_implemented_refs(self):
       
  1948         if not self.ref_to_impl:
       
  1949             self._create_ref_dict()
       
  1950         return sorted(self.ref_to_impl.keys())
       
  1951     
       
  1952     def get_implementations_with_ref(self, ref):
       
  1953         if not self.ref_to_impl:
       
  1954             self._create_ref_dict()
       
  1955         return sorted(self.ref_to_impl.get(ref, []), lambda a,b: cmp(a.ref, b.ref))
       
  1956     
  1289 class RelationExecutionResult(object):
  1957 class RelationExecutionResult(object):
  1290     """
  1958     """
  1291     Class representing a result from relation execution.
  1959     Class representing a result from relation execution.
  1292     """
  1960     """
  1293     def __init__(self, input_refs, affected_refs, source=None, index=None):
  1961     def __init__(self, input_refs, affected_refs, source=None, index=None):
  1332             e.g. the path to a RuleML file.
  2000             e.g. the path to a RuleML file.
  1333         """
  2001         """
  1334         self.entries = entries
  2002         self.entries = entries
  1335         self.source = source
  2003         self.source = source
  1336         
  2004         
  1337     def execute(self):
  2005     def execute(self, context=None):
  1338         """
  2006         """
  1339         Execute all relations inside the container, logging any exceptions thrown
  2007         Execute all relations inside the container, logging any exceptions thrown
  1340         during the execution.
  2008         during the execution.
  1341         @return: A list of RelationExecutionResult objects.
  2009         @return: A list of RelationExecutionResult objects.
  1342         """
  2010         """
  1343         results = []
  2011         results = []
  1344         for i, entry in enumerate(self.entries):
  2012         for i, entry in enumerate(self.entries):
       
  2013             
  1345             if isinstance(entry, rules.RelationBase):
  2014             if isinstance(entry, rules.RelationBase):
  1346                 result = self._execute_relation_and_log_error(entry, self.source, i + 1)
  2015                 result = self._execute_relation_and_log_error(entry, self.source, i + 1, context)
  1347                 if isinstance(RelationExecutionResult):
  2016                 if isinstance(RelationExecutionResult):
  1348                     results.append(result)
  2017                     results.append(result)
  1349             elif isinstance(entry, RelationContainer):
  2018             elif isinstance(entry, RelationContainer):
  1350                 results.extend(self._execute_container_and_log_error(entry))
  2019                 results.extend(self._execute_container_and_log_error(entry, context))
  1351             else:
  2020             else:
  1352                 logging.getLogger('cone').warning("Invalid RelationContainer entry: type=%s, obj=%r" % (type(entry), entry))
  2021                 logging.getLogger('cone').warning("Invalid RelationContainer entry: type=%s, obj=%r" % (type(entry), entry))
  1353         return results
  2022         return results
  1354     
  2023     
  1355     def _execute_relation_and_log_error(self, relation, source, index):
  2024     def _execute_relation_and_log_error(self, relation, source, index, context=None):
  1356         """
  2025         """
  1357         Execute a relation, logging any exceptions that may be thrown.
  2026         Execute a relation, logging any exceptions that may be thrown.
  1358         @param relation: The relation to execute.
  2027         @param relation: The relation to execute.
  1359         @param source: The source of the rule.
  2028         @param source: The source of the rule.
  1360         @param index: The index of the rule, can be None if the index is not known.
  2029         @param index: The index of the rule, can be None if the index is not known.
  1361         @return: The return value from the relation execution, or None if an error occurred.
  2030         @return: The return value from the relation execution, or None if an error occurred.
  1362         """
  2031         """
  1363         try:
  2032         try: 
  1364             return relation.execute()
  2033             return relation.execute(context)
  1365         except Exception, e:
  2034         except Exception, e:
  1366             log = logging.getLogger('cone')
  2035             msg = "Error executing rule %r: %s: %s" % (relation, e.__class__.__name__, e)
  1367             if index is not None:
  2036             if context:
  1368                 utils.log_exception(log, "Error executing rule no. %s in '%s'" % (index, source))
  2037                 gout = GenerationOutput('exception from %s' % source, 
  1369             else:
  2038                                         relation, 
  1370                 utils.log_exception(log, "Error executing a rule in '%s'" % relation_or_container.source)
  2039                                         phase=context.phase,
       
  2040                                         type='exception',
       
  2041                                         output=context.output,
       
  2042                                         exception=msg)
       
  2043                 context.generation_output.append(gout)
       
  2044             utils.log_exception(logging.getLogger('cone'), msg)
  1371             return None
  2045             return None
  1372     
  2046     
  1373     def _execute_container_and_log_error(self, container):
  2047     def _execute_container_and_log_error(self, container, context):
  1374         """
  2048         """
  1375         Execute a relation container, logging any exceptions that may be thrown.
  2049         Execute a relation container, logging any exceptions that may be thrown.
  1376         @param relation: The relation container to execute.
  2050         @param relation: The relation container to execute.
  1377         @return: The results from the relation execution, or an empty list if an error occurred.
  2051         @return: The results from the relation execution, or an empty list if an error occurred.
  1378         """
  2052         """
  1379         try:
  2053         try:
  1380             return container.execute()
  2054             return container.execute(context)
  1381         except Exception, e:
  2055         except Exception, e:
  1382             log = logging.getLogger('cone')
  2056             log = logging.getLogger('cone')
  1383             utils.log_exception(log, "Error executing rules in '%s'" % container.source)
  2057             utils.log_exception(log, "Exception executing rules in '%s': %s" % container.source, e)
  1384             return []
  2058             return []
  1385     
  2059     
  1386     def get_relation_count(self):
  2060     def get_relation_count(self):
  1387         """
  2061         """
  1388         Return the number of relations in this container.
  2062         Return the number of relations in this container.
  1392             if isinstance(entry, RelationContainer):
  2066             if isinstance(entry, RelationContainer):
  1393                 count += entry.get_relation_count()
  2067                 count += entry.get_relation_count()
  1394             else:
  2068             else:
  1395                 count += 1
  2069                 count += 1
  1396         return count
  2070         return count
       
  2071     
       
  2072     def get_relations(self):
       
  2073         """
       
  2074         Return a list of all relations in this container.
       
  2075         """
       
  2076         result = []
       
  2077         for entry in self.entries:
       
  2078             if isinstance(entry, RelationContainer):
       
  2079                 result.extend(entry.get_relations())
       
  2080             else:
       
  2081                 result.append(entry)
       
  2082         return result
  1397     
  2083     
  1398 
  2084 
  1399 class ImplFactory(api.FactoryBase):
  2085 class ImplFactory(api.FactoryBase):
  1400 
  2086 
  1401     __registered_reader_classes = None
  2087     __registered_reader_classes = None
  1435         return a dictionary of reader classes, where key is the reader namespace
  2121         return a dictionary of reader classes, where key is the reader namespace
  1436         """
  2122         """
  1437         file_extensions = []
  2123         file_extensions = []
  1438         for reader in cls.get_reader_classes():
  2124         for reader in cls.get_reader_classes():
  1439             for fe in reader.FILE_EXTENSIONS:
  2125             for fe in reader.FILE_EXTENSIONS:
  1440                 file_extensions.append(fe.lower()) 
  2126                 fe = fe.lower()
       
  2127                 if fe not in file_extensions:
       
  2128                     file_extensions.append(fe)
  1441         return file_extensions
  2129         return file_extensions
  1442 
  2130 
  1443     @classmethod
  2131     @classmethod
  1444     def set_reader_classes_override(cls, reader_classes):
  2132     def set_reader_classes_override(cls, reader_classes):
  1445         """
  2133         """
  1476                 log.warn("'%s' entry point '%s' is not a class (%r)" % (ENTRY_POINT, entry_point.name, reader_class))
  2164                 log.warn("'%s' entry point '%s' is not a class (%r)" % (ENTRY_POINT, entry_point.name, reader_class))
  1477             elif not issubclass(reader_class, ReaderBase):
  2165             elif not issubclass(reader_class, ReaderBase):
  1478                 log.warn("'%s' entry point '%s' is not a sub-class of cone.plugin.ReaderBase (%r)" % (ENTRY_POINT, entry_point.name, reader_class))
  2166                 log.warn("'%s' entry point '%s' is not a sub-class of cone.plugin.ReaderBase (%r)" % (ENTRY_POINT, entry_point.name, reader_class))
  1479             else:
  2167             else:
  1480                 msg = "Reader class for XML namespace '%s' loaded from egg '%s' entry point '%s'" % (reader_class.NAMESPACE, ENTRY_POINT, entry_point.name)
  2168                 msg = "Reader class for XML namespace '%s' loaded from egg '%s' entry point '%s'" % (reader_class.NAMESPACE, ENTRY_POINT, entry_point.name)
  1481                 log.debug(msg)
  2169                 #log.debug(msg)
  1482                 #print msg
  2170                 #print msg
  1483                 reader_classes.append(reader_class)
  2171                 reader_classes.append(reader_class)
  1484                 
  2172                 
  1485         return reader_classes
  2173         return reader_classes
  1486 
  2174 
  1505         @return: List of implementation instances parsed and created from the file.
  2193         @return: List of implementation instances parsed and created from the file.
  1506         
  2194         
  1507         @raise NotSupportedException: The file contains an XML namespace that is
  2195         @raise NotSupportedException: The file contains an XML namespace that is
  1508             not registered as an ImplML namespace.
  2196             not registered as an ImplML namespace.
  1509         """
  2197         """
       
  2198         context = parsecontext.get_implml_context()
       
  2199         context.current_file = resource_ref
  1510         try:
  2200         try:
       
  2201             resource = configuration.get_resource(resource_ref)
       
  2202             try:        data = resource.read()
       
  2203             finally:    resource.close()
       
  2204             
       
  2205             # Schema-validation while parsing disabled for now
       
  2206             #cone.validation.schemavalidation.validate_implml_data(data)
       
  2207             
  1511             impls = []
  2208             impls = []
  1512             reader_dict = cls.get_reader_dict()
  2209             reader_dict = cls.get_reader_dict()
  1513             root = ReaderBase._read_xml_doc_from_resource(resource_ref, configuration)
  2210             
       
  2211             root =  utils.etree.fromstring(data)
  1514             ns = utils.xml.split_tag_namespace(root.tag)[0]
  2212             ns = utils.xml.split_tag_namespace(root.tag)[0]
  1515             if ns not in reader_dict.keys():
  2213             if ns not in reader_dict.keys():
  1516                 logging.getLogger('cone').error("Error: no reader for namespace '%s' in %s" % (ns, resource_ref))
  2214                 context.handle_problem(api.Problem("No reader for namespace '%s'" % ns,
       
  2215                                                    type="xml.implml",
       
  2216                                                    file=resource_ref,
       
  2217                                                    line=utils.etree.get_lineno(root)))
       
  2218                 #logging.getLogger('cone').error("Error: no reader for namespace '%s' in %s" % (ns, resource_ref))
  1517                 return []
  2219                 return []
  1518             rc = reader_dict[ns]
  2220             rc = reader_dict[ns]
  1519             # return the single implementation as a list to maintain 
  2221             # return the single implementation as a list to maintain 
  1520             # backwards compability
  2222             # backwards compability
  1521             impl = rc.read_impl(resource_ref, configuration, root)
  2223             impl = rc.read_impl(resource_ref, configuration, root)
  1522             impl.index = 0
  2224             impl.index = 0
       
  2225             impl.lineno = utils.etree.get_lineno(root)
  1523             return [impl]
  2226             return [impl]
  1524         except exceptions.ParseError, e:
  2227         except Exception, e:
  1525             # Invalid XML data in the file
  2228             if isinstance(e, exceptions.XmlParseError):
  1526             logging.getLogger('cone').error("Implementation %s reading failed with error: %s" % (resource_ref,e))
  2229                 e.problem_type = 'xml.implml'
       
  2230             context.handle_exception(e)
  1527             return []
  2231             return []
  1528 
  2232 
  1529 def get_impl_set(configuration,filter='.*'):
  2233 def get_impl_set(configuration,filter='.*'):
  1530     """
  2234     """
  1531     return a ImplSet object that contains all implementation objects related to the 
  2235     return a ImplSet object that contains all implementation objects related to the 
  1532     given configuration
  2236     given configuration
  1533     """
  2237     """
  1534     impls = configuration.get_layer().list_implml()
  2238     impls = configuration.layered_implml().flatten().values()
  1535     impls = pre_filter_impls(impls)
  2239     impls = pre_filter_impls(impls)
  1536     # filter the resources with a given filter
  2240     # filter the resources with a given filter
  1537     impls = utils.resourceref.filter_resources(impls,filter)
  2241     impls = utils.resourceref.filter_resources(impls,filter)
  1538     impl_container = create_impl_set(impls,configuration)
  2242     impl_set = create_impl_set(impls,configuration)
  1539     return impl_container
  2243     return impl_set
  1540 
  2244 
  1541 def filtered_impl_set(configuration,pathfilters=None, reffilters=None):
  2245 def filtered_impl_set(configuration,pathfilters=None, reffilters=None):
  1542     """
  2246     """
  1543     return a ImplSet object that contains all implementation objects related to the 
  2247     return a ImplSet object that contains all implementation objects related to the 
  1544     given configuration
  2248     given configuration
  1545     """
  2249     """
  1546     if pathfilters: logging.getLogger('cone').info('Filtering impls with %s' % pathfilters)
  2250     if pathfilters: logging.getLogger('cone').info('Filtering impls with %s' % pathfilters)
  1547     impls = configuration.get_layer().list_implml()
  2251     impls = configuration.layered_implml().flatten().values()
  1548     impls = pre_filter_impls(impls)
  2252     impls = pre_filter_impls(impls)
  1549     # filter the resources with a given filter
  2253     # filter the resources with a given filter
  1550     if pathfilters:
  2254     if pathfilters:
  1551         newimpls = []
  2255         newimpls = []
  1552         for filter in pathfilters:
  2256         for filter in pathfilters:
  1553             newimpls += utils.resourceref.filter_resources(impls,filter)
  2257             newimpls += utils.resourceref.filter_resources(impls,filter)
  1554         impls = utils.distinct_array(newimpls)
  2258         impls = utils.distinct_array(newimpls)
  1555     impl_container = create_impl_set(impls,configuration,reffilters)
  2259     impl_set = create_impl_set(impls,configuration,reffilters)
  1556     return impl_container
  2260     return impl_set
  1557 
  2261 
  1558 def create_impl_set(impl_filename_list, configuration,reffilters=None):
  2262 def create_impl_set(impl_filename_list, configuration,reffilters=None):
  1559     impl_filename_list = pre_filter_impls(impl_filename_list)
  2263     impl_filename_list = pre_filter_impls(impl_filename_list)
  1560     if reffilters: logging.getLogger('cone').info('Filtering with refs %s' % reffilters)
  2264     if reffilters: logging.getLogger('cone').info('Filtering with refs %s' % reffilters)
  1561     impl_container = ImplSet()
  2265     impl_container = ImplSet()
       
  2266     impl_container.generation_context = GenerationContext()
       
  2267     impl_container.generation_context.configuration = configuration
  1562     for impl in impl_filename_list:
  2268     for impl in impl_filename_list:
  1563         try:
  2269         try:
  1564             if configuration != None and ImplFactory.is_supported_impl_file(impl):
  2270             if configuration != None and ImplFactory.is_supported_impl_file(impl):
  1565                 plugin_impls = ImplFactory.get_impls_from_file(impl, configuration)
  2271                 plugin_impls = ImplFactory.get_impls_from_file(impl, configuration)
  1566                 for plugin_impl in plugin_impls:
  2272                 for plugin_impl in plugin_impls:
  1576     Pre-filter implementation file refs so that files and directories
  2282     Pre-filter implementation file refs so that files and directories
  1577     beginning with a dot (e.g. '.svn', '.scripts') are ignored.
  2283     beginning with a dot (e.g. '.svn', '.scripts') are ignored.
  1578     """
  2284     """
  1579     filter = r'(/|^|\\)\..*(/|$|\\)'
  2285     filter = r'(/|^|\\)\..*(/|$|\\)'
  1580     return utils.resourceref.neg_filter_resources(impls, filter)
  2286     return utils.resourceref.neg_filter_resources(impls, filter)
       
  2287 
       
  2288 def read_impl_from_location(resource_ref, configuration, lineno):
       
  2289     return ReaderBase.read_impl_from_location(resource_ref, configuration, lineno)