changeset 3 | e7e0ae78773e |
parent 0 | 2e8eeb919028 |
child 4 | 0951727b8815 |
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) |