author | Richard Taylor <richard.i.taylor@nokia.com> |
Mon, 07 Dec 2009 12:50:33 +0000 | |
branch | fix |
changeset 39 | 164b0547f8a5 |
parent 29 | ee00c00df073 |
child 332 | dae2dfe18db2 |
permissions | -rw-r--r-- |
3 | 1 |
# |
2 |
# Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 |
# All rights reserved. |
|
4 |
# This component and the accompanying materials are made available |
|
5 |
# under the terms of the License "Eclipse Public License v1.0" |
|
6 |
# which accompanies this distribution, and is available |
|
7 |
# at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 |
# |
|
9 |
# Initial Contributors: |
|
10 |
# Nokia Corporation - initial contribution. |
|
11 |
# |
|
12 |
# Contributors: |
|
13 |
# |
|
14 |
# Description: |
|
15 |
# raptor_xml module |
|
16 |
# |
|
17 |
||
18 |
import os |
|
19 |
import raptor_data |
|
20 |
import raptor_utilities |
|
21 |
import xml.dom.minidom |
|
22 |
import re |
|
23 |
import generic_path |
|
24 |
||
25 |
# raptor_xml module attributes |
|
26 |
||
27 |
namespace = "http://symbian.com/xml/build" |
|
28 |
xsdVersion = "build/2_0.xsd" |
|
29 |
xsdIgnore = "build/666.xsd" |
|
30 |
||
31 |
_constructors = {"alias":raptor_data.Alias, |
|
32 |
"aliasRef":raptor_data.AliasRef, |
|
33 |
"append":raptor_data.Append, |
|
34 |
"env":raptor_data.Env, |
|
35 |
"group":raptor_data.Group, |
|
36 |
"groupRef":raptor_data.GroupRef, |
|
37 |
"interface":raptor_data.Interface, |
|
38 |
"interfaceRef":raptor_data.InterfaceRef, |
|
39 |
"param":raptor_data.Parameter, |
|
40 |
"paramgroup":raptor_data.ParameterGroup, |
|
41 |
"prepend":raptor_data.Prepend, |
|
42 |
"set":raptor_data.Set, |
|
43 |
"spec":raptor_data.Specification, |
|
44 |
"var":raptor_data.Variant, |
|
45 |
"varRef":raptor_data.VariantRef} |
|
46 |
||
47 |
||
48 |
# raptor_xml module classes |
|
49 |
||
50 |
class XMLError(Exception): |
|
51 |
pass |
|
52 |
||
53 |
# raptor_xml module functions |
|
54 |
||
55 |
def Read(Raptor, filename): |
|
56 |
"Read in a Raptor XML document" |
|
57 |
||
58 |
# try to read and parse the XML file |
|
59 |
try: |
|
60 |
dom = xml.dom.minidom.parse(filename) |
|
61 |
||
62 |
except: # a whole bag of exceptions can be raised here |
|
63 |
raise XMLError |
|
64 |
||
65 |
# <build> is always the root element |
|
66 |
build = dom.documentElement |
|
67 |
objects = [] |
|
68 |
||
69 |
fileVersion = build.getAttribute("xsi:schemaLocation") |
|
70 |
||
71 |
# ignore the file it matches the "invalid" schema |
|
72 |
if fileVersion.endswith(xsdIgnore): |
|
73 |
return objects |
|
74 |
||
75 |
# check that the file matches the expected schema |
|
76 |
if not fileVersion.endswith(xsdVersion): |
|
77 |
Raptor.Warn("file '%s' uses schema '%s' which does not end with the expected version '%s'", filename, fileVersion, xsdVersion) |
|
78 |
||
79 |
# create a Data Model object from each sub-element |
|
80 |
for child in build.childNodes: |
|
81 |
if child.namespaceURI == namespace \ |
|
82 |
and child.nodeType == child.ELEMENT_NODE: |
|
83 |
try: |
|
84 |
o = XMLtoDataModel(Raptor, child) |
|
85 |
if o is not None: |
|
86 |
objects.append(o) |
|
87 |
except raptor_data.InvalidChildError: |
|
88 |
Raptor.Warn("Invalid element %s in %s", child.localName, filename) |
|
89 |
||
90 |
# discard the XML |
|
91 |
dom.unlink() |
|
92 |
return objects |
|
93 |
||
94 |
||
95 |
def XMLtoDataModel(Raptor, node): |
|
96 |
"Create a data-model object from an XML element" |
|
97 |
||
98 |
# look-up a function to create an object from the node name |
|
99 |
try: |
|
100 |
constructor = _constructors[node.localName] |
|
101 |
||
102 |
except KeyError: |
|
103 |
Raptor.Warn("Unknown element %s", node.localName) |
|
104 |
return |
|
105 |
||
106 |
model = constructor() |
|
107 |
||
108 |
# deal with the attributes first |
|
109 |
if node.hasAttributes(): |
|
110 |
for i in range(node.attributes.length): |
|
111 |
attribute = node.attributes.item(i) |
|
112 |
try: |
|
113 |
||
114 |
model.SetProperty(attribute.localName, attribute.value) |
|
115 |
||
116 |
except raptor_data.InvalidPropertyError: |
|
117 |
Raptor.Warn("Can't set attribute %s for element %s", |
|
118 |
attribute.localName, node.localName) |
|
119 |
||
120 |
# add the sub-elements |
|
121 |
for child in node.childNodes: |
|
122 |
if child.namespaceURI == namespace \ |
|
123 |
and child.nodeType == child.ELEMENT_NODE: |
|
124 |
try: |
|
125 |
gc = XMLtoDataModel(Raptor, child) |
|
126 |
if gc is not None: |
|
127 |
model.AddChild(gc) |
|
128 |
||
129 |
except raptor_data.InvalidChildError: |
|
130 |
Raptor.Warn("Can't add child %s to element %s", |
|
131 |
child.localName, node.localName) |
|
132 |
||
133 |
# only return a valid object (or raise error) |
|
134 |
if model.Valid(): |
|
135 |
if model.IsApplicable(): |
|
136 |
return model |
|
137 |
else: |
|
138 |
return None |
|
139 |
else: |
|
140 |
raise raptor_data.InvalidChildError |
|
141 |
||
142 |
||
143 |
class SystemModelComponent(generic_path.Path): |
|
144 |
"""Path sub-class that wraps up a component bld.inf file with |
|
145 |
system_definition.xml context information.""" |
|
146 |
||
147 |
def __init__(self, aBldInfFile, aContainerNames, aSystemDefinitionFile, aSystemDefinitionBase, aSystemDefinitionVersion): |
|
148 |
generic_path.Path.__init__(self, aBldInfFile.Absolute().path) |
|
149 |
self.__ContainerNames = aContainerNames |
|
150 |
self.__SystemDefinitionFile = aSystemDefinitionFile |
|
151 |
self.__SystemDefinitionBase = aSystemDefinitionBase |
|
152 |
self.__SystemDefinitionVersion = aSystemDefinitionVersion |
|
153 |
||
154 |
def GetSystemDefinitionFile(self): |
|
155 |
return self.__SystemDefinitionFile |
|
156 |
||
157 |
def GetSystemDefinitionBase(self): |
|
158 |
return self.__SystemDefinitionBase |
|
159 |
||
160 |
def GetSystemDefinitionFile(self): |
|
161 |
return self.__SystemDefinitionVersion |
|
162 |
||
163 |
def GetContainerName(self, aContainerType): |
|
164 |
if self.__ContainerNames.has_key(aContainerType): |
|
165 |
return self.__ContainerNames[aContainerType] |
|
166 |
return "" |
|
167 |
||
168 |
||
169 |
class SystemModel(object): |
|
170 |
"""A representation of the SystemModel section of a Symbian system_definition.xml file.""" |
|
171 |
||
172 |
def __init__(self, aLogger, aSystemDefinitionFile, aSystemDefinitionBase): |
|
173 |
self.__Logger = aLogger |
|
174 |
self.__SystemDefinitionFile = aSystemDefinitionFile.GetLocalString() |
|
175 |
self.__SystemDefinitionBase = aSystemDefinitionBase.GetLocalString() |
|
176 |
self.__Version = {'MAJOR':0,'MID':0,'MINOR':0} |
|
177 |
self.__ComponentRoot = "" |
|
178 |
self.__TotalComponents = 0 |
|
179 |
self.__LayerList = [] |
|
180 |
self.__LayerDetails = {} |
|
181 |
||
182 |
self.__DOM = None |
|
183 |
self.__SystemDefinitionElement = None |
|
184 |
||
185 |
if self.__Read(): |
|
186 |
if self.__Validate(): |
|
187 |
self.__Parse() |
|
188 |
||
189 |
if self.__DOM: |
|
190 |
self.__DOM.unlink() |
|
191 |
||
192 |
def HasLayer(self, aLayer): |
|
193 |
return aLayer in self.__LayerList |
|
194 |
||
195 |
def GetLayerNames(self): |
|
196 |
return self.__LayerList |
|
197 |
||
198 |
def GetLayerComponents(self, aLayer): |
|
199 |
if not self.HasLayer(aLayer): |
|
200 |
self.__Logger.Error("System Definition layer \"%s\" does not exist in %s", aLayer, self.__SystemDefinitionFile) |
|
201 |
return [] |
|
202 |
||
203 |
return self.__LayerDetails[aLayer] |
|
204 |
||
205 |
def IsLayerBuildable(self, aLayer): |
|
206 |
if len(self.GetLayerComponents(aLayer)): |
|
207 |
return True |
|
208 |
return False |
|
209 |
||
210 |
def GetAllComponents(self): |
|
211 |
components = [] |
|
212 |
||
213 |
for layer in self.GetLayerNames(): |
|
214 |
components.extend(self.GetLayerComponents(layer)) |
|
215 |
||
216 |
return components |
|
217 |
||
218 |
def DumpLayerInfo(self, aLayer): |
|
219 |
if self.HasLayer(aLayer): |
|
220 |
self.__Logger.Info("Found %d bld.inf references in layer \"%s\"", len(self.GetLayerComponents(aLayer)), aLayer) |
|
221 |
||
222 |
def DumpInfo(self): |
|
223 |
self.__Logger.Info("Found %d bld.inf references in %s within %d layers:", len(self.GetAllComponents()), self.__SystemDefinitionFile, len(self.GetLayerNames())) |
|
224 |
self.__Logger.Info("\t%s", ", ".join(self.GetLayerNames())) |
|
29
ee00c00df073
Catchup to Perforce WIP with timing, python24
timothy.murphy@nokia.com
parents:
3
diff
changeset
|
225 |
self.__Logger.InfoDiscovery(object_type = "layers", |
ee00c00df073
Catchup to Perforce WIP with timing, python24
timothy.murphy@nokia.com
parents:
3
diff
changeset
|
226 |
count = len(self.GetLayerNames())) |
ee00c00df073
Catchup to Perforce WIP with timing, python24
timothy.murphy@nokia.com
parents:
3
diff
changeset
|
227 |
self.__Logger.InfoDiscovery(object_type = "bld.inf references", |
ee00c00df073
Catchup to Perforce WIP with timing, python24
timothy.murphy@nokia.com
parents:
3
diff
changeset
|
228 |
count = len(self.GetAllComponents())) |
3 | 229 |
|
230 |
def __Read(self): |
|
231 |
if not os.path.exists(self.__SystemDefinitionFile): |
|
232 |
self.__Logger.Error("System Definition file %s does not exist", self.__SystemDefinitionFile) |
|
233 |
return False |
|
234 |
||
235 |
self.__Logger.Info("System Definition file %s", self.__SystemDefinitionFile) |
|
236 |
||
237 |
# try to read the XML file |
|
238 |
try: |
|
239 |
self.__DOM = xml.dom.minidom.parse(self.__SystemDefinitionFile) |
|
240 |
||
241 |
except: # a whole bag of exceptions can be raised here |
|
242 |
self.__Logger.Error("Failed to parse XML file %s", self.__SystemDefinitionFile) |
|
243 |
return False |
|
244 |
||
245 |
# <SystemDefinition> is always the root element |
|
246 |
self.__SystemDefinitionElement = self.__DOM.documentElement |
|
247 |
||
248 |
return True |
|
249 |
||
250 |
def __Validate(self): |
|
251 |
# account for different schema versions in processing |
|
252 |
# old format : version >= 1.3.0 |
|
253 |
# new format : version >= 2.0.0 (assume later versions are compatible...at least for now) |
|
254 |
version = re.match(r'(?P<MAJOR>\d)\.(?P<MID>\d)(\.(?P<MINOR>\d))?', self.__SystemDefinitionElement.getAttribute("schema")) |
|
255 |
||
256 |
if not version: |
|
257 |
self.__Logger.Error("Cannot determine schema version of XML file %s", self.__SystemDefinitionFile) |
|
258 |
return False |
|
259 |
||
260 |
self.__Version['MAJOR'] = int(version.group('MAJOR')) |
|
261 |
self.__Version['MID'] = int(version.group('MID')) |
|
262 |
self.__Version['MINOR'] = int(version.group('MINOR')) |
|
263 |
||
264 |
if self.__Version['MAJOR'] == 1 and self.__Version['MID'] > 2: |
|
265 |
self.__ComponentRoot = self.__SystemDefinitionBase |
|
266 |
elif self.__Version['MAJOR'] == 2: |
|
267 |
# 2.0.0 format supports SOURCEROOT as an environment specified base - we respect this, unless |
|
268 |
# explicitly overridden on the command line |
|
269 |
if os.environ.has_key('SOURCEROOT'): |
|
270 |
self.__ComponentRoot = generic_path.Path(os.environ['SOURCEROOT']) |
|
271 |
if self.__SystemDefinitionBase and self.__SystemDefinitionBase != ".": |
|
272 |
self.__ComponentRoot = self.__SystemDefinitionBase |
|
273 |
if os.environ.has_key('SOURCEROOT'): |
|
274 |
self.__Logger.Info("Command line specified System Definition file base \'%s\' overriding environment SOURCEROOT \'%s\'", self.__SystemDefinitionBase, os.environ['SOURCEROOT']) |
|
275 |
else: |
|
276 |
self.__Logger.Error("Cannot process schema version %s of file %s", version.string, self.__SystemDefinitionFile) |
|
277 |
return False |
|
278 |
||
279 |
return True |
|
280 |
||
281 |
def __Parse(self): |
|
282 |
# find the <systemModel> element (there can be 0 or 1) and search any <layer> elements for <unit> elements with "bldFile" attributes |
|
283 |
# the <layer> context of captured "bldFile" attributes is recorded as we go |
|
284 |
for child in self.__SystemDefinitionElement.childNodes: |
|
285 |
if child.localName == "systemModel": |
|
286 |
self.__ProcessSystemModelElement(child) |
|
287 |
||
288 |
def __CreateComponent(self, aBldInfFile, aUnitElement): |
|
289 |
# take a resolved bld.inf file and associated <unit/> element and returns a populated Component object |
|
290 |
containers = {} |
|
291 |
self.__GetElementContainers(aUnitElement, containers) |
|
292 |
component = SystemModelComponent(aBldInfFile, containers, self.__SystemDefinitionFile, self.__SystemDefinitionBase, self.__Version) |
|
293 |
||
294 |
return component |
|
295 |
||
296 |
def __GetElementContainers(self, aElement, aContainers): |
|
297 |
# take a <unit/> element and creates a type->name dictionary of all of its parent containers |
|
298 |
# We're only interested in parent nodes if they're not the top-most node |
|
299 |
if aElement.parentNode.parentNode: |
|
300 |
parent = aElement.parentNode |
|
301 |
name = parent.getAttribute("name") |
|
302 |
||
303 |
if name: |
|
304 |
aContainers[parent.tagName] = name |
|
305 |
||
306 |
self.__GetElementContainers(parent, aContainers) |
|
307 |
||
308 |
def __ProcessSystemModelElement(self, aElement): |
|
309 |
"""Search for XML <unit/> elements with 'bldFile' attributes and resolve concrete bld.inf locations |
|
310 |
with an appreciation of different schema versions.""" |
|
311 |
||
312 |
if aElement.tagName == "layer": |
|
313 |
currentLayer = aElement.getAttribute("name") |
|
314 |
||
315 |
if not self.__LayerDetails.has_key(currentLayer): |
|
316 |
self.__LayerDetails[currentLayer] = [] |
|
317 |
||
318 |
if not currentLayer in self.__LayerList: |
|
319 |
self.__LayerList.append(currentLayer) |
|
320 |
||
321 |
elif aElement.tagName == "unit" and aElement.hasAttributes(): |
|
322 |
bldFileValue = aElement.getAttribute("bldFile") |
|
323 |
||
324 |
if bldFileValue: |
|
325 |
bldInfRoot = self.__ComponentRoot |
|
326 |
||
327 |
if self.__Version['MAJOR'] == 1 and self.__Version['MID'] == 4: |
|
328 |
# version 1.4.x schema paths can use DOS slashes |
|
329 |
bldFileValue = raptor_utilities.convertToUnixSlash(bldFileValue) |
|
330 |
elif self.__Version['MAJOR'] == 2: |
|
331 |
# version 2.x.x schema paths are subject to a "root" attribute off-set, if it exists |
|
332 |
rootValue = aElement.getAttribute("root") |
|
333 |
||
334 |
if rootValue: |
|
335 |
if os.environ.has_key(rootValue): |
|
336 |
bldInfRoot = generic_path.Path(os.environ[rootValue]) |
|
337 |
else: |
|
338 |
# Assume that this is an error i.e. don't attempt to resolve in relation to SOURCEROOT |
|
339 |
bldInfRoot = None |
|
340 |
self.__Logger.Error("Cannot resolve \'root\' attribute value \"%s\" in %s", rootValue, self.__SystemDefinitionFile) |
|
341 |
return |
|
342 |
||
343 |
group = generic_path.Path(bldFileValue) |
|
344 |
||
345 |
if not group.isAbsolute() and bldInfRoot: |
|
346 |
group = generic_path.Join(bldInfRoot, group) |
|
347 |
||
348 |
bldinf = generic_path.Join(group, "bld.inf").FindCaseless() |
|
349 |
||
350 |
if bldinf == None: |
|
351 |
self.__Logger.Error("No bld.inf found at %s in %s", group.GetLocalString(), self.__SystemDefinitionFile) |
|
352 |
else: |
|
353 |
component = self.__CreateComponent(bldinf, aElement) |
|
354 |
layer = component.GetContainerName("layer") |
|
355 |
if layer: |
|
356 |
self.__LayerDetails[layer].append(component) |
|
357 |
self.__TotalComponents += 1 |
|
358 |
else: |
|
359 |
self.__Logger.Error("No containing layer found for %s in %s", str(bldinf), self.__SystemDefinitionFile) |
|
360 |
||
361 |
# search the sub-elements |
|
362 |
for child in aElement.childNodes: |
|
363 |
if child.nodeType == child.ELEMENT_NODE: |
|
364 |
self.__ProcessSystemModelElement(child) |
|
365 |
||
366 |
||
367 |
# end of the raptor_xml module |