|
1 #============================================================================ |
|
2 #Name : configuration_model.py |
|
3 #Part of : Helium |
|
4 |
|
5 #Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
6 #All rights reserved. |
|
7 #This component and the accompanying materials are made available |
|
8 #under the terms of the License "Eclipse Public License v1.0" |
|
9 #which accompanies this distribution, and is available |
|
10 #at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
11 # |
|
12 #Initial Contributors: |
|
13 #Nokia Corporation - initial contribution. |
|
14 # |
|
15 #Contributors: |
|
16 # |
|
17 #Description: |
|
18 #=============================================================================== |
|
19 |
|
20 import amara |
|
21 from amara import bindery |
|
22 import logging |
|
23 import types |
|
24 import copy |
|
25 |
|
26 _logger = logging.getLogger('configurationmodel') |
|
27 #logging.basicConfig(level=logging.DEBUG) |
|
28 _handler = logging.StreamHandler() |
|
29 _handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) |
|
30 _logger.addHandler(_handler) |
|
31 |
|
32 |
|
33 class PropertyDef(object): |
|
34 """ The model definition of a property. """ |
|
35 |
|
36 def __init__(self, property_node): |
|
37 """ Initialization. """ |
|
38 if not hasattr(property_node, 'name'): |
|
39 raise Exception("Name is not defined for '" + str(property_node) + "'") |
|
40 if not hasattr(property_node, 'type'): |
|
41 raise Exception("Type is not defined for '" + str(property_node.name) + "'") |
|
42 if not hasattr(property_node, 'description'): |
|
43 raise Exception("Description is not defined for '" + str(property_node.name) + "'") |
|
44 |
|
45 self.name = str(property_node.name) |
|
46 self.editStatus = str(property_node.editStatus) |
|
47 self.type = str(property_node.type) |
|
48 self.description = str(property_node.description).strip() |
|
49 |
|
50 if len(self.description) == 0: |
|
51 _logger.log(logging.ERROR, "Description has no content for '" + str(property_node.name) + "'") |
|
52 |
|
53 if hasattr(property_node, 'deprecated'): |
|
54 self.deprecated = str(property_node.deprecated) |
|
55 |
|
56 def __repr__(self): |
|
57 return self.name |
|
58 |
|
59 def __str__(self): |
|
60 return self.name |
|
61 |
|
62 |
|
63 class GroupDef(object): |
|
64 """ The model definition of a group of properties. """ |
|
65 def __init__(self, group_node): |
|
66 """ Initialization. """ |
|
67 self.name = str(group_node.name) |
|
68 self.description = str(group_node.description) |
|
69 self.properties = {} |
|
70 self.propref = [] |
|
71 for property_ in group_node.propertyRef: |
|
72 self.properties[str(property_)] = property_.usage |
|
73 |
|
74 def check_config(self, config, items): |
|
75 """ Checks that the set of properties in a group are properly defined. """ |
|
76 defined_props = [p for p in self.properties.keys() if config.has_key(p)] |
|
77 if len(defined_props) > 0: |
|
78 required_props = [p for p in self.properties.keys() if self.properties[p] == 'required'] |
|
79 required_not_defined_props = set(required_props).difference(set(defined_props)) |
|
80 for undefined_property in required_not_defined_props: |
|
81 items.append(UndefinedRequiredInGroupItem((self.name, undefined_property))) |
|
82 |
|
83 |
|
84 class DataModel(object): |
|
85 """ A model of the configuration properties. """ |
|
86 def __init__(self, modelpath): |
|
87 """ Initialization. """ |
|
88 doc = amara.parse(open(modelpath, 'r')) |
|
89 |
|
90 self.properties = {} |
|
91 self.required_props = [] |
|
92 for property_ in doc.heliumDataModel.property: |
|
93 self.properties[str(property_.name)] = PropertyDef(property_) |
|
94 |
|
95 self.nongroupedproperties = copy.copy(self.properties) |
|
96 self.groups = {} |
|
97 for group in doc.heliumDataModel.group: |
|
98 groupobj = GroupDef(group) |
|
99 self.groups[str(group.name)] = groupobj |
|
100 |
|
101 for prop in groupobj.properties: |
|
102 groupobj.propref.append(self.properties[prop]) |
|
103 if prop in self.nongroupedproperties: |
|
104 del self.nongroupedproperties[prop] |
|
105 |
|
106 groupobj.propref.sort() |
|
107 |
|
108 required_props_in_group = [p for p in group.propertyRef if p.usage == 'required'] |
|
109 |
|
110 for required_prop in required_props_in_group: |
|
111 self.required_props.append(required_prop) |
|
112 if not self.properties.has_key(str(required_prop)): |
|
113 raise Exception("Required property " + str(required_prop) + " is not defined!") |
|
114 |
|
115 def validate_config(self, config): |
|
116 """ Validate the Ant configuration against the model. """ |
|
117 items = [] |
|
118 self._check_deprecated_properties(config, items) |
|
119 self._check_undefined_properties(config, items) |
|
120 self._check_undefined_properties_in_groups(config, items) |
|
121 self._check_type_validation(config, items) |
|
122 self._check_defined_properties_not_in_groups(config, items) |
|
123 return items |
|
124 |
|
125 def validate_config_at_startup(self, config): |
|
126 """ Validate the Ant configuration against the model at build startup. """ |
|
127 items = [] |
|
128 |
|
129 for p in self.required_props: |
|
130 if not config.has_key(str(p)): |
|
131 print "Required property " + str(p) + " is not defined!" |
|
132 |
|
133 return items |
|
134 |
|
135 def _check_deprecated_properties(self, config, items): |
|
136 """ Check that deprecated properties not being used. """ |
|
137 deprecated_props = [p for p in self.properties.values() if hasattr(p, 'deprecated')] |
|
138 for deprecated_prop in deprecated_props: |
|
139 _logger.debug('Checking deprecated property: ' + str(deprecated_prop)) |
|
140 if config.has_key(str(deprecated_prop)): |
|
141 items.append(UsingDeprecatedItem(deprecated_prop)) |
|
142 |
|
143 def _check_undefined_properties(self, config, items): |
|
144 """ Check for any defined properties that are not in the model. """ |
|
145 undefined_properties = [p for p in config.keys() if p not in self.properties] |
|
146 undefined_properties.sort() |
|
147 for undefined_property in undefined_properties: |
|
148 items.append(MissingFromDataModelItem(undefined_property)) |
|
149 |
|
150 def _check_undefined_properties_in_groups(self, config, items): |
|
151 for group in self.groups.values(): |
|
152 _logger.debug('Checking group: %s' % group.name) |
|
153 group.check_config(config, items) |
|
154 |
|
155 def _check_defined_properties_not_in_groups(self, config, items): |
|
156 gp = [] |
|
157 for group in self.groups.values(): |
|
158 gp = gp + group.properties.keys() |
|
159 for p in self.properties.values(): |
|
160 if not str(p) in gp: |
|
161 raise Exception(str(p) + ' not in a group') |
|
162 |
|
163 def _check_type_validation(self, config, items): |
|
164 prop_string = [p for p in self.properties.values() if p.type == 'string'] |
|
165 prop_integer = [p for p in self.properties.values() if p.type == 'integer'] |
|
166 prop_boolean = [p for p in self.properties.values() if p.type == 'boolean'] |
|
167 prop_flag = [p for p in self.properties.values() if p.type == 'flag'] |
|
168 |
|
169 for prop in prop_integer: |
|
170 if config.has_key(str(prop)): |
|
171 if not config[str(prop)].isdigit(): |
|
172 items.append(WrongTypeItem(("integer", prop))) |
|
173 |
|
174 for prop in prop_boolean: |
|
175 if config.has_key(str(prop)) : |
|
176 if not (config[str(prop)] == 'false' or 'true'): |
|
177 items.append(WrongTypeItem(("boolean", prop))) |
|
178 |
|
179 for prop in prop_string: |
|
180 if config.has_key(str(prop)): |
|
181 if len(config[str(prop)]) == 0: |
|
182 items.append(WrongTypeItem(("string", prop))) |
|
183 |
|
184 |
|
185 class Item(object): |
|
186 level = logging.INFO |
|
187 message = '' |
|
188 |
|
189 def __init__(self, values): |
|
190 """ Initialization. """ |
|
191 self.values = values |
|
192 |
|
193 def log(self, logger): |
|
194 logger.log(self.level, str(self)) |
|
195 |
|
196 def __str__(self): |
|
197 return self.message % self.values |
|
198 |
|
199 |
|
200 class MissingFromDataModelItem(Item): |
|
201 level = logging.INFO |
|
202 message = 'Property not in data model: %s' |
|
203 |
|
204 |
|
205 class UsingDeprecatedItem(Item): |
|
206 level = logging.WARNING |
|
207 message = 'Deprecated property used: %s' |
|
208 |
|
209 |
|
210 class UndefinedRequiredInGroupItem(Item): |
|
211 level = logging.WARNING |
|
212 message = 'Required property in %s group is not defined: %s' |
|
213 |
|
214 |
|
215 class WrongTypeItem(Item): |
|
216 level = logging.WARNING |
|
217 message = 'Invalid %s value: %s' |