Coverage for lobster/tools/trlc/trlc_tool.py: 88%
67 statements
« prev ^ index » next coverage.py v7.10.5, created at 2025-08-27 13:02 +0000
« prev ^ index » next coverage.py v7.10.5, created at 2025-08-27 13:02 +0000
1#!/usr/bin/env python3
2#
3# LOBSTER - Lightweight Open BMW Software Traceability Evidence Report
4# Copyright (C) 2023-2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU Affero General Public License as
8# published by the Free Software Foundation, either version 3 of the
9# License, or (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14# Affero General Public License for more details.
15#
16# You should have received a copy of the GNU Affero General Public
17# License along with this program. If not, see
18# <https://www.gnu.org/licenses/>.
20import argparse
21import os
22import sys
23from typing import Iterable, Optional, Sequence
25from yamale import YamaleError
27from trlc.errors import Message_Handler, TRLC_Error
28from trlc.trlc import Source_Manager
30from lobster.common.errors import PathError
31from lobster.common.io import lobster_write
32from lobster.common.items import Requirement
33from lobster.common.multi_file_input_tool import create_worklist, MultiFileInputTool
35from lobster.tools.trlc.converter import Converter
36from lobster.tools.trlc.errors import (
37 InvalidConversionRuleError,
38 RecordObjectComponentError,
39 TrlcFailure,
40 TupleToStringFailedError,
41 TupleToStringMissingError,
42)
43from lobster.tools.trlc.lobster_trlc_config import LobsterTrlcConfig
46class LOBSTER_Trlc(MultiFileInputTool):
47 def __init__(self):
48 super().__init__(
49 name = "trlc",
50 description = "Extract tracing data from TRLC files.",
51 extensions = ["rsl", "trlc"],
52 official = True,
53 )
55 def _run_impl(self, options: argparse.Namespace):
56 try:
57 self._execute(options)
58 return 0
59 except YamaleError as e:
60 print(
61 f"{self.name}: The configuration file does not "
62 f"conform to the YAML schema. {e}",
63 file=sys.stderr,
64 )
65 except TRLC_Error as e:
66 print(
67 f"{self.name}: An error occurred during processing: {e}",
68 file=sys.stderr,
69 )
70 except FileNotFoundError as e:
71 print(
72 f"{self.name}: File or directory not found: {e}",
73 file=sys.stderr,
74 )
75 except PathError as e:
76 print(
77 f"{self.name}: {e}",
78 file=sys.stderr,
79 )
80 except TrlcFailure as e:
81 print(
82 f"{self.name}: TRLC processing failed: {e}",
83 file=sys.stderr,
84 )
85 except (InvalidConversionRuleError, RecordObjectComponentError) as e:
86 print(
87 f"{self.name}: Invalid conversion rule defined in {options.config}: "
88 f"{e}",
89 file=sys.stderr,
90 )
91 except (TupleToStringMissingError, TupleToStringFailedError) as e:
92 print(
93 f"{self.name}: error in 'to-string-rules' in {options.config}: "
94 f"{e}",
95 file=sys.stderr,
96 )
98 return 1
100 @staticmethod
101 def _register_trlc_files(sm: Source_Manager, work_list: Iterable[str]):
102 for item in work_list:
103 ok = True
104 if os.path.isfile(item): 104 ↛ 106line 104 didn't jump to line 106 because the condition on line 104 was always true
105 ok = sm.register_file(item)
106 elif os.path.isdir(item):
107 ok = sm.register_directory(item)
108 else:
109 raise FileNotFoundError(item)
110 if not ok: 110 ↛ 111line 110 didn't jump to line 111 because the condition on line 110 was never true
111 raise PathError(f"Failed to register file or directory '{item}'")
113 def _execute(self, options: argparse.Namespace) -> None:
114 config = LobsterTrlcConfig.from_file(options.config)
115 work_list = create_worklist(config, options.dir_or_files)
116 trlc_mh = Message_Handler()
117 sm = Source_Manager(trlc_mh)
118 self._register_trlc_files(sm, work_list)
119 symbol_table = sm.process()
120 if not symbol_table:
121 raise TrlcFailure("aborting due to TRLC error")
123 items = []
124 converter = Converter(
125 conversion_rules=config.conversion_rules,
126 to_string_rules=config.to_string_rules,
127 symbol_table=symbol_table,
128 )
129 for n_obj in symbol_table.iter_record_objects():
130 item = converter.generate_lobster_object(n_obj)
131 if item:
132 items.append(item)
134 with open(options.out, "w", encoding="UTF-8") as fd:
135 # lobster-trace: trlc_req.Output_File
136 lobster_write(
137 fd=fd,
138 kind=Requirement,
139 generator="lobster-trlc",
140 items=items,
141 )
142 print(f"lobster-trlc: successfully wrote {len(items)} items to {options.out}")
145def main(args: Optional[Sequence[str]] = None) -> int:
146 return LOBSTER_Trlc().run(args)