Use barectf.cli._run() as the CLI's starting function
[deliverable/barectf.git] / barectf / config_parse_v3.py
1 # The MIT License (MIT)
2 #
3 # Copyright (c) 2015-2020 Philippe Proulx <pproulx@efficios.com>
4 #
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
12 #
13 # The above copyright notice and this permission notice shall be
14 # included in all copies or substantial portions of the Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 import barectf.config_parse_common as barectf_config_parse_common
25 from barectf.config_parse_common import _ConfigurationParseError
26 from barectf.config_parse_common import _append_error_ctx
27 import barectf.config as barectf_config
28 import collections
29 import uuid
30
31
32 # A barectf 3 YAML configuration parser.
33 #
34 # When you build such a parser, it parses the configuration node `node`
35 # (already loaded from the file having the path `path`) and creates a
36 # corresponding `barectf.Configuration` object which you can get with
37 # the `config` property.
38 #
39 # See the comments of _parse() for more implementation details about the
40 # parsing stages and general strategy.
41 class _Parser(barectf_config_parse_common._Parser):
42 # Builds a barectf 3 YAML configuration parser and parses the root
43 # configuration node `node` (already loaded from `path`).
44 def __init__(self, path, node, with_pkg_include_dir, inclusion_dirs, ignore_include_not_found):
45 super().__init__(path, node, with_pkg_include_dir, inclusion_dirs,
46 ignore_include_not_found, 3)
47 self._ft_cls_name_to_create_method = {
48 'unsigned-integer': self._create_int_ft,
49 'signed-integer': self._create_int_ft,
50 'unsigned-enumeration': self._create_enum_ft,
51 'signed-enumeration': self._create_enum_ft,
52 'real': self._create_real_ft,
53 'string': self._create_string_ft,
54 'static-array': self._create_static_array_ft,
55 'structure': self._create_struct_ft,
56 }
57 self._parse()
58
59 # Validates the alignment `alignment`, raising a
60 # `_ConfigurationParseError` exception using `ctx_obj_name` if it's
61 # invalid.
62 @staticmethod
63 def _validate_alignment(alignment, ctx_obj_name):
64 assert alignment >= 1
65
66 # check for power of two
67 if (alignment & (alignment - 1)) != 0:
68 raise _ConfigurationParseError(ctx_obj_name,
69 f'Invalid alignment (not a power of two): {alignment}')
70
71 # Validates the TSDL identifier `iden`, raising a
72 # `_ConfigurationParseError` exception using `ctx_obj_name` and
73 # `prop` to format the message if it's invalid.
74 @staticmethod
75 def _validate_iden(iden, ctx_obj_name, prop):
76 assert type(iden) is str
77 ctf_keywords = {
78 'align',
79 'callsite',
80 'clock',
81 'enum',
82 'env',
83 'event',
84 'floating_point',
85 'integer',
86 'stream',
87 'string',
88 'struct',
89 'trace',
90 'typealias',
91 'typedef',
92 'variant',
93 }
94
95 if iden in ctf_keywords:
96 msg = f'Invalid {prop} (not a valid identifier): `{iden}`'
97 raise _ConfigurationParseError(ctx_obj_name, msg)
98
99 @staticmethod
100 def _alignment_prop(ft_node, prop_name):
101 alignment = ft_node.get(prop_name)
102
103 if alignment is not None:
104 _Parser._validate_alignment(alignment, '`prop_name` property')
105
106 return alignment
107
108 @property
109 def _trace_type_node(self):
110 return self._root_node.config_node['trace']['type']
111
112 @staticmethod
113 def _byte_order_from_node(node):
114 return {
115 'big-endian': barectf_config.ByteOrder.BIG_ENDIAN,
116 'little-endian': barectf_config.ByteOrder.LITTLE_ENDIAN,
117 }[node]
118
119 # Creates a bit array field type having the type `ft_type` from the
120 # bit array field type node `ft_node`, passing the additional
121 # `*args` to ft_type.__init__().
122 def _create_common_bit_array_ft(self, ft_node, ft_type, default_alignment, *args):
123 byte_order = self._byte_order_from_node(ft_node['byte-order'])
124 alignment = self._alignment_prop(ft_node, 'alignment')
125
126 if alignment is None:
127 alignment = default_alignment
128
129 return ft_type(ft_node['size'], byte_order, alignment, *args)
130
131 # Creates an integer field type having the type `ft_type` from the
132 # integer field type node `ft_node`, passing the additional `*args`
133 # to ft_type.__init__().
134 def _create_common_int_ft(self, ft_node, ft_type, *args):
135 preferred_display_base = {
136 'binary': barectf_config.DisplayBase.BINARY,
137 'octal': barectf_config.DisplayBase.OCTAL,
138 'decimal': barectf_config.DisplayBase.DECIMAL,
139 'hexadecimal': barectf_config.DisplayBase.HEXADECIMAL,
140 }[ft_node.get('preferred-display-base', 'decimal')]
141 return self._create_common_bit_array_ft(ft_node, ft_type, None, preferred_display_base, *args)
142
143 # Creates an integer field type from the unsigned/signed integer
144 # field type node `ft_node`.
145 def _create_int_ft(self, ft_node):
146 ft_type = {
147 'unsigned-integer': barectf_config.UnsignedIntegerFieldType,
148 'signed-integer': barectf_config.SignedIntegerFieldType,
149 }[ft_node['class']]
150 return self._create_common_int_ft(ft_node, ft_type)
151
152 # Creates an enumeration field type from the unsigned/signed
153 # enumeration field type node `ft_node`.
154 def _create_enum_ft(self, ft_node):
155 ft_type = {
156 'unsigned-enumeration': barectf_config.UnsignedEnumerationFieldType,
157 'signed-enumeration': barectf_config.SignedEnumerationFieldType,
158 }[ft_node['class']]
159 mappings = collections.OrderedDict()
160
161 for label, mapping_node in ft_node.get('mappings', {}).items():
162 ranges = set()
163
164 for range_node in mapping_node:
165 if type(range_node) is list:
166 ranges.add(barectf_config.EnumerationFieldTypeMappingRange(range_node[0],
167 range_node[1]))
168 else:
169 assert type(range_node) is int
170 ranges.add(barectf_config.EnumerationFieldTypeMappingRange(range_node,
171 range_node))
172
173 mappings[label] = barectf_config.EnumerationFieldTypeMapping(ranges)
174
175 return self._create_common_int_ft(ft_node, ft_type,
176 barectf_config.EnumerationFieldTypeMappings(mappings))
177
178 # Creates a real field type from the real field type node `ft_node`.
179 def _create_real_ft(self, ft_node):
180 return self._create_common_bit_array_ft(ft_node, barectf_config.RealFieldType, 8)
181
182 # Creates a string field type from the string field type node
183 # `ft_node`.
184 def _create_string_ft(self, ft_node):
185 return barectf_config.StringFieldType()
186
187 # Creates a static array field type from the static array field type
188 # node `ft_node`.
189 def _create_static_array_ft(self, ft_node):
190 prop_name = 'element-field-type'
191
192 try:
193 element_ft = self._create_ft(ft_node[prop_name])
194 except _ConfigurationParseError as exc:
195 _append_error_ctx(exc, f'`{prop_name}` property')
196
197 return barectf_config.StaticArrayFieldType(ft_node['length'], element_ft)
198
199 # Creates structure field type members from the structure field type
200 # members node `members_node`.
201 #
202 # `prop_name` is the name of the property of which `members_node` is
203 # the value.
204 def _create_struct_ft_members(self, members_node, prop_name):
205 members = collections.OrderedDict()
206 member_names = set()
207
208 for member_node in members_node:
209 member_name, member_node = list(member_node.items())[0]
210
211 if member_name in member_names:
212 raise _ConfigurationParseError(f'`{prop_name}` property',
213 f'Duplicate member `{member_name}`')
214
215 self._validate_iden(member_name, f'`{prop_name}` property',
216 'structure field type member name')
217 member_names.add(member_name)
218 ft_prop_name = 'field-type'
219 ft_node = member_node[ft_prop_name]
220
221 try:
222 if ft_node['class'] in ['structure', 'static-array']:
223 raise _ConfigurationParseError(f'`{ft_prop_name}` property',
224 'Nested structure and static array field types are not supported')
225
226 try:
227 member_ft = self._create_ft(ft_node)
228 except _ConfigurationParseError as exc:
229 exc._append_ctx(f'`{ft_prop_name}` property')
230 except _ConfigurationParseError as exc:
231 _append_error_ctx(exc, f'Structure field type member `{member_name}`')
232
233 members[member_name] = barectf_config.StructureFieldTypeMember(member_ft)
234
235 return barectf_config.StructureFieldTypeMembers(members)
236
237 # Creates a structure field type from the structure field type node
238 # `ft_node`.
239 def _create_struct_ft(self, ft_node):
240 minimum_alignment = self._alignment_prop(ft_node, 'minimum-alignment')
241
242 if minimum_alignment is None:
243 minimum_alignment = 1
244
245 members = None
246 prop_name = 'members'
247 members_node = ft_node.get(prop_name)
248
249 if members_node is not None:
250 members = self._create_struct_ft_members(members_node, prop_name)
251
252 return barectf_config.StructureFieldType(minimum_alignment, members)
253
254 # Creates a field type from the field type node `ft_node`.
255 def _create_ft(self, ft_node):
256 return self._ft_cls_name_to_create_method[ft_node['class']](ft_node)
257
258 # Creates a field type from the field type node `parent_node[key]`
259 # if it exists.
260 def _try_create_ft(self, parent_node, key):
261 if key not in parent_node:
262 return
263
264 try:
265 return self._create_ft(parent_node[key])
266 except _ConfigurationParseError as exc:
267 _append_error_ctx(exc, f'`{key}` property')
268
269 # Returns the total number of members in the structure field type
270 # node `ft_node` if it exists, otherwise 0.
271 @staticmethod
272 def _total_struct_ft_node_members(ft_node):
273 if ft_node is None:
274 return 0
275
276 members_node = ft_node.get('members')
277
278 if members_node is None:
279 return 0
280
281 return len(members_node)
282
283 # Creates an event type from the event type node `ev_type_node`
284 # named `name`.
285 #
286 # `ev_member_count` is the total number of structure field type
287 # members within the event type so far (from the common part in its
288 # stream type). For example, if the stream type has a event header
289 # field type with `id` and `timestamp` members, then
290 # `ev_member_count` is 2.
291 def _create_ev_type(self, name, ev_type_node, ev_member_count):
292 try:
293 self._validate_iden(name, '`name` property', 'event type name')
294
295 # make sure the event type is not empty
296 spec_ctx_ft_prop_name = 'specific-context-field-type'
297 payload_ft_prop_name = 'payload-field-type'
298 ev_member_count += self._total_struct_ft_node_members(ev_type_node.get(spec_ctx_ft_prop_name))
299 ev_member_count += self._total_struct_ft_node_members(ev_type_node.get(payload_ft_prop_name))
300
301 if ev_member_count == 0:
302 raise _ConfigurationParseError('Event type', 'Event type is empty (no members).')
303
304 # create event type
305 return barectf_config.EventType(name, ev_type_node.get('log-level'),
306 self._try_create_ft(ev_type_node, spec_ctx_ft_prop_name),
307 self._try_create_ft(ev_type_node, payload_ft_prop_name))
308 except _ConfigurationParseError as exc:
309 _append_error_ctx(exc, f'Event type `{name}`')
310
311 # Returns the effective feature field type for the field type
312 # node `parent_node[key]`, if any.
313 #
314 # Returns:
315 #
316 # If `parent_node[key]` is `False`:
317 # `None`.
318 #
319 # If `parent_node[key]` is `True`:
320 # `barectf_config.DEFAULT_FIELD_TYPE`.
321 #
322 # If `parent_node[key]` doesn't exist:
323 # `none` (parameter).
324 #
325 # Otherwise:
326 # A created field type.
327 def _feature_ft(self, parent_node, key, none=None):
328 if key not in parent_node:
329 # missing: default feature field type
330 return none
331
332 ft_node = parent_node[key]
333 assert ft_node is not None
334
335 if ft_node is True:
336 # default feature field type
337 return barectf_config.DEFAULT_FIELD_TYPE
338
339 if ft_node is False:
340 # disabled feature
341 return None
342
343 assert type(ft_node) is collections.OrderedDict
344 return self._create_ft(ft_node)
345
346 def _create_stream_type(self, name, stream_type_node):
347 try:
348 # validate stream type's name
349 self._validate_iden(name, '`name` property', 'stream type name')
350
351 # get default clock type, if any
352 def_clk_type = None
353 prop_name = '$default-clock-type-name'
354 def_clk_type_name = stream_type_node.get(prop_name)
355
356 if def_clk_type_name is not None:
357 try:
358 def_clk_type = self._clk_type(def_clk_type_name, prop_name)
359 except _ConfigurationParseError as exc:
360 _append_error_ctx(exc, f'`{prop_name}` property')
361
362 # create feature field types
363 pkt_total_size_ft = barectf_config.DEFAULT_FIELD_TYPE
364 pkt_content_size_ft = barectf_config.DEFAULT_FIELD_TYPE
365 pkt_beginning_time_ft = None
366 pkt_end_time_ft = None
367 pkt_discarded_events_counter_ft = None
368 ev_type_id_ft = barectf_config.DEFAULT_FIELD_TYPE
369 ev_time_ft = None
370
371 if def_clk_type is not None:
372 # The stream type has a default clock type. Initialize
373 # the packet beginning time, packet end time, and event
374 # time field types to default field types.
375 #
376 # This means your stream type node only needs a default
377 # clock type name to enable those features
378 # automatically. Those features do not add any parameter
379 # to the tracing event functions.
380 pkt_beginning_time_ft = barectf_config.DEFAULT_FIELD_TYPE
381 pkt_end_time_ft = barectf_config.DEFAULT_FIELD_TYPE
382 ev_time_ft = barectf_config.DEFAULT_FIELD_TYPE
383
384 features_node = stream_type_node.get('$features')
385
386 if features_node is not None:
387 # create packet feature field types
388 pkt_node = features_node.get('packet')
389
390 if pkt_node is not None:
391 pkt_total_size_ft = self._feature_ft(pkt_node, 'total-size-field-type',
392 pkt_total_size_ft)
393 pkt_content_size_ft = self._feature_ft(pkt_node, 'content-size-field-type',
394 pkt_content_size_ft)
395 pkt_beginning_time_ft = self._feature_ft(pkt_node, 'beginning-time-field-type',
396 pkt_beginning_time_ft)
397 pkt_end_time_ft = self._feature_ft(pkt_node, 'end-time-field-type',
398 pkt_end_time_ft)
399 pkt_discarded_events_counter_ft = self._feature_ft(pkt_node,
400 'discarded-events-counter-field-type',
401 pkt_discarded_events_counter_ft)
402
403 # create event feature field types
404 ev_node = features_node.get('event')
405 type_id_ft_prop_name = 'type-id-field-type'
406
407 if ev_node is not None:
408 ev_type_id_ft = self._feature_ft(ev_node, type_id_ft_prop_name, ev_type_id_ft)
409 ev_time_ft = self._feature_ft(ev_node, 'time-field-type', ev_time_ft)
410
411 ev_types_prop_name = 'event-types'
412 ev_type_count = len(stream_type_node[ev_types_prop_name])
413
414 try:
415 if ev_type_id_ft is None and ev_type_count > 1:
416 raise _ConfigurationParseError(f'`{type_id_ft_prop_name}` property',
417 'Event type ID field type feature is required because stream type has more than one event type')
418
419 if isinstance(ev_type_id_ft, barectf_config._FieldType) and ev_type_count > (1 << ev_type_id_ft.size):
420 raise _ConfigurationParseError(f'`{type_id_ft_prop_name}` property',
421 f'Field type\'s size ({ev_type_id_ft.size} bits) is too small to accomodate {ev_type_count} event types')
422 except _ConfigurationParseError as exc:
423 exc._append_ctx('`event` property')
424 _append_error_ctx(exc, '`$features` property')
425
426 pkt_features = barectf_config.StreamTypePacketFeatures(pkt_total_size_ft,
427 pkt_content_size_ft,
428 pkt_beginning_time_ft,
429 pkt_end_time_ft,
430 pkt_discarded_events_counter_ft)
431 ev_features = barectf_config.StreamTypeEventFeatures(ev_type_id_ft, ev_time_ft)
432 features = barectf_config.StreamTypeFeatures(pkt_features, ev_features)
433
434 # create packet context (structure) field type extra members
435 pkt_ctx_ft_extra_members = None
436 prop_name = 'packet-context-field-type-extra-members'
437 pkt_ctx_ft_extra_members_node = stream_type_node.get(prop_name)
438
439 if pkt_ctx_ft_extra_members_node is not None:
440 pkt_ctx_ft_extra_members = self._create_struct_ft_members(pkt_ctx_ft_extra_members_node,
441 prop_name)
442
443 # check for illegal packet context field type member names
444 reserved_member_names = {
445 'packet_size',
446 'content_size',
447 'timestamp_begin',
448 'timestamp_end',
449 'events_discarded',
450 'packet_seq_num',
451 }
452
453 for member_name in pkt_ctx_ft_extra_members:
454 if member_name in reserved_member_names:
455 raise _ConfigurationParseError(f'`{prop_name}` property',
456 f'Packet context field type member name `{member_name}` is reserved.')
457
458 # create event types
459 ev_header_common_ctx_member_count = 0
460
461 if ev_features.type_id_field_type is not None:
462 ev_header_common_ctx_member_count += 1
463
464 if ev_features.time_field_type is not None:
465 ev_header_common_ctx_member_count += 1
466
467 ev_common_ctx_ft_prop_name = 'event-common-context-field-type'
468 ev_common_ctx_ft_node = stream_type_node.get(ev_common_ctx_ft_prop_name)
469 ev_header_common_ctx_member_count += self._total_struct_ft_node_members(ev_common_ctx_ft_node)
470 ev_types = set()
471
472 for ev_name, ev_type_node in stream_type_node[ev_types_prop_name].items():
473 ev_types.add(self._create_ev_type(ev_name, ev_type_node, ev_header_common_ctx_member_count))
474
475 # create stream type
476 return barectf_config.StreamType(name, ev_types, def_clk_type, features,
477 pkt_ctx_ft_extra_members,
478 self._try_create_ft(stream_type_node,
479 ev_common_ctx_ft_prop_name))
480 except _ConfigurationParseError as exc:
481 _append_error_ctx(exc, f'Stream type `{name}`')
482
483 def _clk_type(self, name, prop_name):
484 clk_type = self._clk_types.get(name)
485
486 if clk_type is None:
487 raise _ConfigurationParseError(f'`{prop_name}` property',
488 f'Clock type `{name}` does not exist')
489
490 return clk_type
491
492 def _create_clk_type(self, name, clk_type_node):
493 self._validate_iden(name, '`name` property', 'clock type name')
494 clk_type_uuid = None
495 uuid_node = clk_type_node.get('uuid')
496
497 if uuid_node is not None:
498 clk_type_uuid = uuid.UUID(uuid_node)
499
500 offset_seconds = 0
501 offset_cycles = 0
502 offset_node = clk_type_node.get('offset')
503
504 if offset_node is not None:
505 offset_seconds = offset_node.get('seconds', 0)
506 offset_cycles = offset_node.get('cycles', 0)
507
508 return barectf_config.ClockType(name, clk_type_node.get('frequency', int(1e9)),
509 clk_type_uuid, clk_type_node.get('description'),
510 clk_type_node.get('precision', 0),
511 barectf_config.ClockTypeOffset(offset_seconds, offset_cycles),
512 clk_type_node.get('origin-is-unix-epoch', False))
513
514 def _create_clk_types(self):
515 self._clk_types = {}
516
517 for clk_type_name, clk_type_node in self._trace_type_node.get('clock-types', {}).items():
518 self._clk_types[clk_type_name] = self._create_clk_type(clk_type_name, clk_type_node)
519
520 def _create_trace_type(self):
521 try:
522 # create clock types (_create_stream_type() needs them)
523 self._create_clk_types()
524
525 # get UUID
526 trace_type_uuid = None
527 uuid_node = self._trace_type_node.get('uuid')
528
529 if uuid_node is not None:
530 if uuid_node == 'auto':
531 trace_type_uuid = uuid.uuid1()
532 else:
533 trace_type_uuid = uuid.UUID(uuid_node)
534
535 # create feature field types
536 magic_ft = barectf_config.DEFAULT_FIELD_TYPE
537 uuid_ft = None
538 stream_type_id_ft = barectf_config.DEFAULT_FIELD_TYPE
539
540 if trace_type_uuid is not None:
541 # Trace type has a UUID: initialize UUID field type to
542 # a default field type.
543 uuid_ft = barectf_config.DEFAULT_FIELD_TYPE
544
545 features_node = self._trace_type_node.get('$features')
546 stream_type_id_ft_prop_name = 'stream-type-id-field-type'
547
548 if features_node is not None:
549 magic_ft = self._feature_ft(features_node, 'magic-field-type',
550 magic_ft)
551 uuid_ft = self._feature_ft(features_node, 'uuid-field-type', uuid_ft)
552 stream_type_id_ft = self._feature_ft(features_node, stream_type_id_ft_prop_name,
553 stream_type_id_ft)
554
555 stream_types_prop_name = 'stream-types'
556 stream_type_count = len(self._trace_type_node[stream_types_prop_name])
557
558 try:
559 if stream_type_id_ft is None and stream_type_count > 1:
560 raise _ConfigurationParseError(f'`{stream_type_id_ft_prop_name}` property',
561 'Stream type ID field type feature is required because trace type has more than one stream type')
562
563 if isinstance(stream_type_id_ft, barectf_config._FieldType) and stream_type_count > (1 << stream_type_id_ft.size):
564 raise _ConfigurationParseError(f'`{stream_type_id_ft_prop_name}` property',
565 f'Field type\'s size ({stream_type_id_ft.size} bits) is too small to accomodate {stream_type_count} stream types')
566 except _ConfigurationParseError as exc:
567 _append_error_ctx(exc, '`$features` property')
568
569 features = barectf_config.TraceTypeFeatures(magic_ft, uuid_ft, stream_type_id_ft)
570
571 # create stream types
572 stream_types = set()
573
574 for stream_name, stream_type_node in self._trace_type_node[stream_types_prop_name].items():
575 stream_types.add(self._create_stream_type(stream_name, stream_type_node))
576
577 # create trace type
578 return barectf_config.TraceType(stream_types, self._default_byte_order,
579 trace_type_uuid, features)
580 except _ConfigurationParseError as exc:
581 _append_error_ctx(exc, 'Trace type')
582
583 def _create_trace(self):
584 try:
585 trace_type = self._create_trace_type()
586 trace_node = self._root_node.config_node['trace']
587 env = None
588 env_node = trace_node.get('environment')
589
590 if env_node is not None:
591 # validate each environment variable name
592 for name in env_node:
593 self._validate_iden(name, '`environment` property',
594 'environment variable name')
595
596 # the node already has the expected structure
597 env = barectf_config.TraceEnvironment(env_node)
598
599 return barectf_config.Trace(trace_type, env)
600
601 except _ConfigurationParseError as exc:
602 _append_error_ctx(exc, 'Trace')
603
604 def _create_config(self):
605 # create trace first
606 trace = self._create_trace()
607
608 # find default stream type, if any
609 def_stream_type = None
610
611 for stream_type_name, stream_type_node in self._trace_type_node['stream-types'].items():
612 prop_name = '$is-default'
613 is_default = stream_type_node.get(prop_name)
614
615 if is_default is True:
616 if def_stream_type is not None:
617 exc = _ConfigurationParseError(f'`{prop_name}` property',
618 f'Duplicate default stream type (`{def_stream_type.name}`)')
619 exc._append_ctx(f'Stream type `{stream_type_name}`')
620 _append_error_ctx(exc, 'Trace type')
621
622 def_stream_type = trace.type.stream_type(stream_type_name)
623
624 # create clock type C type mapping
625 clk_types_node = self._trace_type_node.get('clock-types')
626 clk_type_c_types = None
627
628 if clk_types_node is not None:
629 clk_type_c_types = collections.OrderedDict()
630
631 for stream_type in trace.type.stream_types:
632 if stream_type.default_clock_type is None:
633 continue
634
635 clk_type_node = clk_types_node[stream_type.default_clock_type.name]
636 c_type = clk_type_node.get('$c-type')
637
638 if c_type is not None:
639 clk_type_c_types[stream_type.default_clock_type] = c_type
640
641 # create options
642 iden_prefix_def = False
643 def_stream_type_name_def = False
644 opts_node = self._root_node.config_node.get('options')
645
646 if opts_node is not None:
647 code_gen_opts_node = opts_node.get('code-generation')
648
649 if code_gen_opts_node is not None:
650 prefix_node = code_gen_opts_node.get('prefix', 'barectf')
651
652 if type(prefix_node) is str:
653 # automatic prefixes
654 iden_prefix = f'{prefix_node}_'
655 file_name_prefix = prefix_node
656 else:
657 iden_prefix = prefix_node['identifier']
658 file_name_prefix = prefix_node['file-name']
659
660 header_opts = code_gen_opts_node.get('header')
661
662 if header_opts is not None:
663 iden_prefix_def = header_opts.get('identifier-prefix-definition', False)
664 def_stream_type_name_def = header_opts.get('default-stream-type-name-definition',
665 False)
666
667 header_opts = barectf_config.ConfigurationCodeGenerationHeaderOptions(iden_prefix_def,
668 def_stream_type_name_def)
669 cg_opts = barectf_config.ConfigurationCodeGenerationOptions(iden_prefix, file_name_prefix,
670 def_stream_type, header_opts,
671 clk_type_c_types)
672 opts = barectf_config.ConfigurationOptions(cg_opts)
673
674 # create configuration
675 self._config = barectf_config.Configuration(trace, opts)
676
677 # Expands the field type aliases found in the trace type node.
678 #
679 # This method modifies the trace type node.
680 #
681 # When this method returns:
682 #
683 # * Any field type alias is replaced with its full field type
684 # node equivalent.
685 #
686 # * The `$field-type-aliases` property of the trace type node is
687 # removed.
688 def _expand_ft_aliases(self):
689 def resolve_ft_alias_from(parent_node, key):
690 if key not in parent_node:
691 return
692
693 if type(parent_node[key]) not in [collections.OrderedDict, str]:
694 return
695
696 return self._resolve_ft_alias_from(ft_aliases_node, parent_node, key)
697
698 ft_aliases_node = self._trace_type_node['$field-type-aliases']
699
700 # Expand field type aliases within trace, stream, and event type
701 # nodes.
702 features_prop_name = '$features'
703
704 try:
705 features_node = self._trace_type_node.get(features_prop_name)
706
707 if features_node is not None:
708 try:
709 resolve_ft_alias_from(features_node, 'magic-field-type')
710 resolve_ft_alias_from(features_node, 'uuid-field-type')
711 resolve_ft_alias_from(features_node, 'stream-type-id-field-type')
712 except _ConfigurationParseError as exc:
713 _append_error_ctx(exc, f'`{features_prop_name}` property')
714 except _ConfigurationParseError as exc:
715 _append_error_ctx(exc, 'Trace type')
716
717 for stream_type_name, stream_type_node in self._trace_type_node['stream-types'].items():
718 try:
719 features_node = stream_type_node.get(features_prop_name)
720
721 if features_node is not None:
722 try:
723 pkt_prop_name = 'packet'
724 pkt_node = features_node.get(pkt_prop_name)
725
726 if pkt_node is not None:
727 try:
728 resolve_ft_alias_from(pkt_node, 'total-size-field-type')
729 resolve_ft_alias_from(pkt_node, 'content-size-field-type')
730 resolve_ft_alias_from(pkt_node, 'beginning-time-field-type')
731 resolve_ft_alias_from(pkt_node, 'end-time-field-type')
732 resolve_ft_alias_from(pkt_node,
733 'discarded-events-counter-field-type')
734 except _ConfigurationParseError as exc:
735 _append_error_ctx(exc, f'`{pkt_prop_name}` property')
736
737 ev_prop_name = 'event'
738 ev_node = features_node.get(ev_prop_name)
739
740 if ev_node is not None:
741 try:
742 resolve_ft_alias_from(ev_node, 'type-id-field-type')
743 resolve_ft_alias_from(ev_node, 'time-field-type')
744 except _ConfigurationParseError as exc:
745 _append_error_ctx(exc, f'`{ev_prop_name}` property')
746 except _ConfigurationParseError as exc:
747 _append_error_ctx(exc, f'`{features_prop_name}` property')
748
749 pkt_ctx_ft_extra_members_prop_name = 'packet-context-field-type-extra-members'
750 pkt_ctx_ft_extra_members_node = stream_type_node.get(pkt_ctx_ft_extra_members_prop_name)
751
752 if pkt_ctx_ft_extra_members_node is not None:
753 try:
754 for member_node in pkt_ctx_ft_extra_members_node:
755 member_node = list(member_node.values())[0]
756 resolve_ft_alias_from(member_node, 'field-type')
757 except _ConfigurationParseError as exc:
758 _append_error_ctx(exc, f'`{pkt_ctx_ft_extra_members_prop_name}` property')
759
760 resolve_ft_alias_from(stream_type_node, 'event-common-context-field-type')
761
762 for ev_type_name, ev_type_node in stream_type_node['event-types'].items():
763 try:
764 resolve_ft_alias_from(ev_type_node, 'specific-context-field-type')
765 resolve_ft_alias_from(ev_type_node, 'payload-field-type')
766 except _ConfigurationParseError as exc:
767 _append_error_ctx(exc, f'Event type `{ev_type_name}`')
768 except _ConfigurationParseError as exc:
769 _append_error_ctx(exc, f'Stream type `{stream_type_name}`')
770
771 # remove the (now unneeded) `$field-type-aliases` property
772 del self._trace_type_node['$field-type-aliases']
773
774 # Applies field type inheritance to all field type nodes found in
775 # the trace type node.
776 #
777 # This method modifies the trace type node.
778 #
779 # When this method returns, no field type node has an `$inherit`
780 # property.
781 def _apply_fts_inheritance(self):
782 def apply_ft_inheritance(parent_node, key):
783 if key not in parent_node:
784 return
785
786 if type(parent_node[key]) is not collections.OrderedDict:
787 return
788
789 return self._apply_ft_inheritance(parent_node, key)
790
791 features_prop_name = '$features'
792 features_node = self._trace_type_node.get(features_prop_name)
793
794 if features_node is not None:
795 apply_ft_inheritance(features_node, 'magic-field-type')
796 apply_ft_inheritance(features_node, 'uuid-field-type')
797 apply_ft_inheritance(features_node, 'stream-type-id-field-type')
798
799 for stream_type_node in self._trace_type_node['stream-types'].values():
800 features_node = stream_type_node.get(features_prop_name)
801
802 if features_node is not None:
803 pkt_node = features_node.get('packet')
804
805 if pkt_node is not None:
806 apply_ft_inheritance(pkt_node, 'total-size-field-type')
807 apply_ft_inheritance(pkt_node, 'content-size-field-type')
808 apply_ft_inheritance(pkt_node, 'beginning-time-field-type')
809 apply_ft_inheritance(pkt_node, 'end-time-field-type')
810 apply_ft_inheritance(pkt_node, 'discarded-events-counter-field-type')
811
812 ev_node = features_node.get('event')
813
814 if ev_node is not None:
815 apply_ft_inheritance(ev_node, 'type-id-field-type')
816 apply_ft_inheritance(ev_node, 'time-field-type')
817
818 pkt_ctx_ft_extra_members_node = stream_type_node.get('packet-context-field-type-extra-members')
819
820 if pkt_ctx_ft_extra_members_node is not None:
821 for member_node in pkt_ctx_ft_extra_members_node:
822 member_node = list(member_node.values())[0]
823 apply_ft_inheritance(member_node, 'field-type')
824
825 apply_ft_inheritance(stream_type_node, 'event-common-context-field-type')
826
827 for ev_type_node in stream_type_node['event-types'].values():
828 apply_ft_inheritance(ev_type_node, 'specific-context-field-type')
829 apply_ft_inheritance(ev_type_node, 'payload-field-type')
830
831 # Normalizes structure field type member nodes.
832 #
833 # A structure field type member node can look like this:
834 #
835 # - msg: custom-string
836 #
837 # which is the equivalent of this:
838 #
839 # - msg:
840 # field-type: custom-string
841 #
842 # This method normalizes form 1 to use form 2.
843 def _normalize_struct_ft_member_nodes(self):
844 def normalize_members_node(members_node):
845 ft_prop_name = 'field-type'
846
847 for member_node in members_node:
848 member_name, val_node = list(member_node.items())[0]
849
850 if type(val_node) is str:
851 member_node[member_name] = collections.OrderedDict({
852 ft_prop_name: val_node
853 })
854
855 normalize_struct_ft_member_nodes(member_node[member_name], ft_prop_name)
856
857 def normalize_struct_ft_member_nodes(parent_node, key):
858 if type(parent_node) is not collections.OrderedDict:
859 return
860
861 ft_node = parent_node.get(key)
862
863 if type(ft_node) is not collections.OrderedDict:
864 return
865
866 members_nodes = ft_node.get('members')
867
868 if members_nodes is not None:
869 normalize_members_node(members_nodes)
870
871 prop_name = '$field-type-aliases'
872 ft_aliases_node = self._trace_type_node.get(prop_name)
873
874 if ft_aliases_node is not None:
875 for alias in ft_aliases_node:
876 normalize_struct_ft_member_nodes(ft_aliases_node, alias)
877
878 features_prop_name = '$features'
879 features_node = self._trace_type_node.get(features_prop_name)
880
881 if features_node is not None:
882 normalize_struct_ft_member_nodes(features_node, 'magic-field-type')
883 normalize_struct_ft_member_nodes(features_node, 'uuid-field-type')
884 normalize_struct_ft_member_nodes(features_node, 'stream-type-id-field-type')
885
886 for stream_type_node in self._trace_type_node['stream-types'].values():
887 features_node = stream_type_node.get(features_prop_name)
888
889 if features_node is not None:
890 pkt_node = features_node.get('packet')
891
892 if pkt_node is not None:
893 normalize_struct_ft_member_nodes(pkt_node, 'total-size-field-type')
894 normalize_struct_ft_member_nodes(pkt_node, 'content-size-field-type')
895 normalize_struct_ft_member_nodes(pkt_node, 'beginning-time-field-type')
896 normalize_struct_ft_member_nodes(pkt_node, 'end-time-field-type')
897 normalize_struct_ft_member_nodes(pkt_node,
898 'discarded-events-counter-field-type')
899
900 ev_node = features_node.get('event')
901
902 if ev_node is not None:
903 normalize_struct_ft_member_nodes(ev_node, 'type-id-field-type')
904 normalize_struct_ft_member_nodes(ev_node, 'time-field-type')
905
906 pkt_ctx_ft_extra_members_node = stream_type_node.get('packet-context-field-type-extra-members')
907
908 if pkt_ctx_ft_extra_members_node is not None:
909 normalize_members_node(pkt_ctx_ft_extra_members_node)
910
911 normalize_struct_ft_member_nodes(stream_type_node, 'event-common-context-field-type')
912
913 for ev_type_node in stream_type_node['event-types'].values():
914 normalize_struct_ft_member_nodes(ev_type_node, 'specific-context-field-type')
915 normalize_struct_ft_member_nodes(ev_type_node, 'payload-field-type')
916
917 # Calls _expand_ft_aliases() and _apply_fts_inheritance() if the
918 # trace type node has a `$field-type-aliases` property.
919 def _expand_fts(self):
920 # Make sure that the current configuration node is valid
921 # considering field types are not expanded yet.
922 self._schema_validator.validate(self._root_node.config_node,
923 '3/config/config-pre-field-type-expansion')
924
925 prop_name = '$field-type-aliases'
926 ft_aliases_node = self._trace_type_node.get(prop_name)
927
928 if ft_aliases_node is None:
929 # If there's no `'$field-type-aliases'` node, then there's
930 # no field type aliases and therefore no possible
931 # inheritance.
932 if prop_name in self._trace_type_node:
933 del self._trace_type_node[prop_name]
934
935 return
936
937 # normalize structure field type member nodes
938 self._normalize_struct_ft_member_nodes()
939
940 # first, expand field type aliases
941 self._expand_ft_aliases()
942
943 # next, apply inheritance to create effective field type nodes
944 self._apply_fts_inheritance()
945
946 # Substitute the event type node log level aliases with their
947 # numeric equivalents.
948 #
949 # Removes the `$log-level-aliases` property of the trace type node.
950 def _sub_log_level_aliases(self):
951 # Make sure that the current configuration node is valid
952 # considering log level aliases are not substituted yet.
953 self._schema_validator.validate(self._root_node.config_node,
954 '3/config/config-pre-log-level-alias-sub')
955
956 log_level_aliases_prop_name = '$log-level-aliases'
957 log_level_aliases_node = self._trace_type_node.get(log_level_aliases_prop_name)
958
959 if log_level_aliases_prop_name in self._trace_type_node:
960 del self._trace_type_node[log_level_aliases_prop_name]
961
962 if log_level_aliases_node is None:
963 # no log level aliases
964 return
965
966 # substitute log level aliases
967 for stream_type_name, stream_type_node in self._trace_type_node['stream-types'].items():
968 try:
969 for ev_type_name, ev_type_node in stream_type_node['event-types'].items():
970 try:
971 prop_name = 'log-level'
972 ll_node = ev_type_node.get(prop_name)
973
974 if ll_node is None:
975 continue
976
977 if type(ll_node) is str:
978 if ll_node not in log_level_aliases_node:
979 raise _ConfigurationParseError(f'`{prop_name}` property',
980 f'Log level alias `{ll_node}` does not exist')
981
982 ev_type_node[prop_name] = log_level_aliases_node[ll_node]
983 except _ConfigurationParseError as exc:
984 _append_error_ctx(exc, f'Event type `{ev_type_name}`')
985 except _ConfigurationParseError as exc:
986 _append_error_ctx(exc, f'Stream type `{stream_type_name}`')
987
988 # Generator of parent node and key pairs for all the nodes,
989 # recursively, of `node`.
990 #
991 # It is safe to delete a yielded node during the iteration.
992 @staticmethod
993 def _props(node):
994 if type(node) is collections.OrderedDict:
995 for key in list(node):
996 yield from _Parser._props(node[key])
997 yield node, key
998 elif type(node) is list:
999 for item_node in node:
1000 yield from _Parser._props(item_node)
1001
1002 def _trace_type_props(self):
1003 yield from _Parser._props(self._root_node.config_node['trace']['type'])
1004
1005 # Normalize the properties of the configuration node.
1006 #
1007 # This method, for each property of the trace type node:
1008 #
1009 # 1. Removes it if it's `None` (means default).
1010 #
1011 # 2. Chooses a specific `class` property value.
1012 #
1013 # 3. Chooses a specific `byte-order`/`$default-byte-order` property
1014 # value.
1015 #
1016 # 4. Chooses a specific `preferred-display-base` property value.
1017 #
1018 # This method also applies 1. to the trace node's `environment`
1019 # property.
1020 def _normalize_props(self):
1021 def normalize_byte_order_prop(parent_node, key):
1022 node = parent_node[key]
1023
1024 if node in ['be', 'big']:
1025 parent_node[key] = 'big-endian'
1026 elif node in ['le', 'little']:
1027 parent_node[key] = 'little-endian'
1028
1029 trace_node = self._root_node.config_node['trace']
1030 trace_type_node = trace_node['type']
1031 prop_name = '$default-byte-order'
1032
1033 if prop_name in trace_type_node and type(trace_type_node[prop_name]) is str:
1034 normalize_byte_order_prop(trace_type_node, prop_name)
1035
1036 for parent_node, key in self._trace_type_props():
1037 node = parent_node[key]
1038
1039 if node is None:
1040 # a `None` property is equivalent to not having it
1041 del parent_node[key]
1042 continue
1043
1044 if key == 'class' and type(node) is str:
1045 # field type class aliases
1046 if node in ['uint', 'unsigned-int']:
1047 parent_node[key] = 'unsigned-integer'
1048 elif node in ['sint', 'signed-int']:
1049 parent_node[key] = 'signed-integer'
1050 elif node in ['uenum', 'unsigned-enum']:
1051 parent_node[key] = 'unsigned-enumeration'
1052 elif node in ['senum', 'signed-enum']:
1053 parent_node[key] = 'signed-enumeration'
1054 elif node == 'str':
1055 parent_node[key] = 'string'
1056 elif node == 'struct':
1057 parent_node[key] = 'structure'
1058 elif key == 'byte-order' and type(node) is str:
1059 # byte order aliases
1060 normalize_byte_order_prop(parent_node, key)
1061 elif key == 'preferred-display-base' and type(node) is str:
1062 # display base aliases
1063 if node == 'bin':
1064 parent_node[key] = 'binary'
1065 elif node == 'oct':
1066 parent_node[key] = 'octal'
1067 elif node == 'dec':
1068 parent_node[key] = 'decimal'
1069 elif node == 'hex':
1070 parent_node[key] = 'hexadecimal'
1071
1072 prop_name = 'environment'
1073
1074 if prop_name in trace_node:
1075 node = trace_node[prop_name]
1076
1077 if node is None:
1078 del trace_node[prop_name]
1079
1080 # Substitutes missing/`None` `byte-order` properties with the trace
1081 # type node's default byte order (`$default-byte-order` property),
1082 # if any.
1083 def _sub_ft_nodes_byte_order(self):
1084 ba_ft_class_names = {
1085 'unsigned-integer',
1086 'signed-integer',
1087 'unsigned-enumeration',
1088 'signed-enumeration',
1089 'real',
1090 }
1091
1092 def set_ft_node_byte_order_prop(parent_node, key):
1093 if key not in parent_node:
1094 return
1095
1096 ft_node = parent_node[key]
1097
1098 if type(ft_node) is not collections.OrderedDict:
1099 return
1100
1101 if ft_node['class'] in ba_ft_class_names:
1102 prop_name = 'byte-order'
1103 byte_order_node = ft_node.get(prop_name)
1104
1105 if byte_order_node is None:
1106 if default_byte_order_node is None:
1107 raise _ConfigurationParseError(f'`{key}` property`',
1108 '`byte-order` property is not set or null, but trace type has no `$default-byte-order` property')
1109
1110 ft_node[prop_name] = default_byte_order_node
1111
1112 members_node = ft_node.get('members')
1113
1114 if members_node is not None:
1115 set_struct_ft_node_members_byte_order_prop(members_node)
1116
1117 set_ft_node_byte_order_prop(ft_node, 'element-field-type')
1118
1119 def set_struct_ft_node_members_byte_order_prop(members_node):
1120 for member_node in members_node:
1121 member_name, member_node = list(member_node.items())[0]
1122
1123 try:
1124 set_ft_node_byte_order_prop(member_node, 'field-type')
1125 except _ConfigurationParseError as exc:
1126 _append_error_ctx(exc, f'Structure field type member `{member_name}`')
1127
1128 default_byte_order_node = self._trace_type_node.get('$default-byte-order')
1129
1130 self._default_byte_order = None
1131
1132 if default_byte_order_node is not None:
1133 self._default_byte_order = self._byte_order_from_node(default_byte_order_node)
1134
1135 features_prop_name = '$features'
1136 features_node = self._trace_type_node.get(features_prop_name)
1137
1138 if features_node is not None:
1139 try:
1140 set_ft_node_byte_order_prop(features_node, 'magic-field-type')
1141 set_ft_node_byte_order_prop(features_node, 'uuid-field-type')
1142 set_ft_node_byte_order_prop(features_node, 'stream-type-id-field-type')
1143 except _ConfigurationParseError as exc:
1144 exc._append_ctx(exc, f'`{features_prop_name}` property')
1145 _append_error_ctx(exc, 'Trace type')
1146
1147 for stream_type_name, stream_type_node in self._trace_type_node['stream-types'].items():
1148 try:
1149 features_node = stream_type_node.get(features_prop_name)
1150
1151 if features_node is not None:
1152 pkt_node = features_node.get('packet')
1153
1154 if pkt_node is not None:
1155 set_ft_node_byte_order_prop(pkt_node, 'total-size-field-type')
1156 set_ft_node_byte_order_prop(pkt_node, 'content-size-field-type')
1157 set_ft_node_byte_order_prop(pkt_node, 'beginning-time-field-type')
1158 set_ft_node_byte_order_prop(pkt_node, 'end-time-field-type')
1159 set_ft_node_byte_order_prop(pkt_node,
1160 'discarded-events-counter-field-type')
1161
1162 ev_node = features_node.get('event')
1163
1164 if ev_node is not None:
1165 set_ft_node_byte_order_prop(ev_node, 'type-id-field-type')
1166 set_ft_node_byte_order_prop(ev_node, 'time-field-type')
1167
1168 prop_name = 'packet-context-field-type-extra-members'
1169 pkt_ctx_ft_extra_members_node = stream_type_node.get(prop_name)
1170
1171 if pkt_ctx_ft_extra_members_node is not None:
1172 try:
1173 set_struct_ft_node_members_byte_order_prop(pkt_ctx_ft_extra_members_node)
1174 except _ConfigurationParseError as exc:
1175 _append_error_ctx(exc, f'`{pkt_ctx_ft_extra_members_node}` property')
1176
1177 set_ft_node_byte_order_prop(stream_type_node, 'event-common-context-field-type')
1178
1179 for ev_type_name, ev_type_node in stream_type_node['event-types'].items():
1180 try:
1181 set_ft_node_byte_order_prop(ev_type_node, 'specific-context-field-type')
1182 set_ft_node_byte_order_prop(ev_type_node, 'payload-field-type')
1183 except _ConfigurationParseError as exc:
1184 _append_error_ctx(exc, f'Event type `{ev_type_name}`')
1185 except _ConfigurationParseError as exc:
1186 _append_error_ctx(exc, f'Stream type `{stream_type_name}`')
1187
1188 # Processes the inclusions of the event type node `ev_type_node`,
1189 # returning the effective node.
1190 def _process_ev_type_node_include(self, ev_type_node):
1191 # Make sure the event type node is valid for the inclusion
1192 # processing stage.
1193 self._schema_validator.validate(ev_type_node, '3/config/event-type-pre-include')
1194
1195 # process inclusions
1196 return self._process_node_include(ev_type_node, self._process_ev_type_node_include)
1197
1198 # Processes the inclusions of the stream type node
1199 # `stream_type_node`, returning the effective node.
1200 def _process_stream_type_node_include(self, stream_type_node):
1201 def process_children_include(stream_type_node):
1202 prop_name = 'event-types'
1203
1204 if prop_name in stream_type_node:
1205 ev_types_node = stream_type_node[prop_name]
1206
1207 for key in list(ev_types_node):
1208 ev_types_node[key] = self._process_ev_type_node_include(ev_types_node[key])
1209
1210 # Make sure the stream type node is valid for the inclusion
1211 # processing stage.
1212 self._schema_validator.validate(stream_type_node, '3/config/stream-type-pre-include')
1213
1214 # process inclusions
1215 return self._process_node_include(stream_type_node, self._process_stream_type_node_include,
1216 process_children_include)
1217
1218 # Processes the inclusions of the clock type node `clk_type_node`,
1219 # returning the effective node.
1220 def _process_clk_type_node_include(self, clk_type_node):
1221 # Make sure the clock type node is valid for the inclusion
1222 # processing stage.
1223 self._schema_validator.validate(clk_type_node, '3/config/clock-type-pre-include')
1224
1225 # process inclusions
1226 return self._process_node_include(clk_type_node, self._process_clk_type_node_include)
1227
1228 # Processes the inclusions of the trace type node `trace_type_node`,
1229 # returning the effective node.
1230 def _process_trace_type_node_include(self, trace_type_node):
1231 def process_children_include(trace_type_node):
1232 prop_name = 'clock-types'
1233
1234 if prop_name in trace_type_node:
1235 clk_types_node = trace_type_node[prop_name]
1236
1237 for key in list(clk_types_node):
1238 clk_types_node[key] = self._process_clk_type_node_include(clk_types_node[key])
1239
1240 prop_name = 'stream-types'
1241
1242 if prop_name in trace_type_node:
1243 stream_types_node = trace_type_node[prop_name]
1244
1245 for key in list(stream_types_node):
1246 stream_types_node[key] = self._process_stream_type_node_include(stream_types_node[key])
1247
1248 # Make sure the trace type node is valid for the inclusion
1249 # processing stage.
1250 self._schema_validator.validate(trace_type_node, '3/config/trace-type-pre-include')
1251
1252 # process inclusions
1253 return self._process_node_include(trace_type_node, self._process_trace_type_node_include,
1254 process_children_include)
1255
1256 # Processes the inclusions of the trace node `trace_node`, returning
1257 # the effective node.
1258 def _process_trace_node_include(self, trace_node):
1259 def process_children_include(trace_node):
1260 prop_name = 'type'
1261 trace_node[prop_name] = self._process_trace_type_node_include(trace_node[prop_name])
1262
1263 # Make sure the trace node is valid for the inclusion processing
1264 # stage.
1265 self._schema_validator.validate(trace_node, '3/config/trace-pre-include')
1266
1267 # process inclusions
1268 return self._process_node_include(trace_node, self._process_trace_node_include,
1269 process_children_include)
1270
1271 # Processes the inclusions of the configuration node, modifying it
1272 # during the process.
1273 def _process_config_includes(self):
1274 # Process inclusions in this order:
1275 #
1276 # 1. Clock type node and event type nodes (the order between
1277 # those is not important).
1278 #
1279 # 2. Stream type nodes.
1280 #
1281 # 3. Trace type node.
1282 #
1283 # 4. Trace node.
1284 #
1285 # This is because:
1286 #
1287 # * A trace node can include a trace type node, clock type
1288 # nodes, stream type nodes, and event type nodes.
1289 #
1290 # * A trace type node can include clock type nodes, stream type
1291 # nodes, and event type nodes.
1292 #
1293 # * A stream type node can include event type nodes.
1294 #
1295 # First, make sure the configuration node itself is valid for
1296 # the inclusion processing stage.
1297 self._schema_validator.validate(self._root_node.config_node, '3/config/config-pre-include')
1298
1299 # Process trace node inclusions.
1300 #
1301 # self._process_trace_node_include() returns a new (or the same)
1302 # trace node without any `$include` property in it, recursively.
1303 self._root_node.config_node['trace'] = self._process_trace_node_include(self._root_node.config_node['trace'])
1304
1305 def _parse(self):
1306 # process configuration node inclusions
1307 self._process_config_includes()
1308
1309 # Expand field type nodes.
1310 #
1311 # This process:
1312 #
1313 # 1. Replaces field type aliases with "effective" field type
1314 # nodes, recursively.
1315 #
1316 # After this step, the `$field-type-aliases` property of the
1317 # trace type node is gone.
1318 #
1319 # 2. Applies inheritance, following the `$inherit` properties.
1320 #
1321 # After this step, field type nodes do not contain `$inherit`
1322 # properties.
1323 #
1324 # This is done blindly, in that the process _doesn't_ validate
1325 # field type nodes at this point.
1326 self._expand_fts()
1327
1328 # Substitute log level aliases.
1329 #
1330 # This process:
1331 #
1332 # 1. Replaces log level aliases in event type nodes with their
1333 # numeric equivalents as found in the `$log-level-aliases`
1334 # property of the trace type node.
1335 #
1336 # 2. Removes the `$log-level-aliases` property from the trace
1337 # type node.
1338 self._sub_log_level_aliases()
1339
1340 # At this point, the configuration node must be valid as an
1341 # effective configuration node.
1342 self._schema_validator.validate(self._root_node.config_node, '3/config/config')
1343
1344 # Normalize properties.
1345 #
1346 # This process removes `None` properties and chooses specific
1347 # enumerators when aliases exist (for example, `big-endian`
1348 # instead of `be`).
1349 #
1350 # The goal of this is that, if the user then gets this parser's
1351 # `config_node` property, it has a normal and very readable
1352 # form.
1353 #
1354 # It also makes _create_config() easier to implement because it
1355 # doesn't need to check for `None` nodes or enumerator aliases.
1356 self._normalize_props()
1357
1358 # Set `byte-order` properties of bit array field type nodes
1359 # missing one.
1360 #
1361 # This process also removes the `$default-byte-order` property
1362 # from the trace type node.
1363 self._sub_ft_nodes_byte_order()
1364
1365 # Create a barectf configuration object from the configuration
1366 # node.
1367 self._create_config()
1368
1369 @property
1370 def config(self):
1371 return self._config
1372
1373 @property
1374 def config_node(self):
1375 return self._root_node
This page took 0.05936 seconds and 4 git commands to generate.