13
|
1 |
#
|
|
2 |
# Copyright (c) 2007-2010 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 |
#
|
18
|
14 |
# Description:
|
13
|
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")
|
18
|
70 |
|
13
|
71 |
# ignore the file it matches the "invalid" schema
|
|
72 |
if fileVersion.endswith(xsdIgnore):
|
|
73 |
return objects
|
18
|
74 |
|
13
|
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)
|
18
|
78 |
|
13
|
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, aLayerName, aContainerNames, aSystemDefinitionFile, aSystemDefinitionBase, aSystemDefinitionVersion):
|
|
148 |
generic_path.Path.__init__(self, aBldInfFile.Absolute().path)
|
|
149 |
self.__ContainerNames = aContainerNames
|
18
|
150 |
self.__LayerName = aLayerName
|
13
|
151 |
self.__SystemDefinitionFile = aSystemDefinitionFile
|
18
|
152 |
self.__SystemDefinitionBase = aSystemDefinitionBase
|
|
153 |
self.__SystemDefinitionVersion = aSystemDefinitionVersion
|
13
|
154 |
|
|
155 |
def GetSystemDefinitionFile(self):
|
|
156 |
return self.__SystemDefinitionFile
|
|
157 |
|
|
158 |
def GetSystemDefinitionBase(self):
|
|
159 |
return self.__SystemDefinitionBase
|
18
|
160 |
|
|
161 |
def GetSystemDefinitionVersion(self):
|
|
162 |
return self.__SystemDefinitionVersion
|
|
163 |
|
|
164 |
def GetLayerName(self):
|
13
|
165 |
return self.__LayerName
|
|
166 |
|
|
167 |
def GetContainerName(self, aContainerType):
|
|
168 |
if self.__ContainerNames.has_key(aContainerType):
|
|
169 |
return self.__ContainerNames[aContainerType]
|
|
170 |
return ""
|
|
171 |
|
|
172 |
|
|
173 |
class SystemModel(object):
|
|
174 |
"""A representation of the SystemModel section of a Symbian system_definition.xml file."""
|
|
175 |
|
|
176 |
def __init__(self, aLogger, aSystemDefinitionFile, aSystemDefinitionBase):
|
|
177 |
self.__Logger = aLogger
|
|
178 |
self.__SystemDefinitionFile = aSystemDefinitionFile.GetLocalString()
|
|
179 |
self.__SystemDefinitionBase = aSystemDefinitionBase.GetLocalString()
|
18
|
180 |
self.__Version = {'MAJOR':0,'MID':0,'MINOR':0}
|
|
181 |
self.__IdAttribute = "name"
|
13
|
182 |
self.__ComponentRoot = ""
|
|
183 |
self.__TotalComponents = 0
|
|
184 |
self.__LayerList = []
|
|
185 |
self.__LayerDetails = {}
|
18
|
186 |
self.__MissingBldInfs = {}
|
13
|
187 |
|
|
188 |
self.__DOM = None
|
|
189 |
self.__SystemDefinitionElement = None
|
|
190 |
|
|
191 |
if self.__Read():
|
|
192 |
if self.__Validate():
|
|
193 |
self.__Parse()
|
|
194 |
|
|
195 |
if self.__DOM:
|
|
196 |
self.__DOM.unlink()
|
|
197 |
|
|
198 |
def HasLayer(self, aLayer):
|
|
199 |
return aLayer in self.__LayerList
|
|
200 |
|
|
201 |
def GetLayerNames(self):
|
|
202 |
return self.__LayerList
|
|
203 |
|
|
204 |
def GetLayerComponents(self, aLayer):
|
|
205 |
if not self.HasLayer(aLayer):
|
|
206 |
self.__Logger.Error("System Definition layer \"%s\" does not exist in %s", aLayer, self.__SystemDefinitionFile)
|
|
207 |
return []
|
|
208 |
|
|
209 |
return self.__LayerDetails[aLayer]
|
|
210 |
|
|
211 |
def IsLayerBuildable(self, aLayer):
|
18
|
212 |
if aLayer in self.__MissingBldInfs:
|
|
213 |
for missingbldinf in self.__MissingBldInfs[aLayer]:
|
|
214 |
self.__Logger.Error("System Definition layer \"%s\" from system definition file \"%s\" " + \
|
|
215 |
"refers to non existent bld.inf file %s", aLayer, self.__SystemDefinitionFile, missingbldinf)
|
|
216 |
|
13
|
217 |
if len(self.GetLayerComponents(aLayer)):
|
|
218 |
return True
|
|
219 |
return False
|
|
220 |
|
18
|
221 |
|
13
|
222 |
def GetAllComponents(self):
|
|
223 |
components = []
|
|
224 |
|
|
225 |
for layer in self.GetLayerNames():
|
|
226 |
components.extend(self.GetLayerComponents(layer))
|
|
227 |
|
|
228 |
return components
|
|
229 |
|
|
230 |
def DumpLayerInfo(self, aLayer):
|
|
231 |
if self.HasLayer(aLayer):
|
|
232 |
self.__Logger.Info("Found %d bld.inf references in layer \"%s\"", len(self.GetLayerComponents(aLayer)), aLayer)
|
|
233 |
|
|
234 |
def DumpInfo(self):
|
|
235 |
self.__Logger.Info("Found %d bld.inf references in %s within %d layers:", len(self.GetAllComponents()), self.__SystemDefinitionFile, len(self.GetLayerNames()))
|
|
236 |
self.__Logger.Info("\t%s", ", ".join(self.GetLayerNames()))
|
|
237 |
self.__Logger.InfoDiscovery(object_type = "layers",
|
|
238 |
count = len(self.GetLayerNames()))
|
|
239 |
self.__Logger.InfoDiscovery(object_type = "bld.inf references",
|
|
240 |
count = len(self.GetAllComponents()))
|
|
241 |
|
|
242 |
def __Read(self):
|
|
243 |
if not os.path.exists(self.__SystemDefinitionFile):
|
|
244 |
self.__Logger.Error("System Definition file %s does not exist", self.__SystemDefinitionFile)
|
|
245 |
return False
|
|
246 |
|
|
247 |
self.__Logger.Info("System Definition file %s", self.__SystemDefinitionFile)
|
|
248 |
|
|
249 |
# try to read the XML file
|
|
250 |
try:
|
|
251 |
self.__DOM = xml.dom.minidom.parse(self.__SystemDefinitionFile)
|
|
252 |
|
|
253 |
except: # a whole bag of exceptions can be raised here
|
|
254 |
self.__Logger.Error("Failed to parse XML file %s", self.__SystemDefinitionFile)
|
|
255 |
return False
|
|
256 |
|
|
257 |
# <SystemDefinition> is always the root element
|
|
258 |
self.__SystemDefinitionElement = self.__DOM.documentElement
|
|
259 |
|
|
260 |
return True
|
|
261 |
|
|
262 |
def __Validate(self):
|
|
263 |
# account for different schema versions in processing
|
|
264 |
# old format : version >= 1.3.0
|
|
265 |
# new format : version >= 2.0.0 (assume later versions are compatible...at least for now)
|
|
266 |
version = re.match(r'(?P<MAJOR>\d)\.(?P<MID>\d)(\.(?P<MINOR>\d))?', self.__SystemDefinitionElement.getAttribute("schema"))
|
|
267 |
|
|
268 |
if not version:
|
|
269 |
self.__Logger.Error("Cannot determine schema version of XML file %s", self.__SystemDefinitionFile)
|
|
270 |
return False
|
|
271 |
|
|
272 |
self.__Version['MAJOR'] = int(version.group('MAJOR'))
|
|
273 |
self.__Version['MID'] = int(version.group('MID'))
|
|
274 |
self.__Version['MINOR'] = int(version.group('MINOR'))
|
|
275 |
|
|
276 |
if self.__Version['MAJOR'] == 1 and self.__Version['MID'] > 2:
|
|
277 |
self.__ComponentRoot = self.__SystemDefinitionBase
|
18
|
278 |
elif self.__Version['MAJOR'] == 2 or self.__Version['MAJOR'] == 3:
|
|
279 |
# 2.0.x and 3.0.0 formats support SOURCEROOT or SRCROOT as an environment specified base - we respect this, unless
|
|
280 |
# explicitly overridden on the command line
|
|
281 |
if os.environ.has_key('SRCROOT'):
|
|
282 |
self.__ComponentRoot = generic_path.Path(os.environ['SRCROOT'])
|
|
283 |
elif os.environ.has_key('SOURCEROOT'):
|
13
|
284 |
self.__ComponentRoot = generic_path.Path(os.environ['SOURCEROOT'])
|
18
|
285 |
|
|
286 |
if self.__SystemDefinitionBase and self.__SystemDefinitionBase != ".":
|
|
287 |
self.__ComponentRoot = self.__SystemDefinitionBase
|
|
288 |
if os.environ.has_key('SRCROOT'):
|
|
289 |
self.__Logger.Info("Command line specified System Definition file base \'%s\' overriding environment SRCROOT \'%s\'", self.__SystemDefinitionBase, os.environ['SRCROOT'])
|
|
290 |
elif os.environ.has_key('SOURCEROOT'):
|
|
291 |
self.__Logger.Info("Command line specified System Definition file base \'%s\' overriding environment SOURCEROOT \'%s\'", self.__SystemDefinitionBase, os.environ['SOURCEROOT'])
|
13
|
292 |
else:
|
|
293 |
self.__Logger.Error("Cannot process schema version %s of file %s", version.string, self.__SystemDefinitionFile)
|
|
294 |
return False
|
18
|
295 |
|
|
296 |
if self.__Version['MAJOR'] >= 3:
|
|
297 |
# id is the unique identifier for 3.0 and later schema
|
|
298 |
self.__IdAttribute = "id"
|
13
|
299 |
|
|
300 |
return True
|
|
301 |
|
|
302 |
def __Parse(self):
|
|
303 |
# For 2.0 and earlier: find the <systemModel> element (there can be 0 or 1) and search any <layer> elements for <unit> elements with "bldFile" attributes
|
18
|
304 |
# the <layer> context of captured "bldFile" attributes is recorded as we go
|
13
|
305 |
# For 3.0 and later, process any architectural topmost element, use the topmost element with an id as the "layer"
|
|
306 |
for child in self.__SystemDefinitionElement.childNodes:
|
|
307 |
if child.localName in ["systemModel", "layer", "package", "collection", "component"]:
|
|
308 |
self.__ProcessSystemModelElement(child)
|
|
309 |
|
|
310 |
def __CreateComponent(self, aBldInfFile, aUnitElement):
|
|
311 |
# take a resolved bld.inf file and associated <unit/> element and returns a populated Component object
|
|
312 |
containers = {}
|
18
|
313 |
self.__GetElementContainers(aUnitElement, containers)
|
13
|
314 |
layer = self.__GetEffectiveLayer(aUnitElement)
|
|
315 |
component = SystemModelComponent(aBldInfFile, layer, containers, self.__SystemDefinitionFile, self.__SystemDefinitionBase, self.__Version)
|
|
316 |
|
|
317 |
return component
|
18
|
318 |
|
|
319 |
def __GetEffectiveLayer(self, aElement):
|
28
|
320 |
# return the ID of the topmost item which has an ID. For 1.x and 2.x, this will always be layer,
|
|
321 |
# for 3.x, it will be the topmost ID'd element in the file never call this on the root element
|
18
|
322 |
if aElement.parentNode.hasAttribute(self.__IdAttribute):
|
|
323 |
return self.__GetEffectiveLayer(aElement.parentNode)
|
|
324 |
elif aElement.hasAttribute(self.__IdAttribute):
|
|
325 |
return aElement.getAttribute(self.__IdAttribute)
|
|
326 |
return ""
|
13
|
327 |
|
|
328 |
def __GetElementContainers(self, aElement, aContainers):
|
|
329 |
# take a <unit/> element and creates a type->name dictionary of all of its parent containers
|
|
330 |
# We're only interested in parent nodes if they're not the top-most node
|
|
331 |
if aElement.parentNode.parentNode:
|
|
332 |
parent = aElement.parentNode
|
|
333 |
name = parent.getAttribute(self.__IdAttribute)
|
|
334 |
|
|
335 |
if name:
|
|
336 |
aContainers[parent.tagName] = name
|
|
337 |
|
|
338 |
self.__GetElementContainers(parent, aContainers)
|
|
339 |
|
28
|
340 |
def __ProcessSystemModelMetaElement(self, aElement):
|
|
341 |
# stub method - may deal with metadata elements at some point in the future
|
|
342 |
return
|
|
343 |
|
13
|
344 |
def __ProcessSystemModelElement(self, aElement):
|
|
345 |
"""Search for XML <unit/> elements with 'bldFile' attributes and resolve concrete bld.inf locations
|
|
346 |
with an appreciation of different schema versions."""
|
18
|
347 |
|
28
|
348 |
# Metadata elements are processed separately - there are no further child nodes
|
|
349 |
# to process in this context
|
|
350 |
if aElement.tagName == "meta" :
|
|
351 |
return self.__ProcessSystemModelMetaElement(aElement)
|
|
352 |
|
13
|
353 |
# The effective "layer" is the item whose parent does not have an id (or name in 2.x and earlier)
|
|
354 |
if not aElement.parentNode.hasAttribute(self.__IdAttribute) :
|
|
355 |
currentLayer = aElement.getAttribute(self.__IdAttribute)
|
|
356 |
|
|
357 |
if not self.__LayerDetails.has_key(currentLayer):
|
|
358 |
self.__LayerDetails[currentLayer] = []
|
|
359 |
|
|
360 |
if not currentLayer in self.__LayerList:
|
|
361 |
self.__LayerList.append(currentLayer)
|
|
362 |
|
|
363 |
elif aElement.tagName == "unit" and aElement.hasAttributes():
|
|
364 |
bldFileValue = aElement.getAttribute("bldFile")
|
|
365 |
|
|
366 |
if bldFileValue:
|
|
367 |
bldInfRoot = self.__ComponentRoot
|
|
368 |
|
|
369 |
if self.__Version['MAJOR'] == 1:
|
|
370 |
# version 1.x schema paths can use DOS slashes
|
|
371 |
bldFileValue = raptor_utilities.convertToUnixSlash(bldFileValue)
|
|
372 |
elif self.__Version['MAJOR'] >= 2:
|
|
373 |
# version 2.x.x schema paths are subject to a "root" attribute off-set, if it exists
|
|
374 |
rootValue = aElement.getAttribute("root")
|
|
375 |
|
|
376 |
if rootValue:
|
|
377 |
if os.environ.has_key(rootValue):
|
|
378 |
bldInfRoot = generic_path.Path(os.environ[rootValue])
|
|
379 |
else:
|
|
380 |
# Assume that this is an error i.e. don't attempt to resolve in relation to SOURCEROOT
|
|
381 |
bldInfRoot = None
|
|
382 |
self.__Logger.Error("Cannot resolve \'root\' attribute value \"%s\" in %s", rootValue, self.__SystemDefinitionFile)
|
|
383 |
return
|
|
384 |
|
|
385 |
group = generic_path.Path(bldFileValue)
|
|
386 |
|
18
|
387 |
if self.__Version['MAJOR'] < 3:
|
|
388 |
# absolute paths are not changed by root var in 1.x and 2.x
|
13
|
389 |
if not group.isAbsolute() and bldInfRoot:
|
18
|
390 |
group = generic_path.Join(bldInfRoot, group)
|
|
391 |
else:
|
28
|
392 |
# relative paths for v3
|
|
393 |
if not group.isAbsolute():
|
|
394 |
group = generic_path.Join(generic_path.Join(self.__SystemDefinitionFile).Dir(),group)
|
|
395 |
# absolute paths for v3
|
|
396 |
# are relative to bldInfRoot if set, or relative to the drive root otherwise
|
|
397 |
elif bldInfRoot:
|
18
|
398 |
group = generic_path.Join(bldInfRoot, group)
|
13
|
399 |
|
|
400 |
bldinf = generic_path.Join(group, "bld.inf").FindCaseless()
|
|
401 |
|
|
402 |
if bldinf == None:
|
18
|
403 |
# recording layers containing non existent bld.infs
|
|
404 |
bldinfname = group.GetLocalString()
|
28
|
405 |
bldinfname = bldinfname+'/'+'bld.inf'
|
18
|
406 |
layer = self.__GetEffectiveLayer(aElement)
|
|
407 |
if not layer in self.__MissingBldInfs:
|
|
408 |
self.__MissingBldInfs[layer]=[]
|
|
409 |
self.__MissingBldInfs[layer].append(bldinfname)
|
|
410 |
|
13
|
411 |
else:
|
|
412 |
component = self.__CreateComponent(bldinf, aElement)
|
|
413 |
layer = component.GetLayerName()
|
|
414 |
if layer:
|
|
415 |
self.__LayerDetails[layer].append(component)
|
|
416 |
self.__TotalComponents += 1
|
|
417 |
else:
|
|
418 |
self.__Logger.Error("No containing layer found for %s in %s", str(bldinf), self.__SystemDefinitionFile)
|
|
419 |
|
|
420 |
# search the sub-elements
|
|
421 |
for child in aElement.childNodes:
|
|
422 |
if child.nodeType == child.ELEMENT_NODE:
|
|
423 |
self.__ProcessSystemModelElement(child)
|
|
424 |
|
|
425 |
|
|
426 |
# end of the raptor_xml module
|