41 |
41 |
42 _logger = logging.getLogger('configuration') |
42 _logger = logging.getLogger('configuration') |
43 logging.basicConfig(level=logging.INFO) |
43 logging.basicConfig(level=logging.INFO) |
44 |
44 |
45 class Configuration(object, UserDict.DictMixin): |
45 class Configuration(object, UserDict.DictMixin): |
46 """ Base Configuration objects. """ |
46 """ Base Configuration object. """ |
47 |
47 |
48 key_re = re.compile(r'\${(?P<name>[._a-zA-Z0-9]+)}', re.M) |
48 key_re = re.compile(r'\${(?P<name>[._a-zA-Z0-9]+)}', re.M) |
49 |
49 |
50 def __init__(self, data=None): |
50 def __init__(self, data=None): |
51 """ Initialization. """ |
51 """ Initialization. """ |
52 if data == None: |
52 #super(UserDict.DictMixin, self).__init__(data) |
53 data = {} |
|
54 self.name = None |
53 self.name = None |
55 self.data = data |
54 self.data = {} |
|
55 if data is not None: |
|
56 self.data.update(data) |
56 |
57 |
57 def __contains__(self, key): |
58 def __contains__(self, key): |
58 """ Check if a keys is defined in the dict. """ |
59 """ Check if a keys is defined in the dict. """ |
59 return self.data.__contains__(key) |
60 return self.data.__contains__(key) |
60 |
61 |
73 del self.data[key] |
74 del self.data[key] |
74 |
75 |
75 def keys(self): |
76 def keys(self): |
76 """ Get the list of item keys. """ |
77 """ Get the list of item keys. """ |
77 return self.data.keys() |
78 return self.data.keys() |
|
79 |
|
80 def has_key(self, key): |
|
81 """ Check if key exists. """ |
|
82 return self.data.has_key(key) |
78 |
83 |
79 def match_name(self, name): |
84 def match_name(self, name): |
80 """ See if the given name matches the name of this configuration. """ |
85 """ See if the given name matches the name of this configuration. """ |
81 return self.name == name |
86 return self.name == name |
82 |
87 |
86 return self.__getitem__(key) |
91 return self.__getitem__(key) |
87 except KeyError: |
92 except KeyError: |
88 return default_value |
93 return default_value |
89 |
94 |
90 def get_list(self, key, default_value): |
95 def get_list(self, key, default_value): |
|
96 """ Get a value as a list. """ |
91 try: |
97 try: |
92 itemlist = self.__getitem__(key) |
98 itemlist = self.__getitem__(key) |
93 if not isinstance(itemlist, types.ListType): |
99 if not isinstance(itemlist, types.ListType): |
94 itemlist = [itemlist] |
100 itemlist = [itemlist] |
95 return itemlist |
101 return itemlist |
96 except KeyError: |
102 except KeyError: |
97 return default_value |
103 return default_value |
98 |
104 |
99 def get_int(self, key, default_value): |
105 def get_int(self, key, default_value): |
|
106 """ Get a value as an int. """ |
100 try: |
107 try: |
101 value = self.__getitem__(key) |
108 value = self.__getitem__(key) |
102 return int(value) |
109 return int(value) |
103 except KeyError: |
110 except KeyError: |
104 return default_value |
111 return default_value |
105 |
112 |
106 def get_boolean(self, key, default_value): |
113 def get_boolean(self, key, default_value): |
|
114 """ Get a value as a boolean. """ |
107 try: |
115 try: |
108 value = self.__getitem__(key) |
116 value = self.__getitem__(key) |
109 return value == "true" or value == "yes" or value == "1" |
117 return value == "true" or value == "yes" or value == "1" |
110 except KeyError: |
118 except KeyError: |
111 return default_value |
119 return default_value |
119 isinstance(value, types.UnicodeType) or \ |
127 isinstance(value, types.UnicodeType) or \ |
120 isinstance(value, types.ListType): |
128 isinstance(value, types.ListType): |
121 for match in self.key_re.finditer(value): |
129 for match in self.key_re.finditer(value): |
122 for property_name in match.groups(): |
130 for property_name in match.groups(): |
123 if self.has_key(property_name): |
131 if self.has_key(property_name): |
|
132 # See if interpolation may cause infinite recursion |
|
133 raw_property_value = self.__getitem__(property_name, False) |
|
134 #print 'raw_property_value: ' + raw_property_value |
|
135 if raw_property_value == None: |
|
136 raw_property_value = '' |
|
137 if isinstance(raw_property_value, types.ListType): |
|
138 for prop in raw_property_value: |
|
139 if re.search('\${' + property_name + '}', prop) != None: |
|
140 raise Exception("Key '%s' will cause recursive interpolation with value %s" % (property_name, raw_property_value)) |
|
141 else: |
|
142 if re.search('\${' + property_name + '}', raw_property_value) != None: |
|
143 raise Exception("Key '%s' will cause recursive interpolation with value %s" % (property_name, raw_property_value)) |
|
144 |
|
145 # Get the property value |
124 property_value = self.__getitem__(property_name) |
146 property_value = self.__getitem__(property_name) |
125 if isinstance(property_value, types.ListType): |
147 if isinstance(property_value, types.ListType): |
126 property_value = ",".join(property_value) |
148 property_value = ",".join(property_value) |
127 else: |
149 else: |
128 property_value = re.sub(r'\\', r'\\\\', property_value, re.M) |
150 property_value = re.sub(r'\\', r'\\\\', property_value, re.M) |
129 value = re.sub('\${' + property_name + '}', property_value, value, re.M) |
151 value = re.sub('\${' + property_name + '}', property_value, value, re.M) |
130 return value |
152 return value |
131 |
153 |
132 def __str__(self): |
154 def __str__(self): |
|
155 """ A string representation. """ |
133 return self.__class__.__name__ + '[' + str(self.name) + ']' |
156 return self.__class__.__name__ + '[' + str(self.name) + ']' |
134 |
157 |
135 def __cmp__(self, other): |
158 def __cmp__(self, other): |
|
159 """ Compare with another object. """ |
136 return cmp(self.__str__, other.__str__) |
160 return cmp(self.__str__, other.__str__) |
137 |
161 |
138 |
162 |
139 class PropertiesConfiguration(Configuration): |
163 class PropertiesConfiguration(Configuration): |
140 """ A Configuration that parses a plain text properties file. |
164 """ A Configuration that parses a plain text properties file. |
366 except IOError, e: |
390 except IOError, e: |
367 raise |
391 raise |
368 |
392 |
369 |
393 |
370 class NestedConfiguration(Configuration): |
394 class NestedConfiguration(Configuration): |
|
395 """ A nested configuration that may have a parent or child configurations. """ |
371 def __init__(self): |
396 def __init__(self): |
372 """ Initialization. """ |
397 """ Initialization. """ |
373 Configuration.__init__(self, None) |
398 Configuration.__init__(self, None) |
374 self.parent = None |
399 self.parent = None |
375 self.type = None |
400 self.type = None |
376 self.abstract = None |
401 self.abstract = None |
377 |
402 |
378 def isBuildable(self): |
403 def isBuildable(self): |
|
404 """ Is this a buildable configuration? """ |
379 return self.abstract == None |
405 return self.abstract == None |
380 |
406 |
381 def _addPropertyValue(self, key, value, parseList=True): |
407 def _addPropertyValue(self, key, value, parseList=True): |
382 """Adds a property value to the configuration. |
408 """Adds a property value to the configuration. |
383 |
409 |
409 self.data[key] = currentValue |
435 self.data[key] = currentValue |
410 else: |
436 else: |
411 self.data[key] = value |
437 self.data[key] = value |
412 |
438 |
413 def __getitem__(self, key, interpolate=True): |
439 def __getitem__(self, key, interpolate=True): |
|
440 """ Get an item. """ |
414 #print "__getitem__(%s, %s)" % (self.name, key) |
441 #print "__getitem__(%s, %s)" % (self.name, key) |
415 if self.data.has_key(key): |
442 if self.data.has_key(key): |
416 value = super(NestedConfiguration, self).__getitem__(key, False) |
443 value = super(NestedConfiguration, self).__getitem__(key, False) |
417 if interpolate: |
444 if interpolate: |
418 return self.interpolate(value) |
445 return self.interpolate(value) |
423 return self.interpolate(value) |
450 return self.interpolate(value) |
424 return value |
451 return value |
425 raise KeyError('Cannot find key: ' + key) |
452 raise KeyError('Cannot find key: ' + key) |
426 |
453 |
427 def __setitem__(self, key, item): |
454 def __setitem__(self, key, item): |
|
455 """ Set the value of an item. """ |
428 self.data[key] = item |
456 self.data[key] = item |
429 |
457 |
430 def __delitem__(self, key): |
458 def __delitem__(self, key): |
|
459 """ Remove an item. """ |
431 del self.data[key] |
460 del self.data[key] |
432 |
461 |
433 def __contains__(self, key): |
462 def __contains__(self, key): |
434 """ Check if a keys is defined in the dict. """ |
463 """ Check if a keys is defined in the dict. """ |
435 if self.data.__contains__(key): |
464 if self.data.__contains__(key): |
437 elif self.parent: |
466 elif self.parent: |
438 return self.parent.__contains__(key) |
467 return self.parent.__contains__(key) |
439 return False |
468 return False |
440 |
469 |
441 def keys(self): |
470 def keys(self): |
|
471 """ Get the list of item keys. """ |
442 myKeys = self.data.keys() |
472 myKeys = self.data.keys() |
443 if self.parent != None: |
473 if self.parent != None: |
444 parentKeys = self.parent.keys() |
474 parentKeys = self.parent.keys() |
445 for key in parentKeys: |
475 for key in parentKeys: |
446 if not key in myKeys: |
476 if not key in myKeys: |
447 myKeys.append(key) |
477 myKeys.append(key) |
448 return myKeys |
478 return myKeys |
|
479 |
|
480 def has_key(self, key): |
|
481 """ Check if key exists. """ |
|
482 if self.data.has_key(key): |
|
483 return True |
|
484 if self.parent != None: |
|
485 return self.parent.has_key(key) |
|
486 return False |
449 |
487 |
450 def match_name(self, name): |
488 def match_name(self, name): |
|
489 """ See if the configuration name matches the argument. """ |
451 if self.name == name: |
490 if self.name == name: |
452 return True |
491 return True |
453 if self.parent != None: |
492 if self.parent != None: |
454 return self.parent.match_name(name) |
493 return self.parent.match_name(name) |
455 return False |
494 return False |
663 elif self._constructors.has_key(child.nodeName): |
702 elif self._constructors.has_key(child.nodeName): |
664 configChildNodes.append(child) |
703 configChildNodes.append(child) |
665 else: |
704 else: |
666 raise Exception('Bad configuration xml element: ' + child.nodeName) |
705 raise Exception('Bad configuration xml element: ' + child.nodeName) |
667 |
706 |
668 for childConfigNode in configChildNodes: |
|
669 self.parseConfiguration(childConfigNode, configs, config) |
|
670 |
|
671 # Only save the buildable configurations |
707 # Only save the buildable configurations |
672 if config.isBuildable(): |
708 if config.isBuildable(): |
673 _logger.debug('Adding config to buildable set: ' + str(config)) |
709 _logger.debug('Adding config to buildable set: ' + str(config)) |
674 configs.append(config) |
710 configs.append(config) |
|
711 |
|
712 for childConfigNode in configChildNodes: |
|
713 self.parseConfiguration(childConfigNode, configs, config) |
675 |
714 |
676 def getNodeByReference(self, refName): |
715 def getNodeByReference(self, refName): |
677 """ Find a node based on a reference to it. """ |
716 """ Find a node based on a reference to it. """ |
678 for child in self.rootNode.childNodes: |
717 for child in self.rootNode.childNodes: |
679 if child.nodeType == xml.dom.Node.ELEMENT_NODE: |
718 if child.nodeType == xml.dom.Node.ELEMENT_NODE: |
698 value = ','.join(values) |
737 value = ','.join(values) |
699 if interpolate: |
738 if interpolate: |
700 value = self.interpolate(value) |
739 value = self.interpolate(value) |
701 return value |
740 return value |
702 |
741 |
|
742 def has_key(self, key): |
|
743 """ Check if key exists. """ |
|
744 elements = self._root.xpath(_Key(key).to_xpath()) |
|
745 if len(elements) > 0: |
|
746 return True |
|
747 return False |
|
748 |
703 |
749 |
704 class _Key(object): |
750 class _Key(object): |
705 """ A hierarchical configuration key. """ |
751 """ A hierarchical configuration key. """ |
706 |
752 |
707 def __init__(self, string): |
753 def __init__(self, string): |
708 """ Initialization. """ |
754 """ Initialization. """ |
709 self.string = string |
755 self.string = string |
710 |
756 |
711 def to_xpath(self): |
757 def to_xpath(self): |
|
758 """ Convert the key to XPath syntax. """ |
712 return self.string.replace('.', '/') |
759 return self.string.replace('.', '/') |
713 |
760 |
714 |
761 |
715 class XMLConfiguration(HierarchicalConfiguration): |
762 class XMLConfiguration(HierarchicalConfiguration): |
716 """ A XML-based hierarchical configuration. """ |
763 """ A XML-based hierarchical configuration. """ |