From de49021eecdfe156dc8b575447bc512982d8bbc7 Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Thu, 20 Aug 2020 15:52:48 -0400 Subject: [PATCH] Use Jinja 2 templates to generate the `metadata` file The goal of this patch is to, as much as possible, and as long as everything remains as readable as possible, move any `metadata` file templating outside of pure Python code to improve template readability, maintenability, and reuse. This patch does the following: 1. Adds a Jinja 2 dependency to `pyproject.toml`. 2. Adds the `template` module which contains helpers to create and render a Jinja 2 template. The _create_template() function uses a `jinja2.PackageLoader` object to load a named package from the `barectf` packet's `templates` directory. It creates an environment with common parameters and common filters: `indent_tab`: Like Jinja 2's built-in `indent`, but uses tabs instead of spaces. `escape_sq`: Escapes a double-quoted string (backslashes and double quotes). Jinja 2 templates can expect to have access to the `barectf_config` and `barectf_version` modules, as well as, possibly, the current barectf configuration as the `cfg` variable. The _render_template() function renders a given template with a given context, keeping a single newline at the end if `is_file_template` is `True`. 3. Adds Jinja 2 templates to generate the `metadata` file: `metadata.j2`: Top-level template for the whole file. `metadata-enum-ft.j2`: Enumeration field type block template. `metadata-int-ft.j2`: Integer field type block template. `metadata-real-ft.j2`: Real field type block template. `metadata-str-ft.j2`: String field type block template. `metadata-struct-ft.j2`: Structure field type block template. 4. Changes `barectf/tsdl182gen.py` so as to use 2. with 3. `barectf/tsdl182gen.py` defines custom Jinja 2 filters to help the templates of 3.: `bo_str`: Converts a `barectf.ByteOrder` value to the `le` or `be` string. `disp_base_int`: Converts a `barectf.DisplayBase` value to an equivalent integer. `int_ft_str`: Converts an integer field type object to its TSDL string equivalent. The first line is not indented. `ft_str`: Converts any field type object to its TSDL string equivalent. The first line is not indented. 5. Adds the `barectf.TraceType.clock_types` property to easily access the set of required clock types (by all stream types). This is required by 3. Signed-off-by: Philippe Proulx --- barectf/config.py | 10 + barectf/template.py | 87 ++++++ barectf/templates/metadata-enum-ft.j2 | 12 + barectf/templates/metadata-int-ft.j2 | 10 + barectf/templates/metadata-real-ft.j2 | 6 + barectf/templates/metadata-str-ft.j2 | 3 + barectf/templates/metadata-struct-ft.j2 | 11 + barectf/templates/metadata.j2 | 109 +++++++ barectf/tsdl182gen.py | 367 ++++-------------------- poetry.lock | 63 +++- pyproject.toml | 1 + 11 files changed, 369 insertions(+), 310 deletions(-) create mode 100644 barectf/template.py create mode 100644 barectf/templates/metadata-enum-ft.j2 create mode 100644 barectf/templates/metadata-int-ft.j2 create mode 100644 barectf/templates/metadata-real-ft.j2 create mode 100644 barectf/templates/metadata-str-ft.j2 create mode 100644 barectf/templates/metadata-struct-ft.j2 create mode 100644 barectf/templates/metadata.j2 diff --git a/barectf/config.py b/barectf/config.py index edf1bfe..e438cfb 100644 --- a/barectf/config.py +++ b/barectf/config.py @@ -740,6 +740,16 @@ class TraceType: def features(self) -> TraceTypeFeatures: return self._features + @property + def clock_types(self) -> Set[ClockType]: + clk_types = set() + + for stream_type in self._stream_types: + if stream_type.default_clock_type is not None: + clk_types.add(stream_type.default_clock_type) + + return clk_types + _EnvEntry = Union[str, int] _EnvEntries = Mapping[str, _EnvEntry] diff --git a/barectf/template.py b/barectf/template.py new file mode 100644 index 0000000..7329996 --- /dev/null +++ b/barectf/template.py @@ -0,0 +1,87 @@ +# The MIT License (MIT) +# +# Copyright (c) 2020 Philippe Proulx +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import jinja2 +import barectf.config as barectf_config +import barectf.version as barectf_version +from barectf.typing import Count +from typing import Callable, Optional, Any, Mapping + + +def _filt_indent_tab(text: str, count: Count = Count(1), indent_first: bool = False) -> str: + in_lines = text.split('\n') + out_lines = [] + tab = '\t' + + for index, in_line in enumerate(in_lines): + in_line = in_line.rstrip() + + if len(in_line) == 0 or (index == 0 and not indent_first): + out_lines.append(in_line) + continue + + out_lines.append(f'{tab * count}{in_line}') + + return '\n'.join(out_lines) + + +def _filt_escape_dq(text: str) -> str: + return text.replace('\\', '\\\\').replace('"', '\\"') + + +_Filter = Callable[[Any], Any] +_Filters = Mapping[str, _Filter] +_Test = Callable[[Any], bool] +_Tests = Mapping[str, _Test] + + +def _create_template(name: str, cfg: Optional[barectf_config.Configuration] = None, + filters: Optional[_Filters] = None, + tests: Optional[_Test] = None) -> jinja2.Template: + env = jinja2.Environment(trim_blocks=True, lstrip_blocks=True, + loader=jinja2.PackageLoader('barectf', 'templates')) + env.globals.update({ + 'cfg': cfg, + 'barectf_config': barectf_config, + 'barectf_version': barectf_version, + }) + + env.filters['indent_tab'] = _filt_indent_tab + env.filters['escape_dq'] = _filt_escape_dq + + if filters is not None: + env.filters.update(filters) + + if tests is not None: + env.tests.update(tests) + + return env.get_template(name) + + +def _render_template(templ: jinja2.Template, is_file_template: bool = False, **kwargs) -> str: + text = templ.render(**kwargs) + + if is_file_template: + text = text.strip() + '\n' + + return text diff --git a/barectf/templates/metadata-enum-ft.j2 b/barectf/templates/metadata-enum-ft.j2 new file mode 100644 index 0000000..1dc2783 --- /dev/null +++ b/barectf/templates/metadata-enum-ft.j2 @@ -0,0 +1,12 @@ +enum : {{ ft | int_ft_str }} { +{% for label, mapping in ft.mappings.items() %} +{% for rg in mapping.ranges %} + {% if rg.lower == rg.upper %} + {% set rg_str = rg.lower %} + {% else %} + {% set rg_str %}{{ rg.lower }} ... {{ rg.upper }}{% endset %} + {% endif %} + "{{ label | escape_dq }}" = {{ rg_str }}, +{% endfor %} +{% endfor %} +} diff --git a/barectf/templates/metadata-int-ft.j2 b/barectf/templates/metadata-int-ft.j2 new file mode 100644 index 0000000..50e6513 --- /dev/null +++ b/barectf/templates/metadata-int-ft.j2 @@ -0,0 +1,10 @@ +integer { + signed = {{ 'true' if is_signed else 'false' }}; + size = {{ ft.size }}; + align = {{ ft.alignment }}; + byte_order = {{ ft.byte_order | bo_str }}; + base = {{ ft.preferred_display_base | disp_base_int }}; + {% if ft._mapped_clk_type_name %} + map = clock.{{ ft._mapped_clk_type_name }}.value; + {% endif %} +} diff --git a/barectf/templates/metadata-real-ft.j2 b/barectf/templates/metadata-real-ft.j2 new file mode 100644 index 0000000..d70fbfd --- /dev/null +++ b/barectf/templates/metadata-real-ft.j2 @@ -0,0 +1,6 @@ +floating_point { + mant_dig = {{ 24 if ft.size == 32 else 53 }}; + exp_dig = {{ 8 if ft.size == 32 else 11 }}; + align = {{ ft.alignment }}; + byte_order = {{ ft.byte_order | bo_str }}; +} diff --git a/barectf/templates/metadata-str-ft.j2 b/barectf/templates/metadata-str-ft.j2 new file mode 100644 index 0000000..6de8a2b --- /dev/null +++ b/barectf/templates/metadata-str-ft.j2 @@ -0,0 +1,3 @@ +string { + encoding = UTF8; +} diff --git a/barectf/templates/metadata-struct-ft.j2 b/barectf/templates/metadata-struct-ft.j2 new file mode 100644 index 0000000..dcfb05d --- /dev/null +++ b/barectf/templates/metadata-struct-ft.j2 @@ -0,0 +1,11 @@ +struct { +{% for name, member in ft.members.items() %} +{# +`chain` is a list of static array field types terminated with a +non-array field type (the most nested). +#} +{% set chain = ft_chain(member.field_type) %} + {{ chain[-1] | ft_str | indent_tab }} {{ name }} + {%- for array_ft in chain[:-1] %}[{{ array_ft.length }}]{% endfor %}; +{% endfor %} +} align({{ ft.minimum_alignment }}) diff --git a/barectf/templates/metadata.j2 b/barectf/templates/metadata.j2 new file mode 100644 index 0000000..f4d5612 --- /dev/null +++ b/barectf/templates/metadata.j2 @@ -0,0 +1,109 @@ +/* CTF 1.8 */ + +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2020 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * + * The following TSDL code was generated by barectf v{{ barectf_version.__version__ }} + * on {{ cfg.trace.environment['barectf_gen_date'] }}. + * + * For more details, see . + */ +{# +Generates a root field type string named `name` for the field type `rft` +with all the lines except the first one indented with a single tab. +#} +{% macro root_ft(name, rft) -%} +{{ name }} := {{ rft | ft_str | indent_tab }}; +{%- endmacro %} + +trace { + major = 1; + minor = 8; + byte_order = {{ cfg.trace.type.default_byte_order | bo_str }}; + {% if cfg.trace.type.uuid %} + uuid = "{{ cfg.trace.type.uuid }}"; + {% endif %} + {% if cfg.trace.type._pkt_header_ft %} + {{ root_ft('packet.header', cfg.trace.type._pkt_header_ft) }} + {% endif %} +}; + +env { +{% for name, value in cfg.trace.environment.items() %} + {{ name }} = {{ value if value is number else '"{}"'.format(value | escape_dq) }}; +{% endfor %} +}; + +{# all clock types (stream types's default clock types) #} +{% for clk_type in cfg.trace.type.clock_types | sort %} +clock { + name = {{ clk_type.name }}; + {% if clk_type.description %} + description = "{{ clk_type.description | escape_dq }}"; + {% endif %} + {% if clk_type.uuid %} + uuid = "{{ clk_type.uuid }}"; + {% endif %} + freq = {{ clk_type.frequency }}; + precision = {{ clk_type.precision }}; + offset_s = {{ clk_type.offset.seconds }}; + offset = {{ clk_type.offset.cycles }}; + absolute = {{ 'true' if clk_type.origin_is_unix_epoch else 'false' }}; +}; + +{% endfor %} +{# stream types and their event types #} +{%- for stream_type in cfg.trace.type.stream_types | sort %} +/* Stream type `{{ stream_type.name }}` */ +stream { + id = {{ stream_type.id }}; + {{ root_ft('packet.context', stream_type._pkt_ctx_ft) }} + {% if stream_type._ev_header_ft %} + {{ root_ft('event.header', stream_type._ev_header_ft) }} + {% endif %} + {% if stream_type.event_common_context_field_type %} + {{ root_ft('event.context', stream_type.event_common_context_field_type) }} + {% endif %} +}; + +{# stream type's event types #} +{% for ev_type in stream_type.event_types | sort %} +event { + id = {{ ev_type.id }}; + stream_id = {{ stream_type.id }}; + name = "{{ ev_type.name }}"; + {% if ev_type.log_level %} + loglevel = {{ ev_type.log_level }}; + {% endif %} + {% if ev_type.specific_context_field_type %} + {{ root_ft('context', ev_type.specific_context_field_type) }} + {% endif %} + {% if ev_type.payload_field_type %} + {{ root_ft('fields', ev_type.payload_field_type) }} + {% endif %} +}; + +{% endfor %} +{% endfor %} diff --git a/barectf/tsdl182gen.py b/barectf/tsdl182gen.py index 99e3063..aa53e76 100644 --- a/barectf/tsdl182gen.py +++ b/barectf/tsdl182gen.py @@ -21,348 +21,97 @@ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -import barectf.codegen as barectf_codegen -import barectf.version as barectf_version import barectf.config as barectf_config +import barectf.template as barectf_template +import jinja2 +from typing import List, Optional +import typing -def _bool_to_string(b): - return 'true' if b else 'false' +def _filt_bo_str(bo: barectf_config.ByteOrder) -> str: + return { + barectf_config.ByteOrder.LITTLE_ENDIAN: 'le', + barectf_config.ByteOrder.BIG_ENDIAN: 'be', + }[bo] -_byte_order_to_string_map = { - barectf_config.ByteOrder.LITTLE_ENDIAN: 'le', - barectf_config.ByteOrder.BIG_ENDIAN: 'be', -} - - -def _byte_order_to_string(byte_order): - return _byte_order_to_string_map[byte_order] - - -_display_base_to_int_map = { - barectf_config.DisplayBase.BINARY: 2, - barectf_config.DisplayBase.OCTAL: 8, - barectf_config.DisplayBase.DECIMAL: 10, - barectf_config.DisplayBase.HEXADECIMAL: 16, -} - - -def _display_base_to_int(disp_base): - return _display_base_to_int_map[disp_base] - - -def _gen_int_ft(ft, cg): - cg.add_line('integer {') - cg.indent() - cg.add_line(f'size = {ft.size};') - cg.add_line(f'align = {ft.alignment};') - is_signed = isinstance(ft, barectf_config.SignedIntegerFieldType) - cg.add_line(f'signed = {_bool_to_string(is_signed)};') - cg.add_line(f'byte_order = {_byte_order_to_string(ft.byte_order)};') - cg.add_line(f'base = {_display_base_to_int(ft.preferred_display_base)};') - - if isinstance(ft, barectf_config.UnsignedIntegerFieldType) and ft._mapped_clk_type_name is not None: - cg.add_line(f'map = clock.{ft._mapped_clk_type_name}.value;') - - cg.unindent() - cg.add_line('}') - - -def _gen_enum_ft(ft, cg): - cg.add_line('enum : ') - cg.add_glue() - _gen_int_ft(ft, cg) - cg.append_to_last_line(' {') - cg.indent() - - for label, mapping in ft.mappings.items(): - for rg in mapping.ranges: - if rg.lower == rg.upper: - rg_str = str(rg.lower) - else: - rg_str = f'{rg.lower} ... {rg.upper}' - - line = f'"{label}" = {rg_str},' - cg.add_line(line) - - cg.unindent() - cg.add_line('}') - +def _filt_disp_base_int(disp_base: barectf_config.DisplayBase) -> int: + return { + barectf_config.DisplayBase.BINARY: 2, + barectf_config.DisplayBase.OCTAL: 8, + barectf_config.DisplayBase.DECIMAL: 10, + barectf_config.DisplayBase.HEXADECIMAL: 16, + }[disp_base] -def _gen_real_ft(ft, cg): - cg.add_line('floating_point {') - cg.indent() - if ft.size == 32: - exp_dig = 8 - mant_dig = 24 - else: - assert ft.size == 64 - exp_dig = 11 - mant_dig = 53 +def _filt_int_ft_str(ft: barectf_config._FieldType) -> str: + return barectf_template._render_template(_INT_FT_TEMPL, ft=ft, + is_signed=isinstance(ft, barectf_config.SignedIntegerFieldType)) - cg.add_line(f'exp_dig = {exp_dig};') - cg.add_line(f'mant_dig = {mant_dig};') - cg.add_line(f'align = {ft.alignment};') - cg.add_line(f'byte_order = {_byte_order_to_string(ft.byte_order)};') - cg.unindent() - cg.add_line('}') +def _gen_enum_ft(ft: barectf_config._FieldType) -> str: + return barectf_template._render_template(_ENUM_FT_TEMPL, ft=ft) -def _gen_string_ft(ft, cg): - cg.add_line('string {') - cg.indent() - cg.add_line('encoding = UTF8;') - cg.unindent() - cg.add_line('}') +def _gen_real_ft(ft: barectf_config._FieldType) -> str: + return barectf_template._render_template(_REAL_FT_TEMPL, ft=ft) -def _find_deepest_array_ft_element_ft(ft): - if isinstance(ft, barectf_config._ArrayFieldType): - return _find_deepest_array_ft_element_ft(ft.element_field_type) - return ft +def _gen_str_ft(ft: barectf_config._FieldType) -> str: + return barectf_template._render_template(_STR_FT_TEMPL, ft=ft) -def _static_array_ft_lengths(ft, lengths): - if type(ft) is barectf_config.StaticArrayFieldType: - lengths.append(ft.length) - _static_array_ft_lengths(ft.element_field_type, lengths) +def _ft_chain(ft: barectf_config._FieldType) -> List[barectf_config._FieldType]: + chain: List[barectf_config._FieldType] = [] + while isinstance(ft, barectf_config.StaticArrayFieldType): + chain.append(ft) + ft = ft.element_field_type -def _gen_struct_ft_entry(name, ft, cg): - elem_ft = _find_deepest_array_ft_element_ft(ft) - _gen_ft(elem_ft, cg) - cg.append_to_last_line(f' {name}') + chain.append(ft) + return chain - # array - lengths = [] - _static_array_ft_lengths(ft, lengths) - if lengths: - for length in reversed(lengths): - cg.append_to_last_line(f'[{length}]') +def _gen_struct_ft(ft: barectf_config._FieldType) -> str: + return barectf_template._render_template(_STRUCT_FT_TEMPL, ft=ft, ft_chain=_ft_chain) - cg.append_to_last_line(';') - -def _gen_struct_ft(ft, cg): - cg.add_line('struct {') - cg.indent() - - for name, member in ft.members.items(): - _gen_struct_ft_entry(name, member.field_type, cg) - - cg.unindent() - - if len(ft.members) == 0: - cg.add_glue() - - cg.add_line(f'}} align({ft.minimum_alignment})') - - -_ft_to_gen_ft_func = { - barectf_config.UnsignedIntegerFieldType: _gen_int_ft, - barectf_config.SignedIntegerFieldType: _gen_int_ft, +_FT_CLS_TO_GEN_FT_FUNC = { + barectf_config.UnsignedIntegerFieldType: _filt_int_ft_str, + barectf_config.SignedIntegerFieldType: _filt_int_ft_str, barectf_config.UnsignedEnumerationFieldType: _gen_enum_ft, barectf_config.SignedEnumerationFieldType: _gen_enum_ft, barectf_config.RealFieldType: _gen_real_ft, - barectf_config.StringFieldType: _gen_string_ft, + barectf_config.StringFieldType: _gen_str_ft, barectf_config.StructureFieldType: _gen_struct_ft, } -def _gen_ft(ft, cg): - _ft_to_gen_ft_func[type(ft)](ft, cg) - - -def _gen_root_ft(name, ft, cg): - cg.add_line('{} := '.format(name)) - cg.add_glue() - _gen_ft(ft, cg) - cg.append_to_last_line(';') - - -def _try_gen_root_ft(name, ft, cg): - if ft is None: - return - - _gen_root_ft(name, ft, cg) - - -def _gen_start_block(name, cg): - cg.add_line(f'{name} {{') - cg.indent() - - -def _gen_end_block(cg): - cg.unindent() - cg.add_line('};') - cg.add_empty_line() - +def _filt_ft_str(ft: barectf_config._FieldType) -> str: + return _FT_CLS_TO_GEN_FT_FUNC[type(ft)](ft) -def _gen_trace_type_block(config, cg): - trace_type = config.trace.type - _gen_start_block('trace', cg) - cg.add_line('major = 1;') - cg.add_line('minor = 8;') - default_byte_order = trace_type.default_byte_order - if default_byte_order is None: - default_byte_order = barectf_config.ByteOrder.LITTLE_ENDIAN - - cg.add_line(f'byte_order = {_byte_order_to_string(default_byte_order)};') - - if trace_type.uuid is not None: - cg.add_line(f'uuid = "{trace_type.uuid}";') - - _try_gen_root_ft('packet.header', trace_type._pkt_header_ft, cg) - _gen_end_block(cg) - - -def _escape_literal_string(s): - esc = s.replace('\\', '\\\\') - esc = esc.replace('\n', '\\n') - esc = esc.replace('\r', '\\r') - esc = esc.replace('\t', '\\t') - esc = esc.replace('"', '\\"') - return esc - - -def _gen_trace_env_block(config, cg): - env = config.trace.environment - assert env is not None - _gen_start_block('env', cg) - - for name, value in env.items(): - if type(value) is int: - value_string = str(value) - else: - value_string = f'"{_escape_literal_string(value)}"' - - cg.add_line(f'{name} = {value_string};') - - _gen_end_block(cg) - - -def _gen_clk_type_block(clk_type, cg): - _gen_start_block('clock', cg) - cg.add_line(f'name = {clk_type.name};') - - if clk_type.description is not None: - cg.add_line(f'description = "{_escape_literal_string(clk_type.description)}";') - - if clk_type.uuid is not None: - cg.add_line(f'uuid = "{clk_type.uuid}";') - - cg.add_line(f'freq = {clk_type.frequency};') - cg.add_line(f'offset_s = {clk_type.offset.seconds};') - cg.add_line(f'offset = {clk_type.offset.cycles};') - cg.add_line(f'precision = {clk_type.precision};') - cg.add_line(f'absolute = {_bool_to_string(clk_type.origin_is_unix_epoch)};') - _gen_end_block(cg) - - -def _gen_clk_type_blocks(config, cg): - for stream_type in sorted(config.trace.type.stream_types): - if stream_type.default_clock_type is not None: - _gen_clk_type_block(stream_type.default_clock_type, cg) - - -def _gen_stream_type_block(config, stream_type, cg): - cg.add_cc_line(stream_type.name.replace('/', '')) - _gen_start_block('stream', cg) - - if config.trace.type.features.stream_type_id_field_type is not None: - cg.add_line(f'id = {stream_type.id};') - - _try_gen_root_ft('packet.context', stream_type._pkt_ctx_ft, cg) - _try_gen_root_ft('event.header', stream_type._ev_header_ft, cg) - _try_gen_root_ft('event.context', stream_type.event_common_context_field_type, cg) - _gen_end_block(cg) - - -def _gen_ev_type_block(config, stream_type, ev_type, cg): - _gen_start_block('event', cg) - cg.add_line(f'name = "{ev_type.name}";') - - if stream_type.features.event_features.type_id_field_type is not None: - cg.add_line(f'id = {ev_type.id};') - - if config.trace.type.features.stream_type_id_field_type is not None: - cg.add_line(f'stream_id = {stream_type.id};') - cg.append_cc_to_last_line(f'Stream type `{stream_type.name.replace("/", "")}`') - - if ev_type.log_level is not None: - cg.add_line(f'loglevel = {ev_type.log_level};') - - _try_gen_root_ft('context', ev_type.specific_context_field_type, cg) - payload_ft = ev_type.payload_field_type - - if payload_ft is None: - payload_ft = barectf_config.StructureFieldType(8) - - _try_gen_root_ft('fields', ev_type.payload_field_type, cg) - _gen_end_block(cg) - - -def _gen_stream_type_ev_type_blocks(config, cg): - for stream_type in sorted(config.trace.type.stream_types): - _gen_stream_type_block(config, stream_type, cg) - - for ev_type in sorted(stream_type.event_types): - _gen_ev_type_block(config, stream_type, ev_type, cg) - - -def _from_config(config): - cg = barectf_codegen._CodeGenerator('\t') +_TEMPL_FILTERS = { + 'bo_str': _filt_bo_str, + 'disp_base_int': _filt_disp_base_int, + 'int_ft_str': _filt_int_ft_str, + 'ft_str': _filt_ft_str, +} - # version/magic - cg.add_line('/* CTF 1.8 */') - cg.add_empty_line() - cg.add_line('''/* - * The MIT License (MIT) - * - * Copyright (c) 2015-2020 Philippe Proulx - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *''') - cg.add_line(f' * The following TSDL code was generated by barectf v{barectf_version.__version__}') - cg.add_line(f' * on {config.trace.environment["barectf_gen_date"]}.') - cg.add_line(' *') - cg.add_line(' * For more details, see .') - cg.add_line(' */') - cg.add_empty_line() - # trace type block - _gen_trace_type_block(config, cg) +def _create_template(name: str, + cfg: Optional[barectf_config.Configuration] = None) -> jinja2.Template: + return barectf_template._create_template(name, cfg, + typing.cast(barectf_template._Filters, _TEMPL_FILTERS)) - # trace environment block - _gen_trace_env_block(config, cg) - # clock type blocks - _gen_clk_type_blocks(config, cg) +_ENUM_FT_TEMPL = _create_template('metadata-enum-ft.j2') +_INT_FT_TEMPL = _create_template('metadata-int-ft.j2') +_REAL_FT_TEMPL = _create_template('metadata-real-ft.j2') +_STR_FT_TEMPL = _create_template('metadata-str-ft.j2') +_STRUCT_FT_TEMPL = _create_template('metadata-struct-ft.j2') - # stream and type blocks - _gen_stream_type_ev_type_blocks(config, cg) - return cg.code +def _from_config(cfg: barectf_config.Configuration) -> str: + return barectf_template._render_template(_create_template('metadata.j2', cfg), + is_file_template=True) diff --git a/poetry.lock b/poetry.lock index ea8cadc..adf4eed 100644 --- a/poetry.lock +++ b/poetry.lock @@ -28,6 +28,20 @@ zipp = ">=0.5" docs = ["sphinx", "rst.linker"] testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] +[[package]] +category = "main" +description = "A very fast and expressive template engine." +name = "jinja2" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.11.2" + +[package.dependencies] +MarkupSafe = ">=0.23" + +[package.extras] +i18n = ["Babel (>=0.8)"] + [[package]] category = "main" description = "An implementation of JSON Schema validation for Python" @@ -50,6 +64,14 @@ version = "*" format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"] format_nongpl = ["idna", "jsonpointer (>1.13)", "webcolors", "rfc3986-validator (>0.1.0)", "rfc3339-validator"] +[[package]] +category = "main" +description = "Safely add untrusted strings to HTML/XML markup." +name = "markupsafe" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +version = "1.1.1" + [[package]] category = "main" description = "Persistent/Functional/Immutable data structures" @@ -99,7 +121,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["jaraco.itertools", "func-timeout"] [metadata] -content-hash = "2f2cf818db3b560712dbd0c7900be46cb0135efdd4de5decc1df157991693279" +content-hash = "a4409c00d57cf44d61809d0073fe1433379ea22afdd4cb25a2fd1f7a4b8951d4" python-versions = '^3.6' [metadata.files] @@ -111,10 +133,49 @@ importlib-metadata = [ {file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"}, {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"}, ] +jinja2 = [ + {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, + {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, +] jsonschema = [ {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, ] +markupsafe = [ + {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, + {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, + {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, + {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, + {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, + {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, + {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, + {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, + {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, + {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, +] pyrsistent = [ {file = "pyrsistent-0.16.0.tar.gz", hash = "sha256:28669905fe725965daa16184933676547c5bb40a5153055a8dee2a4bd7933ad3"}, ] diff --git a/pyproject.toml b/pyproject.toml index 076cced..59c2ca3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,6 +59,7 @@ termcolor = '^1.1' pyyaml = '^5.3' jsonschema = '^3.2' setuptools = '*' +jinja2 = '^2.11' [tool.poetry.scripts] barectf = 'barectf.cli:_run' -- 2.34.1