Coverage for lobster/tools/trlc/trlc_tool.py: 88%

64 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-01-09 10:06 +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/>. 

19 

20import argparse 

21import os 

22import sys 

23from typing import Iterable, Optional, Sequence 

24 

25from yamale import YamaleError 

26 

27from trlc.errors import Message_Handler, TRLC_Error 

28from trlc.trlc import Source_Manager 

29 

30from lobster.common.errors import PathError 

31from lobster.common.items import Requirement 

32from lobster.common.multi_file_input_tool import create_worklist, MultiFileInputTool 

33 

34from lobster.tools.trlc.converter import Converter 

35from lobster.tools.trlc.errors import ( 

36 InvalidConversionRuleError, 

37 RecordObjectComponentError, 

38 TrlcFailure, 

39 TupleToStringFailedError, 

40 TupleToStringMissingError, 

41) 

42from lobster.tools.trlc.lobster_trlc_config import LobsterTrlcConfig 

43 

44 

45class LOBSTER_Trlc(MultiFileInputTool): 

46 def __init__(self): 

47 super().__init__( 

48 name = "trlc", 

49 description = "Extract tracing data from TRLC files.", 

50 extensions = ["rsl", "trlc"], 

51 official = True, 

52 ) 

53 

54 def _run_impl(self, options: argparse.Namespace): 

55 try: 

56 self._execute(options) 

57 return 0 

58 except YamaleError as e: 

59 print( 

60 f"{self.name}: The configuration file does not " 

61 f"conform to the YAML schema. {e}", 

62 file=sys.stderr, 

63 ) 

64 except TRLC_Error as e: 

65 print( 

66 f"{self.name}: An error occurred during processing: {e}", 

67 file=sys.stderr, 

68 ) 

69 except FileNotFoundError as e: 

70 print( 

71 f"{self.name}: File or directory not found: {e}", 

72 file=sys.stderr, 

73 ) 

74 except PathError as e: 

75 print( 

76 f"{self.name}: {e}", 

77 file=sys.stderr, 

78 ) 

79 except TrlcFailure as e: 

80 print( 

81 f"{self.name}: TRLC processing failed: {e}", 

82 file=sys.stderr, 

83 ) 

84 except (InvalidConversionRuleError, RecordObjectComponentError) as e: 

85 print( 

86 f"{self.name}: Invalid conversion rule defined in {options.config}: " 

87 f"{e}", 

88 file=sys.stderr, 

89 ) 

90 except (TupleToStringMissingError, TupleToStringFailedError) as e: 

91 print( 

92 f"{self.name}: error in 'to-string-rules' in {options.config}: " 

93 f"{e}", 

94 file=sys.stderr, 

95 ) 

96 

97 return 1 

98 

99 @staticmethod 

100 def _register_trlc_files(sm: Source_Manager, work_list: Iterable[str]): 

101 for item in work_list: 

102 ok = True 

103 if os.path.isfile(item): 103 ↛ 105line 103 didn't jump to line 105 because the condition on line 103 was always true

104 ok = sm.register_file(item) 

105 elif os.path.isdir(item): 

106 ok = sm.register_directory(item) 

107 else: 

108 raise FileNotFoundError(item) 

109 if not ok: 109 ↛ 110line 109 didn't jump to line 110 because the condition on line 109 was never true

110 raise PathError(f"Failed to register file or directory '{item}'") 

111 

112 def _execute(self, options: argparse.Namespace) -> None: 

113 config = LobsterTrlcConfig.from_file(options.config) 

114 work_list = create_worklist(config, options.dir_or_files) 

115 trlc_mh = Message_Handler() 

116 sm = Source_Manager(trlc_mh) 

117 self._register_trlc_files(sm, work_list) 

118 symbol_table = sm.process() 

119 if not symbol_table: 

120 raise TrlcFailure("aborting due to TRLC error") 

121 

122 items = [] 

123 converter = Converter( 

124 conversion_rules=config.conversion_rules, 

125 to_string_rules=config.to_string_rules, 

126 symbol_table=symbol_table, 

127 ) 

128 for n_obj in symbol_table.iter_record_objects(): 

129 item = converter.generate_lobster_object(n_obj) 

130 if item: 

131 items.append(item) 

132 

133 # lobster-trace: trlc_req.Output_File 

134 self._write_output(Requirement, options.out, items) 

135 

136 

137def main(args: Optional[Sequence[str]] = None) -> int: 

138 return LOBSTER_Trlc().run(args)