0
|
1 |
#
|
|
2 |
# Copyright (c) 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 "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 |
#
|
|
16 |
|
|
17 |
import copy
|
|
18 |
import logging
|
3
|
19 |
from cone.public import exceptions, api, utils
|
|
20 |
import plugin
|
0
|
21 |
import cone.confml.model
|
|
22 |
|
|
23 |
log = logging.getLogger('cone')
|
|
24 |
|
|
25 |
# The XML namespace for common ImplML definitions
|
|
26 |
COMMON_IMPLML_NAMESPACE = "http://www.symbianfoundation.org/xml/implml/1"
|
|
27 |
|
|
28 |
# Name of the marker variable used to mark a feature as a temporary
|
|
29 |
# feature
|
|
30 |
TEMP_FEATURE_MARKER_VARNAME = '__plugin_temp_feature_marker'
|
|
31 |
|
|
32 |
class TempVariableDefinition(object):
|
|
33 |
"""
|
|
34 |
Class representing a temporary variable definition in an implementation file.
|
|
35 |
"""
|
|
36 |
|
3
|
37 |
def __init__(self, ref, type, value, lineno=None):
|
0
|
38 |
self.ref = ref
|
|
39 |
self.type = type
|
|
40 |
self.value = value
|
3
|
41 |
self.lineno = lineno
|
0
|
42 |
|
|
43 |
def create_feature(self, config):
|
|
44 |
"""
|
|
45 |
Add a feature based on this temp feature definition to the given configuration.
|
|
46 |
"""
|
|
47 |
if '.' in self.ref:
|
|
48 |
pos = self.ref.rfind('.')
|
|
49 |
ref = self.ref[pos + 1:]
|
|
50 |
namespace = self.ref[:pos]
|
|
51 |
else:
|
|
52 |
ref = self.ref
|
|
53 |
namespace = ''
|
|
54 |
|
|
55 |
mapping = {'string' : cone.confml.model.ConfmlStringSetting,
|
|
56 |
'int' : cone.confml.model.ConfmlIntSetting,
|
|
57 |
'real' : cone.confml.model.ConfmlRealSetting,
|
|
58 |
'boolean': cone.confml.model.ConfmlBooleanSetting}
|
3
|
59 |
# Create temp variables always name being also the ref
|
|
60 |
feature = mapping[self.type](ref, name=ref)
|
0
|
61 |
setattr(feature, TEMP_FEATURE_MARKER_VARNAME, True)
|
|
62 |
config.add_feature(feature, namespace)
|
|
63 |
|
|
64 |
value = utils.expand_refs_by_default_view(self.value, config.get_default_view())
|
|
65 |
config.add_data(api.Data(fqr=self.ref, value=value))
|
|
66 |
|
|
67 |
def __eq__(self, other):
|
|
68 |
if type(self) is type(other):
|
|
69 |
for varname in ('ref', 'type', 'value'):
|
|
70 |
if getattr(self, varname) != getattr(other, varname):
|
|
71 |
return False
|
|
72 |
return True
|
|
73 |
else:
|
|
74 |
return False
|
|
75 |
|
|
76 |
def __ne__(self, other):
|
|
77 |
return not (self == other)
|
|
78 |
|
|
79 |
def __repr__(self):
|
|
80 |
return "TempFeatureDefinition(ref=%r, type=%r, value=%r)" % (self.ref, self.type, self.value)
|
|
81 |
|
|
82 |
class TempVariableSequenceDefinition(object):
|
|
83 |
"""
|
|
84 |
Class representing a temporary variable sequence definition in an implementation file.
|
|
85 |
"""
|
|
86 |
|
3
|
87 |
def __init__(self, ref, sub_items, lineno=None):
|
0
|
88 |
self.ref = ref
|
|
89 |
self.sub_items = sub_items
|
3
|
90 |
self.lineno = lineno
|
0
|
91 |
|
|
92 |
def create_feature(self, config):
|
|
93 |
if '.' in self.ref:
|
|
94 |
pos = self.ref.rfind('.')
|
|
95 |
ref = self.ref[pos + 1:]
|
|
96 |
namespace = self.ref[:pos]
|
|
97 |
else:
|
|
98 |
ref = self.ref
|
|
99 |
namespace = ''
|
|
100 |
|
|
101 |
# Creature the sequence feature
|
3
|
102 |
# Create temp variables always name being also the ref
|
|
103 |
seq_fea = api.FeatureSequence(ref, name=ref)
|
0
|
104 |
setattr(seq_fea, TEMP_FEATURE_MARKER_VARNAME, True)
|
|
105 |
config.add_feature(seq_fea, namespace)
|
|
106 |
|
|
107 |
# Create the sub-features
|
|
108 |
mapping = {'string' : cone.confml.model.ConfmlStringSetting,
|
|
109 |
'int' : cone.confml.model.ConfmlIntSetting,
|
|
110 |
'real' : cone.confml.model.ConfmlRealSetting,
|
|
111 |
'boolean': cone.confml.model.ConfmlBooleanSetting}
|
|
112 |
sub_features = []
|
|
113 |
for sub_item in self.sub_items:
|
3
|
114 |
sub_feature = mapping[sub_item[1]](sub_item[0], name=sub_item[0])
|
0
|
115 |
seq_fea.add_feature(sub_feature)
|
|
116 |
|
|
117 |
def __eq__(self, other):
|
|
118 |
if type(self) is type(other):
|
|
119 |
return self.ref == other.ref and self.sub_items == other.sub_items
|
|
120 |
else:
|
|
121 |
return False
|
|
122 |
|
|
123 |
def __ne__(self, other):
|
|
124 |
return not (self == other)
|
|
125 |
|
|
126 |
def __repr__(self):
|
|
127 |
return "TempSeqFeatureDefinition(ref=%r, sub_items=%r)" % (self.ref, self.sub_items)
|
|
128 |
|
|
129 |
class SettingRefsOverride(object):
|
|
130 |
"""
|
|
131 |
Class representing a setting reference override for an implementation.
|
|
132 |
"""
|
|
133 |
def __init__(self, refs=None):
|
|
134 |
"""
|
|
135 |
@param refs: The reference overrides, can be a list of references or None.
|
|
136 |
"""
|
|
137 |
self.refs = refs
|
|
138 |
|
|
139 |
def get_refs(self):
|
|
140 |
return self.refs
|
|
141 |
|
|
142 |
def __eq__(self, other):
|
|
143 |
if type(self) is type(other):
|
|
144 |
return self.refs == other.refs
|
|
145 |
else:
|
|
146 |
return False
|
|
147 |
|
|
148 |
def __ne__(self, other):
|
|
149 |
return not (self == other)
|
|
150 |
|
|
151 |
def __repr__(self):
|
|
152 |
return "SettingRefsOverride(refs=%r)" % self.refs
|
|
153 |
|
|
154 |
class CommonImplmlData(object):
|
|
155 |
"""
|
|
156 |
Class representing the common ImplML namespace data read from
|
|
157 |
an XML element.
|
|
158 |
"""
|
|
159 |
|
|
160 |
def __init__(self):
|
|
161 |
self.phase = None
|
|
162 |
self.tags = None
|
|
163 |
self.tempvar_defs = []
|
|
164 |
self.setting_refs_override = None
|
|
165 |
self.output_root_dir = None
|
|
166 |
self.output_sub_dir = None
|
|
167 |
|
|
168 |
def apply(self, impl):
|
|
169 |
"""
|
|
170 |
Apply the data on the given implementation instance.
|
|
171 |
"""
|
|
172 |
if self.phase:
|
|
173 |
impl.set_invocation_phase(self.phase)
|
|
174 |
if self.tags:
|
|
175 |
impl.set_tags(self.tags)
|
|
176 |
if self.setting_refs_override:
|
|
177 |
# Override the get_refs() method of the implementation
|
|
178 |
impl.get_refs = self.setting_refs_override.get_refs
|
|
179 |
# Override also the has_ref() method in case it is overridden
|
|
180 |
# in the implementation sub-class
|
|
181 |
impl.has_ref = lambda refs: plugin.ImplBase.has_ref(impl, refs)
|
|
182 |
if self.output_root_dir:
|
|
183 |
impl.set_output_root_override(self.output_root_dir)
|
|
184 |
if self.output_sub_dir:
|
|
185 |
impl.output_subdir = self.output_sub_dir
|
|
186 |
|
|
187 |
def extend(self, other):
|
|
188 |
"""
|
|
189 |
Extend this object with the contents of another CommonImplmlData object.
|
|
190 |
"""
|
3
|
191 |
if other is None:
|
|
192 |
return
|
|
193 |
|
0
|
194 |
if other.phase:
|
|
195 |
self.phase = other.phase
|
|
196 |
if other.tags:
|
|
197 |
self.tags = other.tags
|
|
198 |
if other.setting_refs_override:
|
|
199 |
self.setting_refs_override = other.setting_refs_override
|
|
200 |
if other.output_root_dir:
|
|
201 |
self.output_root_dir = other.output_root_dir
|
|
202 |
if other.output_sub_dir:
|
|
203 |
self.output_sub_dir = other.output_sub_dir
|
|
204 |
|
|
205 |
def copy(self):
|
|
206 |
result = CommonImplmlData()
|
|
207 |
result.phase = self.phase
|
3
|
208 |
if self.tags is not None:
|
0
|
209 |
result.tags = self.tags.copy()
|
|
210 |
result.tempvar_defs = list(self.tempvar_defs)
|
|
211 |
result.setting_refs_override = copy.deepcopy(self.setting_refs_override)
|
|
212 |
result.output_root_dir = self.output_root_dir
|
|
213 |
result.output_sub_dir = self.output_sub_dir
|
|
214 |
return result
|
|
215 |
|
|
216 |
def __eq__(self, other):
|
|
217 |
if type(self) is type(other):
|
|
218 |
for varname in ('phase', 'tags', 'tempvar_defs', 'setting_refs_override', 'output_root_dir', 'output_sub_dir'):
|
|
219 |
if getattr(self, varname) != getattr(other, varname):
|
|
220 |
return False
|
|
221 |
return True
|
|
222 |
else:
|
|
223 |
return False
|
|
224 |
|
|
225 |
def __ne__(self, other):
|
|
226 |
return not (self == other)
|
|
227 |
|
|
228 |
def __repr__(self):
|
|
229 |
return "CommonImplmlData(phase=%r, tags=%r, tempvar_defs=%r, setting_refs_override=%r, output_root_dir=%r, output_sub_dir=%r)" \
|
|
230 |
% (self.phase,
|
|
231 |
self.tags,
|
|
232 |
self.tempvar_defs,
|
|
233 |
self.setting_refs_override,
|
|
234 |
self.output_root_dir,
|
|
235 |
self.output_sub_dir)
|
|
236 |
|
|
237 |
class ImplReader(object):
|
|
238 |
"""
|
|
239 |
Internal reader class for reading implementations from a file in a configuration.
|
|
240 |
"""
|
|
241 |
|
|
242 |
# The reader class list loaded using ImplFactory
|
|
243 |
__loaded_reader_classes = None
|
|
244 |
__reader_classes = None
|
|
245 |
__supported_file_extensions = None
|
|
246 |
__ignored_namespaces = None
|
|
247 |
|
|
248 |
def __init__(self, resource_ref, configuration):
|
|
249 |
self.resource_ref = resource_ref
|
|
250 |
self.configuration = configuration
|
|
251 |
|
|
252 |
@classmethod
|
|
253 |
def _load_data_from_plugins(cls):
|
|
254 |
"""
|
|
255 |
Load all data needed for implementation parsing from the plug-ins.
|
|
256 |
|
|
257 |
The actual loading is only done the first time this method is called.
|
|
258 |
"""
|
|
259 |
# Load the data only if the reader class list has not been loaded
|
|
260 |
# yet or it has changed
|
|
261 |
loaded_reader_classes = plugin.ImplFactory.get_reader_classes()
|
|
262 |
if cls.__loaded_reader_classes is loaded_reader_classes:
|
|
263 |
return
|
|
264 |
|
|
265 |
reader_classes = [plugin.ReaderBase]
|
|
266 |
reader_classes.extend(loaded_reader_classes)
|
|
267 |
|
|
268 |
cls.__reader_classes = {}
|
|
269 |
cls.__ignored_namespaces = []
|
|
270 |
cls.__supported_file_extensions = []
|
|
271 |
|
|
272 |
for rc in reader_classes:
|
|
273 |
# Reader class
|
|
274 |
ns = rc.NAMESPACE
|
|
275 |
if ns is not None:
|
|
276 |
if ns in cls.__reader_classes:
|
|
277 |
raise RuntimeError("Multiple reader classes registered for ImplML namespace '%s': at least %s and %s"\
|
|
278 |
% (ns, rc, cls.__reader_classes[ns]))
|
|
279 |
cls.__reader_classes[ns] = rc
|
|
280 |
|
|
281 |
# Ignored namespaces
|
|
282 |
for ns in rc.IGNORED_NAMESPACES:
|
|
283 |
if ns not in cls.__ignored_namespaces:
|
|
284 |
cls.__ignored_namespaces.append(ns)
|
|
285 |
|
|
286 |
# Supported file extensions
|
|
287 |
for fe in rc.FILE_EXTENSIONS:
|
|
288 |
fe = fe.lower()
|
|
289 |
if fe not in cls.__supported_file_extensions:
|
|
290 |
cls.__supported_file_extensions.append(fe)
|
|
291 |
|
|
292 |
cls.__loaded_reader_classes = loaded_reader_classes
|
|
293 |
|
|
294 |
@classmethod
|
|
295 |
def _get_namespaces(cls, etree):
|
|
296 |
"""
|
|
297 |
Return a list of XML namespaces in the given element tree.
|
|
298 |
"""
|
|
299 |
namespaces = []
|
|
300 |
namespaces.append(utils.xml.split_tag_namespace(etree.tag)[0])
|
|
301 |
for elem in etree:
|
|
302 |
ns = utils.xml.split_tag_namespace(elem.tag)[0]
|
|
303 |
if ns not in namespaces:
|
|
304 |
namespaces.append(ns)
|
|
305 |
return filter(lambda ns: ns is not None, namespaces)
|
|
306 |
|
|
307 |
def _read_impls_from_file_root_element(self, root, namespaces):
|
|
308 |
impls = []
|
|
309 |
reader_classes = self.get_reader_classes()
|
|
310 |
|
|
311 |
# Go through the list of XML namespaces encountered in the
|
|
312 |
# file and read an implementation using the corresponding
|
|
313 |
# reader for each namespace
|
|
314 |
impl_count = 0
|
|
315 |
common_data = CommonImplmlDataReader.read_data(root)
|
|
316 |
for ns in namespaces:
|
|
317 |
if ns not in reader_classes: continue
|
|
318 |
|
|
319 |
rc = reader_classes[ns]
|
|
320 |
impl = self._read_impl(rc, root)
|
|
321 |
if impl:
|
|
322 |
impl.index = impl_count
|
|
323 |
impl_count += 1
|
|
324 |
if common_data: common_data.apply(impl)
|
|
325 |
impls.append(impl)
|
|
326 |
|
|
327 |
# Add temp feature definitions to the first implementation
|
|
328 |
if common_data and impls:
|
|
329 |
impls[0]._tempvar_defs.extend(common_data.tempvar_defs)
|
|
330 |
return impls
|
|
331 |
|
|
332 |
def _read_impls_from_file_sub_elements(self, root):
|
|
333 |
impls = []
|
|
334 |
|
|
335 |
# Collect common ImplML namespace data
|
|
336 |
common_data = CommonImplmlData()
|
|
337 |
for elem in root:
|
|
338 |
ns = utils.xml.split_tag_namespace(elem.tag)[0]
|
|
339 |
if ns == COMMON_IMPLML_NAMESPACE:
|
|
340 |
cd = CommonImplmlDataReader.read_data(elem)
|
|
341 |
if cd: common_data.extend(cd)
|
|
342 |
|
|
343 |
# Go through all sub-elements and read an implementation instance
|
|
344 |
# from each if possible
|
|
345 |
impl_count = 0
|
|
346 |
reader_classes = self.get_reader_classes()
|
|
347 |
for elem in root:
|
|
348 |
ns = utils.xml.split_tag_namespace(elem.tag)[0]
|
|
349 |
if ns != COMMON_IMPLML_NAMESPACE and ns in reader_classes:
|
|
350 |
reader_class = reader_classes[ns]
|
|
351 |
impl = self._read_impl(reader_class, elem)
|
|
352 |
if impl:
|
|
353 |
cd = CommonImplmlDataReader.read_data(elem)
|
|
354 |
if cd is not None:
|
|
355 |
impl._tempvar_defs.extend(cd.tempvar_defs)
|
|
356 |
data = common_data.copy()
|
|
357 |
data.extend(cd)
|
|
358 |
data.apply(impl)
|
|
359 |
else:
|
|
360 |
common_data.apply(impl)
|
|
361 |
|
|
362 |
impl.index = impl_count
|
|
363 |
impl_count += 1
|
|
364 |
impls.append(impl)
|
|
365 |
|
|
366 |
# Add temporary feature definitions to the first implementation instance
|
|
367 |
if impls:
|
|
368 |
impls[0]._tempvar_defs = common_data.tempvar_defs + impls[0]._tempvar_defs
|
|
369 |
|
|
370 |
return impls
|
|
371 |
|
|
372 |
def _read_impl(self, reader_class, elem):
|
|
373 |
"""
|
|
374 |
Read an implementation with the given reader class from the given element.
|
|
375 |
|
|
376 |
If an exception is raised during reading, the exception is logged
|
|
377 |
and None returned.
|
|
378 |
|
|
379 |
@return: The read implementation or None.
|
|
380 |
"""
|
|
381 |
try:
|
|
382 |
return reader_class.read_impl(self.resource_ref, self.configuration, elem)
|
|
383 |
except exceptions.ParseError, e:
|
|
384 |
log.error("Error reading implementation '%s': %s", (self.resource_ref, e))
|
|
385 |
except Exception, e:
|
|
386 |
utils.log_exception(log, e)
|
|
387 |
|
|
388 |
return None
|
|
389 |
|
|
390 |
@classmethod
|
|
391 |
def get_reader_classes(cls):
|
|
392 |
"""
|
|
393 |
Return a dictionary of all possible implementation reader classes.
|
|
394 |
|
|
395 |
Dictionary key is the XML namespace and the value is the corresponding
|
|
396 |
reader class.
|
|
397 |
"""
|
|
398 |
cls._load_data_from_plugins()
|
|
399 |
return cls.__reader_classes
|
|
400 |
|
|
401 |
@classmethod
|
|
402 |
def get_supported_file_extensions(cls):
|
|
403 |
"""
|
|
404 |
Return a list of all supported implementation file extensions.
|
|
405 |
"""
|
|
406 |
cls._load_data_from_plugins()
|
|
407 |
return cls.__supported_file_extensions
|
|
408 |
|
|
409 |
@classmethod
|
|
410 |
def get_ignored_namespaces(cls):
|
|
411 |
"""
|
|
412 |
Return a list of all ignored XML namespaces.
|
|
413 |
"""
|
|
414 |
cls._load_data_from_plugins()
|
|
415 |
return cls.__ignored_namespaces
|
|
416 |
|
|
417 |
def read_implementations(self):
|
|
418 |
try:
|
|
419 |
root = plugin.ReaderBase._read_xml_doc_from_resource(self.resource_ref, self.configuration)
|
|
420 |
return self.read_implementation(root)
|
|
421 |
except exceptions.ParseError, e:
|
|
422 |
# Invalid XML data in the file
|
|
423 |
log.error(e)
|
|
424 |
return []
|
|
425 |
|
|
426 |
def read_implementation(self, xmlroot):
|
|
427 |
root = xmlroot
|
|
428 |
|
|
429 |
# Check if the implementations should all be read from the
|
|
430 |
# document root, or each from its own sub-element under the root
|
|
431 |
read_from_root = False
|
|
432 |
ns = utils.xml.split_tag_namespace(root.tag)[0]
|
|
433 |
if ns: read_from_root = True
|
|
434 |
|
|
435 |
# Collect namespaces from the file and check that all are supported or ignored
|
|
436 |
namespaces = self._get_namespaces(root)
|
|
437 |
for ns in namespaces:
|
|
438 |
if ns != COMMON_IMPLML_NAMESPACE \
|
|
439 |
and ns not in self.get_reader_classes() \
|
|
440 |
and ns not in self.get_ignored_namespaces():
|
|
441 |
log.error("Unsupported XML namespace '%s' in file '%s'" % (ns, self.resource_ref))
|
|
442 |
return []
|
|
443 |
|
|
444 |
if read_from_root:
|
|
445 |
impls = self._read_impls_from_file_root_element(root, namespaces)
|
|
446 |
else:
|
|
447 |
impls = self._read_impls_from_file_sub_elements(root)
|
|
448 |
return impls
|
|
449 |
|
|
450 |
|
|
451 |
class CommonImplmlDataReader(object):
|
|
452 |
"""
|
|
453 |
Internal reader class for reading common ImplML namespace data from and element.
|
|
454 |
"""
|
|
455 |
|
|
456 |
VALID_PHASES = ('pre', 'normal', 'post')
|
|
457 |
VALID_TYPES = ('string', 'int', 'real', 'boolean')
|
|
458 |
|
|
459 |
@classmethod
|
|
460 |
def read_data(cls, etree):
|
|
461 |
"""
|
|
462 |
Read common ImplML data from the given XML element.
|
3
|
463 |
@return: A CommonImplmlData instance.
|
0
|
464 |
"""
|
|
465 |
result = CommonImplmlData()
|
|
466 |
|
|
467 |
reader_methods = {'phase' : cls._read_phase,
|
|
468 |
'tag' : cls._read_tag,
|
|
469 |
'tempVariable' : cls._read_tempvar,
|
|
470 |
'tempVariableSequence' : cls._read_tempvarseq,
|
|
471 |
'settingRefsOverride' : cls._read_setting_refs_override,
|
|
472 |
'outputRootDir' : cls._read_output_root_dir,
|
|
473 |
'outputSubDir' : cls._read_output_sub_dir}
|
|
474 |
|
|
475 |
for elem in etree:
|
|
476 |
ns, tag = utils.xml.split_tag_namespace(elem.tag)
|
|
477 |
if ns != COMMON_IMPLML_NAMESPACE: continue
|
|
478 |
if tag not in reader_methods: continue
|
|
479 |
|
|
480 |
reader_methods[tag](elem, result)
|
|
481 |
|
3
|
482 |
return result
|
0
|
483 |
|
|
484 |
@classmethod
|
|
485 |
def _read_phase(cls, elem, result):
|
|
486 |
phase = elem.get('name')
|
|
487 |
if phase is None:
|
|
488 |
cls._raise_missing_attr(elem, 'name')
|
|
489 |
if phase not in cls.VALID_PHASES:
|
|
490 |
raise exceptions.ParseError("Invalid invocation phase '%s' defined." % phase)
|
|
491 |
|
|
492 |
result.phase = phase
|
|
493 |
|
|
494 |
@classmethod
|
|
495 |
def _read_tag(cls, elem, result):
|
|
496 |
name = elem.get('name')
|
|
497 |
value = elem.get('value')
|
|
498 |
if name is not None:
|
|
499 |
if result.tags is None: result.tags = {}
|
|
500 |
if name not in result.tags: result.tags[name] = []
|
|
501 |
result.tags[name].append(value)
|
|
502 |
|
|
503 |
@classmethod
|
|
504 |
def _read_tempvar(cls, elem, result):
|
|
505 |
ref = elem.get('ref')
|
|
506 |
type = elem.get('type', 'string')
|
|
507 |
value = elem.get('value', '')
|
3
|
508 |
lineno = utils.etree.get_lineno(elem)
|
0
|
509 |
|
|
510 |
if ref is None:
|
|
511 |
cls._raise_missing_attr(elem, 'ref')
|
|
512 |
if type not in cls.VALID_TYPES:
|
|
513 |
cls._raise_invalid_type(ref, type)
|
|
514 |
|
3
|
515 |
result.tempvar_defs.append(TempVariableDefinition(ref, type, value, lineno))
|
0
|
516 |
|
|
517 |
@classmethod
|
|
518 |
def _read_tempvarseq(cls, elem, result):
|
|
519 |
ref = elem.get('ref')
|
|
520 |
if ref is None:
|
|
521 |
cls._raise_missing_attr(elem, 'ref')
|
|
522 |
|
|
523 |
sub_items = []
|
|
524 |
for sub_elem in elem.findall('{%s}tempVariable' % COMMON_IMPLML_NAMESPACE):
|
|
525 |
sub_ref = sub_elem.get('ref')
|
|
526 |
sub_type = sub_elem.get('type', 'string')
|
|
527 |
|
|
528 |
if sub_ref is None:
|
|
529 |
cls._raise_missing_attr(sub_elem, 'ref')
|
|
530 |
if sub_type not in cls.VALID_TYPES:
|
|
531 |
cls._raise_invalid_type(sub_ref, sub_type)
|
|
532 |
|
|
533 |
sub_items.append((sub_ref, sub_type))
|
|
534 |
|
|
535 |
if not sub_items:
|
|
536 |
raise exceptions.ParseError("Temporary variable sequence '%s' does not have any sub-items" % ref)
|
|
537 |
|
3
|
538 |
lineno = utils.etree.get_lineno(elem)
|
|
539 |
|
|
540 |
result.tempvar_defs.append(TempVariableSequenceDefinition(ref, sub_items, lineno))
|
0
|
541 |
|
|
542 |
@classmethod
|
|
543 |
def _read_setting_refs_override(cls, elem, result):
|
|
544 |
if elem.get('refsIrrelevant', 'false').lower() in ('1', 'true'):
|
|
545 |
refs = None
|
|
546 |
else:
|
|
547 |
refs = []
|
|
548 |
for sub_elem in elem.findall('{%s}settingRef' % COMMON_IMPLML_NAMESPACE):
|
|
549 |
ref = sub_elem.get('value')
|
|
550 |
|
|
551 |
if ref is None:
|
|
552 |
cls._raise_missing_attr(sub_elem, 'value')
|
|
553 |
|
|
554 |
refs.append(ref)
|
|
555 |
|
|
556 |
result.setting_refs_override = SettingRefsOverride(refs)
|
|
557 |
|
|
558 |
@classmethod
|
|
559 |
def _read_output_root_dir(cls, elem, result):
|
|
560 |
value = elem.get('value')
|
|
561 |
if value: result.output_root_dir = value
|
|
562 |
|
|
563 |
@classmethod
|
|
564 |
def _read_output_sub_dir(cls, elem, result):
|
|
565 |
value = elem.get('value')
|
|
566 |
if value: result.output_sub_dir = value
|
|
567 |
|
|
568 |
@classmethod
|
|
569 |
def _raise_missing_attr(cls, elem, attrname):
|
|
570 |
raise exceptions.ParseError("XML element %s does not contain the mandatory '%s' attribute." % (elem.tag, attrname))
|
|
571 |
|
|
572 |
@classmethod
|
|
573 |
def _raise_invalid_type(cls, ref, type):
|
|
574 |
raise exceptions.ParseError("Invalid feature type '%s' specified for temporary ConfML feature '%s'." % (type, ref)) |