buildframework/helium/sf/python/pythoncore/lib/configuration.py
author wbernard
Fri, 13 Aug 2010 14:59:05 +0300
changeset 628 7c4a911dc066
parent 587 85df38eb4012
child 645 b8d81fa19e7d
permissions -rw-r--r--
helium_11.0.0-e00f171ca185
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
587
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
     1
#============================================================================ 
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
     2
#Name        : configuration.py 
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
     3
#Part of     : Helium 
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
     4
#
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
     5
#Partly Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
     6
#All rights reserved.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
     7
#This component and the accompanying materials are made available
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
     8
#under the terms of the License "Eclipse Public License v1.0"
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
     9
#which accompanies this distribution, and is available
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    10
#at the URL "http://www.eclipse.org/legal/epl-v10.html".
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    11
#
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    12
#Initial Contributors:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    13
#Nokia Corporation - initial contribution.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    14
#
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    15
#Contributors:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    16
#
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    17
#Description: 
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    18
# 
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    19
#==============================================================================
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    20
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    21
"""Defines an interface for accessing configurations, typically for SW builds.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    22
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    23
This interface is generally based on the Jakarta Commons Configuration API. A
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    24
configuration is a collection of properties. Builders create Configuration
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    25
objects from various source inputs.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    26
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    27
"""
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    28
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    29
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    30
import copy
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    31
import logging
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    32
import re
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    33
import time
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    34
import types
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    35
import UserDict
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    36
import xml.dom.minidom
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    37
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    38
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    39
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    40
_logger = logging.getLogger('configuration')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    41
logging.basicConfig(level=logging.INFO)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    42
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    43
class Configuration(object, UserDict.DictMixin):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    44
    """ Base Configuration object. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    45
    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    46
    key_re = re.compile(r'\${(?P<name>[._a-zA-Z0-9]+)}', re.M)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    47
    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    48
    def __init__(self, data=None):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    49
        """ Initialization. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    50
        #super(UserDict.DictMixin, self).__init__(data)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    51
        self.name = None
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    52
        self.data = {}
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    53
        if data is not None:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    54
            self.data.update(data)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    55
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    56
    def __contains__(self, key):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    57
        """ Check if a keys is defined in the dict. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    58
        return self.data.__contains__(key)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    59
    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    60
    def __getitem__(self, key, interpolate=True):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    61
        """ Get an item from the configuration via dictionary interface. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    62
        if interpolate:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    63
            return self.interpolate(self.data[key])
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    64
        return self.data[key]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    65
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    66
    def __setitem__(self, key, item):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    67
        """ Set an item from the configuration via dictionary interface. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    68
        self.data[key] = item
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    69
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    70
    def __delitem__(self, key):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    71
        """ Remove an item from the configuration via dictionary interface. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    72
        del self.data[key]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    73
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    74
    def keys(self):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    75
        """ Get the list of item keys. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    76
        return self.data.keys()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    77
    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    78
    def has_key(self, key):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    79
        """ Check if key exists. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    80
        return self.data.has_key(key)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    81
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    82
    def match_name(self, name):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    83
        """ See if the given name matches the name of this configuration. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    84
        return self.name == name
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    85
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents: 587
diff changeset
    86
    def get(self, key, failobj=None):
587
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    87
        """ Get an item from the configuration. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    88
        try:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    89
            return self.__getitem__(key)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    90
        except KeyError:
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents: 587
diff changeset
    91
            return failobj
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents: 587
diff changeset
    92
        
587
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    93
    def get_list(self, key, default_value):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    94
        """ Get a value as a list. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    95
        try:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    96
            itemlist = self.__getitem__(key)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    97
            if not isinstance(itemlist, types.ListType):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    98
                itemlist = [itemlist]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
    99
            return itemlist
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   100
        except KeyError:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   101
            return default_value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   102
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   103
    def get_int(self, key, default_value):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   104
        """ Get a value as an int. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   105
        try:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   106
            value = self.__getitem__(key)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   107
            return int(value)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   108
        except KeyError:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   109
            return default_value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   110
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   111
    def get_boolean(self, key, default_value):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   112
        """ Get a value as a boolean. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   113
        try:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   114
            value = self.__getitem__(key)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   115
            return value == "true" or value == "yes" or value == "1"
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   116
        except KeyError:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   117
            return default_value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   118
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   119
    def interpolate(self, value):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   120
        """ Search for patterns of the form '${..}' and insert matching values. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   121
        if isinstance(value, types.ListType):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   122
            value = [self.interpolate(elem) for elem in value]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   123
        else:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   124
            if isinstance(value, types.StringType) or \
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   125
               isinstance(value, types.UnicodeType) or \
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   126
               isinstance(value, types.ListType):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   127
                for match in self.key_re.finditer(value):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   128
                    for property_name in match.groups():
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   129
                        if self.has_key(property_name):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   130
                            # See if interpolation may cause infinite recursion
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   131
                            raw_property_value = self.__getitem__(property_name, False)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   132
                            #print 'raw_property_value: ' + raw_property_value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   133
                            if raw_property_value == None:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   134
                                raw_property_value = ''
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   135
                            if isinstance(raw_property_value, types.ListType):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   136
                                for prop in raw_property_value:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   137
                                    if re.search('\${' + property_name + '}', prop) != None:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   138
                                        raise Exception("Key '%s' will cause recursive interpolation with value %s" % (property_name, raw_property_value))
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   139
                            else:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   140
                                if re.search('\${' + property_name + '}', raw_property_value) != None:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   141
                                    raise Exception("Key '%s' will cause recursive interpolation with value %s" % (property_name, raw_property_value))
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   142
                                    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   143
                            # Get the property value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   144
                            property_value = self.__getitem__(property_name)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   145
                            if isinstance(property_value, types.ListType):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   146
                                property_value = ",".join(property_value)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   147
                            else:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   148
                                property_value = re.sub(r'\\', r'\\\\', property_value, re.M)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   149
                            value = re.sub('\${' + property_name + '}', property_value, value, re.M)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   150
        return value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   151
    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   152
    def __str__(self):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   153
        """ A string representation. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   154
        return self.__class__.__name__ + '[' + str(self.name) + ']'
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   155
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   156
    def __cmp__(self, other):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   157
        """ Compare with another object. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   158
        return cmp(self.__str__, other.__str__)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   159
       
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   160
       
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   161
class PropertiesConfiguration(Configuration):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   162
    """ A Configuration that parses a plain text properties file.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   163
    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   164
    This typically follows the java.util.Properties format.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   165
    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   166
    Note: This code is mostly based on this recipe
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   167
    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496795.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   168
    Copyright (c) Anand Balachandran Pillai
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   169
    """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   170
    def __init__(self, stream=None, data=None):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   171
        Configuration.__init__(self, data)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   172
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   173
        self.othercharre = re.compile(r'(?<!\\)(\s*\=)|(?<!\\)(\s*\:)')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   174
        self.othercharre2 = re.compile(r'(\s*\=)|(\s*\:)')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   175
        self.bspacere = re.compile(r'\\(?!\s$)')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   176
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   177
        if stream is not None:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   178
            self.load(stream)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   179
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   180
#    def __str__(self):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   181
#        s='{'
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   182
#        for key,value in self.data.items():
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   183
#            s = ''.join((s,key,'=',value,', '))
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   184
#
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   185
#        s=''.join((s[:-2],'}'))
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   186
#        return s
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   187
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   188
    def __parse(self, lines):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   189
        """ Parse a list of lines and create
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   190
        an internal property dictionary """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   191
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   192
        # Every line in the file must consist of either a comment
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   193
        # or a key-value pair. A key-value pair is a line consisting
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   194
        # of a key which is a combination of non-white space characters
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   195
        # The separator character between key-value pairs is a '=',
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   196
        # ':' or a whitespace character not including the newline.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   197
        # If the '=' or ':' characters are found, in the line, even
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   198
        # keys containing whitespace chars are allowed.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   199
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   200
        # A line with only a key according to the rules above is also
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   201
        # fine. In such case, the value is considered as the empty string.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   202
        # In order to include characters '=' or ':' in a key or value,
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   203
        # they have to be properly escaped using the backslash character.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   204
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   205
        # Some examples of valid key-value pairs:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   206
        #
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   207
        # key     value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   208
        # key=value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   209
        # key:value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   210
        # key     value1,value2,value3
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   211
        # key     value1,value2,value3 \
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   212
        #         value4, value5
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   213
        # key
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   214
        # This key= this value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   215
        # key = value1 value2 value3
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   216
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   217
        # Any line that starts with a '#' is considerered a comment
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   218
        # and skipped. Also any trailing or preceding whitespaces
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   219
        # are removed from the key/value.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   220
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   221
        # This is a line parser. It parses the
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   222
        # contents like by line.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   223
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   224
        lineno = 0
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   225
        i = iter(lines)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   226
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   227
        for line in i:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   228
            lineno += 1
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   229
            line = line.strip()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   230
            # Skip null lines
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   231
            if not line: 
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   232
                continue
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   233
            # Skip lines which are comments
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   234
            if line[0] == '#': 
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   235
                continue
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   236
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   237
            # Position of first separation char
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   238
            sepidx = -1
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   239
            # A flag for performing wspace re check
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   240
            #flag = 0
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   241
            # Check for valid space separation
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   242
            # First obtain the max index to which we
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   243
            # can search.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   244
            m_index = self.othercharre.search(line)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   245
            if m_index:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   246
                first, last = m_index.span()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   247
                start, end = 0, first
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   248
                #flag = 1
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   249
                wspacere = re.compile(r'(?<![\\\=\:])(\s)')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   250
            else:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   251
                if self.othercharre2.search(line):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   252
                    # Check if either '=' or ':' is present
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   253
                    # in the line. If they are then it means
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   254
                    # they are preceded by a backslash.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   255
                    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   256
                    # This means, we need to modify the
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   257
                    # wspacere a bit, not to look for
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   258
                    # : or = characters.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   259
                    wspacere = re.compile(r'(?<![\\])(\s)')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   260
                start, end = 0, len(line)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   261
                
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   262
            m2_index = wspacere.search(line, start, end)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   263
            if m2_index:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   264
                # print 'Space match=>',line
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   265
                # Means we need to split by space.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   266
                first, last = m2_index.span()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   267
                sepidx = first
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   268
            elif m_index:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   269
                # print 'Other match=>',line
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   270
                # No matching wspace char found, need
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   271
                # to split by either '=' or ':'
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   272
                first, last = m_index.span()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   273
                sepidx = last - 1
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   274
                # print line[sepidx]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   275
                
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   276
                
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   277
            # If the last character is a backslash
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   278
            # it has to be preceded by a space in which
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   279
            # case the next line is read as part of the
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   280
            # same property
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   281
            while line[-1] == '\\':
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   282
                # Read next line
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   283
                try:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   284
                    nextline = i.next()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   285
                    nextline = nextline.strip()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   286
                    lineno += 1
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   287
                    # This line will become part of the value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   288
                    line = line[:-1] + nextline
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   289
                except StopIteration:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   290
                    break
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   291
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   292
            # Now split to key,value according to separation char
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   293
            if sepidx != -1:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   294
                key, value = line[:sepidx], line[sepidx+1:]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   295
            else:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   296
                key, value = line,''
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   297
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   298
            self.processPair(key, value)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   299
            
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   300
    def processPair(self, key, value):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   301
        """ Process a (key, value) pair """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   302
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   303
        oldkey = key
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   304
        oldvalue = value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   305
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   306
        # Create key intelligently
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   307
        keyparts = self.bspacere.split(key)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   308
        # print keyparts
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   309
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   310
        strippable = False
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   311
        lastpart = keyparts[-1]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   312
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   313
        if lastpart.find('\\ ') != -1:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   314
            keyparts[-1] = lastpart.replace('\\','')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   315
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   316
        # If no backspace is found at the end, but empty
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   317
        # space is found, strip it
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   318
        elif lastpart and lastpart[-1] == ' ':
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   319
            strippable = True
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   320
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   321
        key = ''.join(keyparts)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   322
        if strippable:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   323
            key = key.strip()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   324
            oldkey = oldkey.strip()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   325
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   326
        oldvalue = self.unescape(oldvalue)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   327
        value = self.unescape(value)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   328
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   329
        self.data[key] = value.strip()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   330
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   331
#        # Check if an entry exists in pristine keys
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   332
#        if self._keymap.has_key(key):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   333
#            oldkey = self._keymap.get(key)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   334
#            self._origprops[oldkey] = oldvalue.strip()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   335
#        else:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   336
#            self._origprops[oldkey] = oldvalue.strip()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   337
#            # Store entry in keymap
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   338
#            self._keymap[key] = oldkey
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   339
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   340
    def escape(self, value):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   341
        """Java escapes the '=' and ':' in the value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   342
         string with backslashes in the store method.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   343
         So let us do the same."""
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   344
        newvalue = value.replace(':','\:')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   345
        newvalue = newvalue.replace('=','\=')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   346
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   347
        return newvalue
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   348
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   349
    def unescape(self, value):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   350
        """ Reverse of escape"""
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   351
        newvalue = value.replace('\:',':')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   352
        newvalue = newvalue.replace('\=','=')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   353
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   354
        return newvalue    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   355
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   356
    def load(self, stream):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   357
        """ Load properties from an open file stream """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   358
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   359
        # For the time being only accept file input streams
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   360
        if not(hasattr(stream, 'readlines') and callable(stream.readlines)):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   361
            raise TypeError,'Argument should be a file object!'
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   362
        # Check for the opened mode
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   363
        if hasattr(stream, 'mode') and stream.mode != 'r':
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   364
            raise ValueError,'Stream should be opened in read-only mode!'
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   365
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   366
        try:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   367
            lines = stream.readlines()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   368
            self.__parse(lines)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   369
        except IOError:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   370
            raise
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   371
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   372
    def store(self, out):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   373
        """ Serialize the properties back to a file. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   374
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   375
        if out.mode[0] != 'w':
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   376
            raise ValueError, 'Stream should be opened in write mode!'
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   377
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   378
        try:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   379
            # Write timestamp
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   380
            out.write(''.join(('# ', time.strftime('%a %b %d %H:%M:%S %Z %Y', time.localtime()), '\n')))
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   381
            
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   382
            # Write properties from the  dictionary
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   383
            for key in self.data.keys():
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   384
                value = self.data[key]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   385
                out.write(''.join((key, '=', self.escape(value), '\n')))
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   386
                
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   387
            out.close()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   388
        except IOError:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   389
            raise
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   390
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   391
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   392
class NestedConfiguration(Configuration):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   393
    """ A nested configuration that may have a parent or child configurations. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   394
    def __init__(self):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   395
        """ Initialization. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   396
        Configuration.__init__(self, None)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   397
        self.parent = None
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   398
        self.type = None
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   399
        self.abstract = None
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   400
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   401
    def isBuildable(self):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   402
        """ Is this a buildable configuration? """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   403
        return self.abstract == None
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   404
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents: 587
diff changeset
   405
    def add_property_value(self, key, value, parseList=True):
587
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   406
        """Adds a property value to the configuration.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   407
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   408
        If the property does not exist, it is added without modification.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   409
        If there is already a single value matching the key, the value is replaced by a list
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   410
        containing the original and new values.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   411
        If there is already a list, the new value is added to the list.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   412
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   413
        The value is first processed in case it also represents a list of values,
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   414
        e.g. comma-separated values.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   415
        """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   416
        if parseList and value.find(',') != -1:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   417
            value = value.split(',')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   418
            # Remove all whitespace
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   419
            value = [v.strip() for v in value]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   420
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   421
        if key in self.data:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   422
            currentValue = self.data[key]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   423
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   424
            # Make sure current value is a list
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   425
            if not isinstance(currentValue, types.ListType):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   426
                currentValue = [currentValue]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   427
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   428
            # Add new value(s)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   429
            if isinstance(value, types.ListType):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   430
                currentValue.extend(value)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   431
            else:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   432
                currentValue.append(value)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   433
            self.data[key] = currentValue
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   434
        else:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   435
            self.data[key] = value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   436
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   437
    def __getitem__(self, key, interpolate=True):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   438
        """ Get an item. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   439
        #print "__getitem__(%s, %s)" % (self.name, key)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   440
        if self.data.has_key(key):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   441
            value = super(NestedConfiguration, self).__getitem__(key, False)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   442
            if interpolate:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   443
                return self.interpolate(value)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   444
            return value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   445
        elif self.parent != None:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   446
            value = self.parent.__getitem__(key, False)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   447
            if interpolate:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   448
                return self.interpolate(value)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   449
            return value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   450
        raise KeyError('Cannot find key: ' + key)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   451
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   452
    def __setitem__(self, key, item):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   453
        """ Set the value of an item. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   454
        self.data[key] = item
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   455
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   456
    def __delitem__(self, key):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   457
        """ Remove an item. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   458
        del self.data[key]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   459
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   460
    def __contains__(self, key):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   461
        """ Check if a keys is defined in the dict. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   462
        if self.data.__contains__(key):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   463
            return True 
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   464
        elif self.parent:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   465
            return self.parent.__contains__(key)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   466
        return False
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   467
            
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   468
    def keys(self):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   469
        """ Get the list of item keys. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   470
        myKeys = self.data.keys()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   471
        if self.parent != None:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   472
            parentKeys = self.parent.keys()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   473
            for key in parentKeys:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   474
                if not key in myKeys:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   475
                    myKeys.append(key)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   476
        return myKeys
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   477
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   478
    def has_key(self, key):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   479
        """ Check if key exists. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   480
        if self.data.has_key(key):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   481
            return True
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   482
        if self.parent != None:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   483
            return self.parent.has_key(key)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   484
        return False
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   485
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   486
    def match_name(self, name):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   487
        """ See if the configuration name matches the argument. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   488
        if self.name == name:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   489
            return True
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   490
        if self.parent != None:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   491
            return self.parent.match_name(name)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   492
        return False
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   493
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   494
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   495
class Specification(NestedConfiguration):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   496
    """ Deprecated. This should be removed in future, it adds no value. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   497
    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   498
    def __init__(self):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   499
        """ Initialization. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   500
        NestedConfiguration.__init__(self)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   501
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   502
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   503
class ConfigurationSet(Configuration):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   504
    """A ConfigurationSet represents a set of configurations.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   505
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   506
    Each configuration should be processed separately. This is matching
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   507
    the Raptor model where a single XML file can contain definitions
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   508
    of multiple specifications and configurations.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   509
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   510
    It is however somewhat different from the Commons Configuration classes
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   511
    that combine configurations, e.g. CombinedConfiguration,
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   512
    CompositeConfiguration. These act to combine configurations in a way
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   513
    such that a single configuration interface is still presented to the
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   514
    client.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   515
    """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   516
    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   517
    def __init__(self, configs):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   518
        """ Initialization. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   519
        Configuration.__init__(self)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   520
        self._configs = configs
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   521
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents: 587
diff changeset
   522
    def getConfigurations(self, name=None, type_=None):
587
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   523
        """ Return a list of configs that matches the name and type specified. 
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   524
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   525
        This can be queried multiple times to retrieve different named configurations.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   526
        """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   527
        result = []
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   528
        for conf in self._configs:
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents: 587
diff changeset
   529
            if ((name != None and conf.match_name(name)) or name == None) and ((type_ != None and conf.type == type_) or type_ == None):
587
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   530
                result.append(conf)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   531
        return result
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   532
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   533
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   534
class ConfigurationBuilder(object):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   535
    """ Base class for builders that can create Configuration objects. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   536
    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   537
    def getConfiguration(self):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   538
        """Returns a Configuration object."""
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   539
        raise NotImplementedError
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   540
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   541
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   542
class NestedConfigurationBuilder(ConfigurationBuilder):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   543
    """ Builder for building Configuration objects from nested configurations. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   544
    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   545
    _constructors = {'spec':Specification, 'config':NestedConfiguration}
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   546
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   547
    def __init__(self, inputfile, configname=''):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   548
        """ Initialization. """
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents: 587
diff changeset
   549
        ConfigurationBuilder.__init__(self)
587
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   550
        self.inputfile = inputfile
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   551
        self.configname = configname
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   552
        self._warn_on_deprecated_spec = False
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents: 587
diff changeset
   553
        self.rootNode = None
587
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   554
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   555
    def getConfiguration(self):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   556
        """ Returns a ConfigurationSet object.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   557
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   558
        A ConfigurationSet represents a number of Configuration objects
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   559
        that all may need to be processed.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   560
        """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   561
        try:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   562
            dom = xml.dom.minidom.parse(self.inputfile)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   563
        except Exception, exc:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   564
            raise Exception("XML file '%s' cannot be parsed properly: %s" % (self.inputfile, exc))
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   565
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   566
        # The root element is typically <build> but can be anything
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   567
        self.rootNode = dom.documentElement
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   568
        configs = []
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   569
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   570
        # Create a flat list of buildable configurations
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   571
        for child in self.rootNode.childNodes:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   572
            if child.nodeType == xml.dom.Node.ELEMENT_NODE:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   573
                _logger.debug('Parsing children')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   574
                self.parseConfiguration(child, configs)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   575
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   576
        # Add configuration references
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   577
        references = []
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   578
        for reference in self.getReferences():
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   579
            for conf in configs:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   580
                if conf.match_name(reference[1]):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   581
                    newConf = copy.deepcopy(conf)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   582
                    newConf.name = reference[0]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   583
                    references.append(newConf)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   584
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   585
        configs = configs + references
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   586
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   587
        dom.unlink()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   588
        _logger.debug('Set of configs: ' + str(configs))
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   589
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   590
        if self._warn_on_deprecated_spec:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   591
            _logger.warning("Use of deprecated 'spec' element name in this configuration. Please rename to config")
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   592
        return ConfigurationSet(configs)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   593
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   594
    def writeToXML(self, output, config_list, config_name=None):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   595
        """write XML"""
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   596
        document = """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   597
<build>
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   598
</build>"""
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   599
        doc = xml.dom.minidom.parseString(document)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   600
        docRootNode = doc.documentElement
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   601
        configNode = doc.createElement( 'config')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   602
        docRootNode.appendChild(configNode)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   603
        if config_name is not None:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   604
            configNode.setAttribute( 'name', config_name)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   605
        configNode.setAttribute( 'abstract', 'true')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   606
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   607
        for config in config_list:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   608
            configSubNode = doc.createElement( 'config')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   609
            configNode.appendChild(configSubNode)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   610
            if config.name is not None:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   611
                configSubNode.setAttribute( 'name', config.name)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   612
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   613
            for key in config.keys():
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   614
                if type(config.__getitem__(key)) == types.ListType:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   615
                    for i in range(len(config.__getitem__(key))):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   616
                        setNode = doc.createElement( 'set')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   617
                        configSubNode.appendChild(setNode)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   618
                        setNode.setAttribute( 'name', key)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   619
                        setNode.setAttribute( 'value', config.__getitem__(key)[i]) 
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   620
                else:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   621
                    setNode = doc.createElement( 'set')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   622
                    configSubNode.appendChild(setNode)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   623
                    setNode.setAttribute( 'name', key)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   624
                    setNode.setAttribute( 'value', config.__getitem__(key))
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   625
        out = open(output, 'w+')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   626
        out.write(doc.toprettyxml())
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   627
        out.close()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   628
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents: 587
diff changeset
   629
    def getConfigurations(self, name=None, type_=None):
587
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   630
        """ Get a list of the individual configurations. 
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   631
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   632
        Once read a new builder must be opened to retrieve a differently filtered set of configurations.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   633
        """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   634
        config_set = self.getConfiguration()
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents: 587
diff changeset
   635
        return config_set.getConfigurations(name, type_)
587
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   636
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   637
    def getReferences(self):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   638
        """get references"""
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   639
        references = []
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   640
        for rootNode in self.rootNode.childNodes:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   641
            if rootNode.nodeType == xml.dom.Node.ELEMENT_NODE:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   642
                for child in rootNode.childNodes:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   643
                    if child.nodeType == xml.dom.Node.ELEMENT_NODE:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   644
                        for conf in child.childNodes:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   645
                            if conf.nodeName == 'specRef':
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   646
                                for ref in conf.getAttribute('ref').split(','):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   647
                                    if not ( child.getAttribute('abstract') and str(self.configname) == '' ):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   648
                                        references.append([child.getAttribute('name'), ref])
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   649
        return references
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   650
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   651
    def parseConfiguration(self, configNode, configs, parentConfig=None):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   652
        """ Parse an individual nested configuration. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   653
        # Create appropriate config object
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   654
        if configNode.nodeName == 'spec':
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   655
            self._warn_on_deprecated_spec = True
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   656
        constructor = self._constructors[configNode.nodeName]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   657
        config = constructor()
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   658
        _logger.debug('Configuration created: ' + str(config))
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   659
        if parentConfig != None:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   660
            config.parent = parentConfig
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   661
            #config.data.update(parentConfig.data)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   662
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   663
        # Add any attribute properties
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   664
        for i in range(configNode.attributes.length):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   665
            attribute = configNode.attributes.item(i)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   666
            if hasattr(config, attribute.name):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   667
                _logger.debug('Adding config attribute: ' + str(attribute.name))
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   668
                setattr(config, str(attribute.name), attribute.nodeValue)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   669
            else:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   670
                raise Exception('Invalid attribute for configuration: ' + attribute.name)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   671
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   672
        # Process the config element's children
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   673
        configChildNodes = []
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   674
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   675
        for child in configNode.childNodes:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   676
            if child.nodeType == xml.dom.Node.ELEMENT_NODE:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   677
                # <append> directives should add to parent values. In
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   678
                # this case initially set the value to the parent value.
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   679
                if child.nodeName == 'append':
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   680
                    name = child.getAttribute('name')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   681
                    if parentConfig != None and parentConfig.has_key(name):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   682
                        parent_value = parentConfig.__getitem__(name, False)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   683
                        if not isinstance(parent_value, types.ListType):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   684
                            parent_value = [parent_value]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   685
                        for value in parent_value:
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents: 587
diff changeset
   686
                            config.add_property_value(name, value)
587
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   687
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   688
                if child.nodeName == 'set' or child.nodeName == 'append':
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   689
                    name = child.getAttribute('name')
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   690
                    if child.hasAttribute('value'):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   691
                        value = child.getAttribute('value')
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents: 587
diff changeset
   692
                        config.add_property_value(name, value)
587
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   693
                    elif child.hasChildNodes():
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   694
                        value = ""
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   695
                        for textchild in child.childNodes:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   696
                            value += textchild.data
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents: 587
diff changeset
   697
                        config.add_property_value(name, value, False)
587
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   698
                elif child.nodeName == 'specRef':
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   699
                    for ref in child.getAttribute('ref').split(','):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   700
                        node = self.getNodeByReference(ref)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   701
                        if not node:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   702
                            raise Exception('Referenced spec not found: ' + ref)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   703
                elif self._constructors.has_key(child.nodeName):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   704
                    configChildNodes.append(child)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   705
                else:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   706
                    raise Exception('Bad configuration xml element: ' + child.nodeName)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   707
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   708
        # Only save the buildable configurations
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   709
        if config.isBuildable():
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   710
            _logger.debug('Adding config to buildable set: ' + str(config))
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   711
            configs.append(config)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   712
            
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   713
        for childConfigNode in configChildNodes:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   714
            self.parseConfiguration(childConfigNode, configs, config)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   715
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   716
    def getNodeByReference(self, refName):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   717
        """ Find a node based on a reference to it. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   718
        for child in self.rootNode.childNodes:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   719
            if child.nodeType == xml.dom.Node.ELEMENT_NODE:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   720
                for conf in child.childNodes:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   721
                    if conf.nodeName == 'spec':
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   722
                        if refName == conf.getAttribute('name'):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   723
                            return conf
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   724
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   725
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   726
class HierarchicalConfiguration(Configuration):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   727
    """ Represents hierarchical configurations such as XML documents. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   728
    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   729
    def __init__(self):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   730
        """ Initialization. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   731
        Configuration.__init__(self, None)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   732
        self._root = None
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   733
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   734
    def __getitem__(self, key, interpolate=True):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   735
        """ Get an item as a dict. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   736
        elements = self._root.xpath(_Key(key).to_xpath())
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   737
        values = [element.text for element in elements]
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   738
        value = ','.join(values)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   739
        if interpolate:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   740
            value = self.interpolate(value)
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   741
        return value
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   742
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   743
    def has_key(self, key):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   744
        """ Check if key exists. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   745
        elements = self._root.xpath(_Key(key).to_xpath())
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   746
        if len(elements) > 0:
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   747
            return True
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   748
        return False
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   749
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   750
    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   751
class _Key(object):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   752
    """ A hierarchical configuration key. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   753
    
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   754
    def __init__(self, string):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   755
        """ Initialization. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   756
        self.string = string
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   757
        
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   758
    def to_xpath(self):
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   759
        """ Convert the key to XPath syntax. """
85df38eb4012 helium_9.0-a7879c935424
wbernard
parents:
diff changeset
   760
        return self.string.replace('.', '/')
628
7c4a911dc066 helium_11.0.0-e00f171ca185
wbernard
parents: 587
diff changeset
   761