SAE Teensy ECU
IIT SAE Microcontroller programming
Loading...
Searching...
No Matches
file_entry.py
1import os
2import re
3from typing import Callable
4
5import script.regex as REGEX
6import script.error as Error
7import script.text as Text
8import script.util as Util
9import script.id_matcher as IDMatch
10
11IGNORE_KEYWORD = "PRE_BUILD_IGNORE" # Keyword that makes this script ignore a line
12
13FILE_LOG_LEVELS = {
14 "p": "",
15 "": "[ LOG ] ",
16 "d": "[DEBUG] ",
17 "i": "[INFO] ",
18 "w": "[WARN] ",
19 "e": "[ERROR] ",
20 "f": "[FATAL] ",
21}
22
23
24class FileEntry: # IMPROVE: Make IDs persistent
25 """Represents a source file to map log calls with"""
26
27 name = ""
28 path = ""
29 rawpath = ""
30 working_path = ""
31 offset = ""
32 modified = False
33 errors: list[str]
34
35 def __init__(self, RawPath, FilePath, FileName, Offset):
36 if not os.path.exists(FilePath):
37 raise FileNotFoundError(FilePath)
38
39 self.namename = FileName
40 self.pathpath = FilePath
41 self.rawpathrawpath = RawPath
42 self.working_pathworking_path = f"{Offset}{FilePath}"
43 self.offsetoffset = Offset
44 self.errorserrors = list()
45
46 Util.touch(f"{Offset}{RawPath}")
47
48 def new_error(self, exception: Exception, name: str, tag: str) -> None:
49 """Store an error to display later
50
51 Args:
52 exception (Exception): Exception to store
53 name (str): Name of this error
54 tag (str): Additional tag for this error
55 """
56 self.errorserrors.append(f" {name}:{tag}\n {Text.red(type(exception).__name__)}\n > {Error.error_to_string(exception)}\n")
57
58 async def get_new_pair_mapping(self, tag_str: str, id_str: str, map_range: range) -> int:
59 """Get a new unique mapping to both a TAG and ID
60
61 Args:
62 tag_str (str): raw tag string to store
63 id_str (str): raw id string to store
64
65 Returns:
66 int: uid to replace these strings with
67 """
68
69 tag_str = tag_str.strip('"')
70 tstring = f"[{tag_str}]"
71 istring = id_str.strip('"')
72 number_id = await IDMatch.map_unique_pair(tstring, istring, map_range)
73 return number_id
74
75 async def get_new_tag(self, tag_str: str) -> int:
76 """Get a new unique TAG mapping
77
78 Args:
79 tag_str (str): raw string to store
80
81 Returns:
82 int: uid to replace this string with
83 """
84
85 state_match = re.findall(REGEX.STATE_PASS, tag_str)
86
87 tag_str = tag_str.strip('"')
88 tstring = f"[{tag_str}]"
89
90 number_id = await IDMatch.map_unique_tag(tstring, IDMatch.TAG_RANGE_STATE if len(state_match) != 0 else IDMatch.TAG_RANGE_ELSE)
91 return number_id
92
93 async def get_new_id(self, raw_log_level: str, id_str: str) -> int:
94 """Get a new unique ID mapping
95
96 Args:
97 raw_log_level (str): Logging level of this tag
98 id_str (str): raw string to store
99
100 Returns:
101 int: uid to replace this string with
102 """
103 istring = FILE_LOG_LEVELS[raw_log_level] + id_str.strip('"')
104 number_id = await IDMatch.map_unique_id(istring)
105 return number_id
106
107 async def line_special(self, line: str, matches: list[str]) -> str:
108 """Format special string msg calls
109
110 Args:
111 line (str): The line that matched this type
112 reMatch (list[str]): The resulting regex list
113
114 Returns:
115 str: Reformatted line
116 """
117 uid = await self.get_new_id("", matches) # Special strings are always LOG for simplicity
118 return line.replace(matches, str(uid), 1)
119
120 async def line_tag(self, line: str, matches: list[str]) -> str:
121 """Format defined log tags
122
123 Args:
124 line (str): The line that matched this type
125 reMatch (list[str]): The resulting regex list
126
127 Returns:
128 str: Reformatted line
129 """
130 tag = await self.get_new_tag(matches)
131 return line.replace(matches, str(tag), 1)
132
133 async def line_vsx(self, line: str, matches: list[str]) -> str:
134 """Format 'variable string' type log calls
135
136 Args:
137 line (str): The line that matched this type
138 reMatch (list[str]): The resulting regex list
139
140 Returns:
141 str: Reformatted line
142 """
143 uid = await self.get_new_id(matches[0], matches[2])
144 return line.replace(matches[2], str(uid), 1)
145
146 async def line_ssx(self, line: str, matches: list[str]) -> str:
147 """Format 'string string' type log calls
148
149 Args:
150 line (str): The line that matched this type
151 reMatch (list[str]): The resulting regex list
152
153 Returns:
154 str: Reformatted line
155 """
156
157 tag = 0
158 uid = 0
159
160 if matches[0] == "p":
161 tag = await self.get_new_pair_mapping(matches[1], matches[2], IDMatch.TAG_RANGE_VALUE)
162 uid = tag
163 else:
164 tag = await self.get_new_tag(matches[1])
165 uid = await self.get_new_id(matches[0], matches[2])
166
167 return line.replace(matches[1], str(tag), 1).replace(matches[2], str(uid), 1)
168
169 async def map_lines(self, function: Callable[[str], str]) -> None:
170 """Map a function to each line of this file
171
172 Args:
173 function (Callable[[str], None]): Function that takes in a str and returns a str
174 """
175 temp_path = self.working_pathworking_path + ".__Lock"
176 line_no = 1
177 newline = ""
178
179 with open(self.pathpath, "r", encoding="utf-8") as original, open(temp_path, "w", encoding="utf-8") as new_file:
180 for line in original:
181 try:
182 newline = await function(line)
183 new_file.buffer.write(newline.encode("utf-8"))
184 except Exception as err: # If prev exception was about IO then oh well
185 self.new_error(err, self.pathpath, line_no)
186 new_file.buffer.write(line.encode("utf-8"))
187 finally:
188 line_no += 1
189 self.modifiedmodified = Util.sync_file(temp_path, self.offsetoffset, self.rawpathrawpath, self.working_pathworking_path)
190 os.remove(temp_path)
191
192 async def match_log_mapping(self, line: str) -> str:
193 """Maps a source file line to Log related syntax
194
195 Args:
196 line (str): The line to scan
197
198 Raises:
199 ScriptException: On invalid Log related syntax
200
201 Returns:
202 str: Reformatted line
203 """
204 newline: str = line
205
206 if IGNORE_KEYWORD in newline: # Return if this line has the ignore keyword
207 return newline
208
209 scan_sequence = [
210 (REGEX.CALL_VS, self.line_vsxline_vsx),
211 (REGEX.CALL_VSV, self.line_vsxline_vsx),
212 (REGEX.CALL_SS, self.line_ssxline_ssx),
213 (REGEX.CALL_SSV, self.line_ssxline_ssx),
214 (REGEX.SPECIAL_PASS, self.line_specialline_special),
215 (REGEX.TAG_PASS, self.line_tagline_tag),
216 ]
217
218 for reg, func in scan_sequence:
219 matches = re.findall(reg, line)
220 if len(matches) != 0:
221 return await func(line, matches[0])
222
223 fail_sequence = [
224 (REGEX.TAG_FAIL, Error.MalformedTAGDefinitionException),
225 (REGEX.CALL_ERR_LITERAL, Error.MalformedLogCallException),
226 (REGEX.CALL_ERR_BLANK, Error.BlankTAGException),
227 ]
228
229 for reg, exception in fail_sequence:
230 err = re.findall(reg, line)
231 if len(err) != 0:
232 err = err[0]
233 raise exception(err[0] + Text.error(err[1]) + err[2])
234
235 return newline
236
237 async def scan(self) -> None:
238 """Begin replacing lines for mapping log calls"""
Represents a source file to map log calls with.
Definition file_entry.py:24
int get_new_pair_mapping(self, str tag_str, str id_str, range map_range)
Get a new unique mapping to both a TAG and ID.
Definition file_entry.py:58
rawpath
Definition file_entry.py:41
line_ssx
str line_special(self, str line, list[str] matches)
Format special string msg calls.
str offset
Definition file_entry.py:31
int get_new_tag(self, str tag_str)
Get a new unique TAG mapping.
Definition file_entry.py:75
str path
Definition file_entry.py:28
match_log_mapping
str line_vsx(self, str line, list[str] matches)
Format 'variable string' type log calls.
offset
Definition file_entry.py:43
None scan(self)
Begin replacing lines for mapping log calls.
list errors
Definition file_entry.py:33
str match_log_mapping(self, str line)
Maps a source file line to Log related syntax.
working_path
Definition file_entry.py:42
line_vsx
modified
str name
Definition file_entry.py:27
bool modified
Definition file_entry.py:32
name
Definition file_entry.py:39
line_special
None map_lines(self, Callable[[str], str] function)
Map a function to each line of this file.
int get_new_id(self, str raw_log_level, str id_str)
Get a new unique ID mapping.
Definition file_entry.py:93
str working_path
Definition file_entry.py:30
str line_tag(self, str line, list[str] matches)
Format defined log tags.
line_tag
None new_error(self, Exception exception, str name, str tag)
Store an error to display later.
Definition file_entry.py:48
str rawpath
Definition file_entry.py:29
path
Definition file_entry.py:40
errors
Definition file_entry.py:44
str line_ssx(self, str line, list[str] matches)
Format 'string string' type log calls.
Error related items.
Definition error.py:1
Regex definitions for logging.
Definition regex.py:1
Text styling functions.
Definition text.py:1
Misc.
Definition util.py:1