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