diff -r 044383f39525 -r be27ed110b50 buildframework/helium/tools/common/python/lib/configuration_model.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/buildframework/helium/tools/common/python/lib/configuration_model.py Wed Oct 28 14:39:48 2009 +0000 @@ -0,0 +1,217 @@ +#============================================================================ +#Name : configuration_model.py +#Part of : Helium + +#Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +#All rights reserved. +#This component and the accompanying materials are made available +#under the terms of the License "Eclipse Public License v1.0" +#which accompanies this distribution, and is available +#at the URL "http://www.eclipse.org/legal/epl-v10.html". +# +#Initial Contributors: +#Nokia Corporation - initial contribution. +# +#Contributors: +# +#Description: +#=============================================================================== + +import amara +from amara import bindery +import logging +import types +import copy + +_logger = logging.getLogger('configurationmodel') +#logging.basicConfig(level=logging.DEBUG) +_handler = logging.StreamHandler() +_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) +_logger.addHandler(_handler) + + +class PropertyDef(object): + """ The model definition of a property. """ + + def __init__(self, property_node): + """ Initialization. """ + if not hasattr(property_node, 'name'): + raise Exception("Name is not defined for '" + str(property_node) + "'") + if not hasattr(property_node, 'type'): + raise Exception("Type is not defined for '" + str(property_node.name) + "'") + if not hasattr(property_node, 'description'): + raise Exception("Description is not defined for '" + str(property_node.name) + "'") + + self.name = str(property_node.name) + self.editStatus = str(property_node.editStatus) + self.type = str(property_node.type) + self.description = str(property_node.description).strip() + + if len(self.description) == 0: + _logger.log(logging.ERROR, "Description has no content for '" + str(property_node.name) + "'") + + if hasattr(property_node, 'deprecated'): + self.deprecated = str(property_node.deprecated) + + def __repr__(self): + return self.name + + def __str__(self): + return self.name + + +class GroupDef(object): + """ The model definition of a group of properties. """ + def __init__(self, group_node): + """ Initialization. """ + self.name = str(group_node.name) + self.description = str(group_node.description) + self.properties = {} + self.propref = [] + for property_ in group_node.propertyRef: + self.properties[str(property_)] = property_.usage + + def check_config(self, config, items): + """ Checks that the set of properties in a group are properly defined. """ + defined_props = [p for p in self.properties.keys() if config.has_key(p)] + if len(defined_props) > 0: + required_props = [p for p in self.properties.keys() if self.properties[p] == 'required'] + required_not_defined_props = set(required_props).difference(set(defined_props)) + for undefined_property in required_not_defined_props: + items.append(UndefinedRequiredInGroupItem((self.name, undefined_property))) + + +class DataModel(object): + """ A model of the configuration properties. """ + def __init__(self, modelpath): + """ Initialization. """ + doc = amara.parse(open(modelpath, 'r')) + + self.properties = {} + self.required_props = [] + for property_ in doc.heliumDataModel.property: + self.properties[str(property_.name)] = PropertyDef(property_) + + self.nongroupedproperties = copy.copy(self.properties) + self.groups = {} + for group in doc.heliumDataModel.group: + groupobj = GroupDef(group) + self.groups[str(group.name)] = groupobj + + for prop in groupobj.properties: + groupobj.propref.append(self.properties[prop]) + if prop in self.nongroupedproperties: + del self.nongroupedproperties[prop] + + groupobj.propref.sort() + + required_props_in_group = [p for p in group.propertyRef if p.usage == 'required'] + + for required_prop in required_props_in_group: + self.required_props.append(required_prop) + if not self.properties.has_key(str(required_prop)): + raise Exception("Required property " + str(required_prop) + " is not defined!") + + def validate_config(self, config): + """ Validate the Ant configuration against the model. """ + items = [] + self._check_deprecated_properties(config, items) + self._check_undefined_properties(config, items) + self._check_undefined_properties_in_groups(config, items) + self._check_type_validation(config, items) + self._check_defined_properties_not_in_groups(config, items) + return items + + def validate_config_at_startup(self, config): + """ Validate the Ant configuration against the model at build startup. """ + items = [] + + for p in self.required_props: + if not config.has_key(str(p)): + print "Required property " + str(p) + " is not defined!" + + return items + + def _check_deprecated_properties(self, config, items): + """ Check that deprecated properties not being used. """ + deprecated_props = [p for p in self.properties.values() if hasattr(p, 'deprecated')] + for deprecated_prop in deprecated_props: + _logger.debug('Checking deprecated property: ' + str(deprecated_prop)) + if config.has_key(str(deprecated_prop)): + items.append(UsingDeprecatedItem(deprecated_prop)) + + def _check_undefined_properties(self, config, items): + """ Check for any defined properties that are not in the model. """ + undefined_properties = [p for p in config.keys() if p not in self.properties] + undefined_properties.sort() + for undefined_property in undefined_properties: + items.append(MissingFromDataModelItem(undefined_property)) + + def _check_undefined_properties_in_groups(self, config, items): + for group in self.groups.values(): + _logger.debug('Checking group: %s' % group.name) + group.check_config(config, items) + + def _check_defined_properties_not_in_groups(self, config, items): + gp = [] + for group in self.groups.values(): + gp = gp + group.properties.keys() + for p in self.properties.values(): + if not str(p) in gp: + raise Exception(str(p) + ' not in a group') + + def _check_type_validation(self, config, items): + prop_string = [p for p in self.properties.values() if p.type == 'string'] + prop_integer = [p for p in self.properties.values() if p.type == 'integer'] + prop_boolean = [p for p in self.properties.values() if p.type == 'boolean'] + prop_flag = [p for p in self.properties.values() if p.type == 'flag'] + + for prop in prop_integer: + if config.has_key(str(prop)): + if not config[str(prop)].isdigit(): + items.append(WrongTypeItem(("integer", prop))) + + for prop in prop_boolean: + if config.has_key(str(prop)) : + if not (config[str(prop)] == 'false' or 'true'): + items.append(WrongTypeItem(("boolean", prop))) + + for prop in prop_string: + if config.has_key(str(prop)): + if len(config[str(prop)]) == 0: + items.append(WrongTypeItem(("string", prop))) + + +class Item(object): + level = logging.INFO + message = '' + + def __init__(self, values): + """ Initialization. """ + self.values = values + + def log(self, logger): + logger.log(self.level, str(self)) + + def __str__(self): + return self.message % self.values + + +class MissingFromDataModelItem(Item): + level = logging.INFO + message = 'Property not in data model: %s' + + +class UsingDeprecatedItem(Item): + level = logging.WARNING + message = 'Deprecated property used: %s' + + +class UndefinedRequiredInGroupItem(Item): + level = logging.WARNING + message = 'Required property in %s group is not defined: %s' + + +class WrongTypeItem(Item): + level = logging.WARNING + message = 'Invalid %s value: %s' \ No newline at end of file