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()))
|
|
225 |
|
|
226 |
def __Read(self):
|
|
227 |
if not os.path.exists(self.__SystemDefinitionFile):
|
|
228 |
self.__Logger.Error("System Definition file %s does not exist", self.__SystemDefinitionFile)
|
|
229 |
return False
|
|
230 |
|
|
231 |
self.__Logger.Info("System Definition file %s", self.__SystemDefinitionFile)
|
|
232 |
|
|
233 |
# try to read the XML file
|
|
234 |
try:
|
|
235 |
self.__DOM = xml.dom.minidom.parse(self.__SystemDefinitionFile)
|
|
236 |
|
|
237 |
except: # a whole bag of exceptions can be raised here
|
|
238 |
self.__Logger.Error("Failed to parse XML file %s", self.__SystemDefinitionFile)
|
|
239 |
return False
|
|
240 |
|
|
241 |
# <SystemDefinition> is always the root element
|
|
242 |
self.__SystemDefinitionElement = self.__DOM.documentElement
|
|
243 |
|
|
244 |
return True
|
|
245 |
|
|
246 |
def __Validate(self):
|
|
247 |
# account for different schema versions in processing
|
|
248 |
# old format : version >= 1.3.0
|
|
249 |
# new format : version >= 2.0.0 (assume later versions are compatible...at least for now)
|
|
250 |
version = re.match(r'(?P<MAJOR>\d)\.(?P<MID>\d)(\.(?P<MINOR>\d))?', self.__SystemDefinitionElement.getAttribute("schema"))
|
|
251 |
|
|
252 |
if not version:
|
|
253 |
self.__Logger.Error("Cannot determine schema version of XML file %s", self.__SystemDefinitionFile)
|
|
254 |
return False
|
|
255 |
|
|
256 |
self.__Version['MAJOR'] = int(version.group('MAJOR'))
|
|
257 |
self.__Version['MID'] = int(version.group('MID'))
|
|
258 |
self.__Version['MINOR'] = int(version.group('MINOR'))
|
|
259 |
|
|
260 |
if self.__Version['MAJOR'] == 1 and self.__Version['MID'] > 2:
|
|
261 |
self.__ComponentRoot = self.__SystemDefinitionBase
|
|
262 |
elif self.__Version['MAJOR'] == 2:
|
|
263 |
# 2.0.0 format supports SOURCEROOT as an environment specified base - we respect this, unless
|
|
264 |
# explicitly overridden on the command line
|
|
265 |
if os.environ.has_key('SOURCEROOT'):
|
|
266 |
self.__ComponentRoot = generic_path.Path(os.environ['SOURCEROOT'])
|
|
267 |
if self.__SystemDefinitionBase and self.__SystemDefinitionBase != ".":
|
|
268 |
self.__ComponentRoot = self.__SystemDefinitionBase
|
|
269 |
if os.environ.has_key('SOURCEROOT'):
|
|
270 |
self.__Logger.Info("Command line specified System Definition file base \'%s\' overriding environment SOURCEROOT \'%s\'", self.__SystemDefinitionBase, os.environ['SOURCEROOT'])
|
|
271 |
else:
|
|
272 |
self.__Logger.Error("Cannot process schema version %s of file %s", version.string, self.__SystemDefinitionFile)
|
|
273 |
return False
|
|
274 |
|
|
275 |
return True
|
|
276 |
|
|
277 |
def __Parse(self):
|
|
278 |
# find the <systemModel> element (there can be 0 or 1) and search any <layer> elements for <unit> elements with "bldFile" attributes
|
|
279 |
# the <layer> context of captured "bldFile" attributes is recorded as we go
|
|
280 |
for child in self.__SystemDefinitionElement.childNodes:
|
|
281 |
if child.localName == "systemModel":
|
|
282 |
self.__ProcessSystemModelElement(child)
|
|
283 |
|
|
284 |
def __CreateComponent(self, aBldInfFile, aUnitElement):
|
|
285 |
# take a resolved bld.inf file and associated <unit/> element and returns a populated Component object
|
|
286 |
containers = {}
|
|
287 |
self.__GetElementContainers(aUnitElement, containers)
|
|
288 |
component = SystemModelComponent(aBldInfFile, containers, self.__SystemDefinitionFile, self.__SystemDefinitionBase, self.__Version)
|
|
289 |
|
|
290 |
return component
|
|
291 |
|
|
292 |
def __GetElementContainers(self, aElement, aContainers):
|
|
293 |
# take a <unit/> element and creates a type->name dictionary of all of its parent containers
|
|
294 |
# We're only interested in parent nodes if they're not the top-most node
|
|
295 |
if aElement.parentNode.parentNode:
|
|
296 |
parent = aElement.parentNode
|
|
297 |
name = parent.getAttribute("name")
|
|
298 |
|
|
299 |
if name:
|
|
300 |
aContainers[parent.tagName] = name
|
|
301 |
|
|
302 |
self.__GetElementContainers(parent, aContainers)
|
|
303 |
|
|
304 |
def __ProcessSystemModelElement(self, aElement):
|
|
305 |
"""Search for XML <unit/> elements with 'bldFile' attributes and resolve concrete bld.inf locations
|
|
306 |
with an appreciation of different schema versions."""
|
|
307 |
|
|
308 |
if aElement.tagName == "layer":
|
|
309 |
currentLayer = aElement.getAttribute("name")
|
|
310 |
|
|
311 |
if not self.__LayerDetails.has_key(currentLayer):
|
|
312 |
self.__LayerDetails[currentLayer] = []
|
|
313 |
|
|
314 |
if not currentLayer in self.__LayerList:
|
|
315 |
self.__LayerList.append(currentLayer)
|
|
316 |
|
|
317 |
elif aElement.tagName == "unit" and aElement.hasAttributes():
|
|
318 |
bldFileValue = aElement.getAttribute("bldFile")
|
|
319 |
|
|
320 |
if bldFileValue:
|
|
321 |
bldInfRoot = self.__ComponentRoot
|
|
322 |
|
|
323 |
if self.__Version['MAJOR'] == 1 and self.__Version['MID'] == 4:
|
|
324 |
# version 1.4.x schema paths can use DOS slashes
|
|
325 |
bldFileValue = raptor_utilities.convertToUnixSlash(bldFileValue)
|
|
326 |
elif self.__Version['MAJOR'] == 2:
|
|
327 |
# version 2.x.x schema paths are subject to a "root" attribute off-set, if it exists
|
|
328 |
rootValue = aElement.getAttribute("root")
|
|
329 |
|
|
330 |
if rootValue:
|
|
331 |
if os.environ.has_key(rootValue):
|
|
332 |
bldInfRoot = generic_path.Path(os.environ[rootValue])
|
|
333 |
else:
|
|
334 |
# Assume that this is an error i.e. don't attempt to resolve in relation to SOURCEROOT
|
|
335 |
bldInfRoot = None
|
|
336 |
self.__Logger.Error("Cannot resolve \'root\' attribute value \"%s\" in %s", rootValue, self.__SystemDefinitionFile)
|
|
337 |
return
|
|
338 |
|
|
339 |
group = generic_path.Path(bldFileValue)
|
|
340 |
|
|
341 |
if not group.isAbsolute() and bldInfRoot:
|
|
342 |
group = generic_path.Join(bldInfRoot, group)
|
|
343 |
|
|
344 |
bldinf = generic_path.Join(group, "bld.inf").FindCaseless()
|
|
345 |
|
|
346 |
if bldinf == None:
|
|
347 |
self.__Logger.Error("No bld.inf found at %s in %s", group.GetLocalString(), self.__SystemDefinitionFile)
|
|
348 |
else:
|
|
349 |
component = self.__CreateComponent(bldinf, aElement)
|
|
350 |
layer = component.GetContainerName("layer")
|
|
351 |
if layer:
|
|
352 |
self.__LayerDetails[layer].append(component)
|
|
353 |
self.__TotalComponents += 1
|
|
354 |
else:
|
|
355 |
self.__Logger.Error("No containing layer found for %s in %s", str(bldinf), self.__SystemDefinitionFile)
|
|
356 |
|
|
357 |
# search the sub-elements
|
|
358 |
for child in aElement.childNodes:
|
|
359 |
if child.nodeType == child.ELEMENT_NODE:
|
|
360 |
self.__ProcessSystemModelElement(child)
|
|
361 |
|
|
362 |
|
|
363 |
# end of the raptor_xml module
|