buildframework/helium/tools/common/python/lib/configuration.py
changeset 179 d8ac696cc51f
parent 1 be27ed110b50
--- a/buildframework/helium/tools/common/python/lib/configuration.py	Wed Oct 28 14:39:48 2009 +0000
+++ b/buildframework/helium/tools/common/python/lib/configuration.py	Wed Dec 23 19:29:07 2009 +0200
@@ -43,16 +43,17 @@
 logging.basicConfig(level=logging.INFO)
 
 class Configuration(object, UserDict.DictMixin):
-    """ Base Configuration objects. """
+    """ Base Configuration object. """
     
     key_re = re.compile(r'\${(?P<name>[._a-zA-Z0-9]+)}', re.M)
     
     def __init__(self, data=None):
         """ Initialization. """
-        if data == None:
-            data = {}
+        #super(UserDict.DictMixin, self).__init__(data)
         self.name = None
-        self.data = data
+        self.data = {}
+        if data is not None:
+            self.data.update(data)
 
     def __contains__(self, key):
         """ Check if a keys is defined in the dict. """
@@ -75,6 +76,10 @@
     def keys(self):
         """ Get the list of item keys. """
         return self.data.keys()
+    
+    def has_key(self, key):
+        """ Check if key exists. """
+        return self.data.has_key(key)
 
     def match_name(self, name):
         """ See if the given name matches the name of this configuration. """
@@ -88,6 +93,7 @@
             return default_value
 
     def get_list(self, key, default_value):
+        """ Get a value as a list. """
         try:
             itemlist = self.__getitem__(key)
             if not isinstance(itemlist, types.ListType):
@@ -97,6 +103,7 @@
             return default_value
         
     def get_int(self, key, default_value):
+        """ Get a value as an int. """
         try:
             value = self.__getitem__(key)
             return int(value)
@@ -104,6 +111,7 @@
             return default_value
         
     def get_boolean(self, key, default_value):
+        """ Get a value as a boolean. """
         try:
             value = self.__getitem__(key)
             return value == "true" or value == "yes" or value == "1"
@@ -121,6 +129,20 @@
                 for match in self.key_re.finditer(value):
                     for property_name in match.groups():
                         if self.has_key(property_name):
+                            # See if interpolation may cause infinite recursion
+                            raw_property_value = self.__getitem__(property_name, False)
+                            #print 'raw_property_value: ' + raw_property_value
+                            if raw_property_value == None:
+                                raw_property_value = ''
+                            if isinstance(raw_property_value, types.ListType):
+                                for prop in raw_property_value:
+                                    if re.search('\${' + property_name + '}', prop) != None:
+                                        raise Exception("Key '%s' will cause recursive interpolation with value %s" % (property_name, raw_property_value))
+                            else:
+                                if re.search('\${' + property_name + '}', raw_property_value) != None:
+                                    raise Exception("Key '%s' will cause recursive interpolation with value %s" % (property_name, raw_property_value))
+                                    
+                            # Get the property value
                             property_value = self.__getitem__(property_name)
                             if isinstance(property_value, types.ListType):
                                 property_value = ",".join(property_value)
@@ -130,9 +152,11 @@
         return value
     
     def __str__(self):
+        """ A string representation. """
         return self.__class__.__name__ + '[' + str(self.name) + ']'
         
     def __cmp__(self, other):
+        """ Compare with another object. """
         return cmp(self.__str__, other.__str__)
        
        
@@ -368,6 +392,7 @@
             
 
 class NestedConfiguration(Configuration):
+    """ A nested configuration that may have a parent or child configurations. """
     def __init__(self):
         """ Initialization. """
         Configuration.__init__(self, None)
@@ -376,6 +401,7 @@
         self.abstract = None
 
     def isBuildable(self):
+        """ Is this a buildable configuration? """
         return self.abstract == None
 
     def _addPropertyValue(self, key, value, parseList=True):
@@ -411,6 +437,7 @@
             self.data[key] = value
 
     def __getitem__(self, key, interpolate=True):
+        """ Get an item. """
         #print "__getitem__(%s, %s)" % (self.name, key)
         if self.data.has_key(key):
             value = super(NestedConfiguration, self).__getitem__(key, False)
@@ -425,9 +452,11 @@
         raise KeyError('Cannot find key: ' + key)
 
     def __setitem__(self, key, item):
+        """ Set the value of an item. """
         self.data[key] = item
 
     def __delitem__(self, key):
+        """ Remove an item. """
         del self.data[key]
 
     def __contains__(self, key):
@@ -439,6 +468,7 @@
         return False
             
     def keys(self):
+        """ Get the list of item keys. """
         myKeys = self.data.keys()
         if self.parent != None:
             parentKeys = self.parent.keys()
@@ -446,8 +476,17 @@
                 if not key in myKeys:
                     myKeys.append(key)
         return myKeys
+        
+    def has_key(self, key):
+        """ Check if key exists. """
+        if self.data.has_key(key):
+            return True
+        if self.parent != None:
+            return self.parent.has_key(key)
+        return False
 
     def match_name(self, name):
+        """ See if the configuration name matches the argument. """
         if self.name == name:
             return True
         if self.parent != None:
@@ -665,13 +704,13 @@
                 else:
                     raise Exception('Bad configuration xml element: ' + child.nodeName)
 
-        for childConfigNode in configChildNodes:
-            self.parseConfiguration(childConfigNode, configs, config)
-
         # Only save the buildable configurations
         if config.isBuildable():
             _logger.debug('Adding config to buildable set: ' + str(config))
             configs.append(config)
+            
+        for childConfigNode in configChildNodes:
+            self.parseConfiguration(childConfigNode, configs, config)
 
     def getNodeByReference(self, refName):
         """ Find a node based on a reference to it. """
@@ -700,6 +739,13 @@
             value = self.interpolate(value)
         return value
         
+    def has_key(self, key):
+        """ Check if key exists. """
+        elements = self._root.xpath(_Key(key).to_xpath())
+        if len(elements) > 0:
+            return True
+        return False
+        
     
 class _Key(object):
     """ A hierarchical configuration key. """
@@ -709,6 +755,7 @@
         self.string = string
         
     def to_xpath(self):
+        """ Convert the key to XPath syntax. """
         return self.string.replace('.', '/')