SAE Teensy ECU
IIT SAE Microcontroller programming
Loading...
Searching...
No Matches
util.py
1"""Misc. utility functions"""
2
3import hashlib
4import os
5import shutil
6import glob
7import errno
8import subprocess
9from pathlib import Path
10from os.path import join as join_path
11
12import script.text as Text
13
14
15def encode_log_map(path: str) -> None:
16 """Encodes the last generated log map into a z-lib compressed C binary array
17
18 Args:
19 path (str): Path to store the C file containing the array
20 """
21 print("Encoding LogMap 📃\n")
22 subprocess.Popen(
23 [
24 "python",
25 "bin2cc.py",
26 "-i",
27 "log_lookup.json",
28 "-o",
29 f"{path}\\log_lookup.cpp",
30 "-v",
31 "log_lookup",
32 ]
33 ).wait()
34
35
36def check_git_submodules(file_types: str) -> None:
37 """Checks for missing or uninitalized submodules within project
38
39 Args:
40 file_types (str): File types to expect in submodules
41 """
42 err = False
43 try:
44 response = subprocess.check_output("git config -f .gitmodules -l", stderr=subprocess.STDOUT, shell=True)
45 submodules = tuple(line.split("=")[1] for line in response.decode("utf-8").splitlines() if ".url=" not in line)
46 for module in submodules:
47 if (
48 not os.path.exists(module)
49 or not os.path.isdir(module)
50 or not list(1 for ext in file_types if len(glob.glob(f"**{os.path.sep}*{ext}", root_dir=module, recursive=True)))
51 ):
52 print(Text.warning("Submodule does not exist, or contains no source files : " + module))
53 err = True
54 except subprocess.CalledProcessError:
55 print(Text.error("Failed to check for git submodules"))
56 if err:
57 print(Text.important("\nConsider running " + Text.red("git pull --recurse-submodules")))
58 print(Text.important("or " + Text.red("git submodule update --init")) + Text.important(" if repo has just been cloned\n"))
59
60
61LIB_BLACKLIST = join_path("libraries", ".blacklist")
62
63
64def get_library_blacklist() -> dict[str, list]:
65 """Get the library folder blacklist based on core model
66
67 Returns:
68 dict[str, list]: folder blacklist as a dict
69 """
70 blacklist: dict[str, list] = {}
71 with open(LIB_BLACKLIST, "r", encoding="utf-8") as file:
72 currentModel = ""
73 for line in file.readlines():
74 if line[0] == ".":
75 currentModel = line.split(" ")[0][1:]
76 if currentModel not in blacklist:
77 blacklist[currentModel] = []
78 else:
79 for token in line.split(" "):
80 token = token.strip(" \n")
81 if not token or token[0] == "#":
82 break
83 elif os.path.exists(join_path(os.path.dirname(LIB_BLACKLIST), token)):
84 blacklist[currentModel].append(join_path(os.path.dirname(LIB_BLACKLIST), token))
85 return blacklist
86
87
88FILES_CHANGED = False
89
90
91def sync_file(filePath: str, offset: str, rawpath: str, workingFilePath: str = None, suppress: bool = False) -> bool:
92 """Syncs a file between directories
93
94 Args:
95 filePath (str): Path to the original file
96 offset (str): Path offset to prepend to the rawpath to get the filepath
97 rawpath (str): Path to the directory the original file is in
98 workingFilePath (str, optional): Path to the file to sync to. Defaults to offset + filepath.
99 suppress (bool, optional): Suppress log messages. Defaults to False.
100
101 Returns:
102 bool: Whether the file was synced
103 """
104 workingFilePath = workingFilePath or f"{offset}{filePath}"
105
106 new = hashFile(filePath)
107 old = hashFile(workingFilePath)
108 if old == "":
109 old = 0
110
111 if not os.path.exists(workingFilePath) or new != old:
112 global FILES_CHANGED
113 FILES_CHANGED = True
114 touch(f"{offset}{rawpath}")
115 shutil.copyfile(filePath, workingFilePath)
116 if not suppress:
117 print(f"Sync File: {os.path.basename(workingFilePath)}")
118 return True
119 return False
120
121
122def touch(rawpath: str) -> None:
123 """Creates a directory tree
124
125 Args:
126 rawpath (str): Path to generate
127 """
128 try:
129 Path(rawpath).mkdir(parents=True, exist_ok=True)
130 except OSError as exc:
131 if exc.errno != errno.EEXIST:
132 raise
133
134
135RAM_MEMO = False
136
137
138def available_ram() -> bool:
139 """Get The amount of RAM available in GBs
140
141 Returns:
142 bool: RAM in GBs
143 """
144 global RAM_MEMO
145 if not RAM_MEMO:
146 out = subprocess.check_output("wmic OS get FreePhysicalMemory /Value", stderr=subprocess.STDOUT, shell=True)
147 RAM_MEMO = round(
148 int(str(out).strip("b").strip("'").replace("\\r", "").replace("\\n", "").replace("FreePhysicalMemory=", "")) / 1048576, 2
149 )
150 return RAM_MEMO
151
152
153LOW_RAM = 4
154BUF_SIZE = 65536
155
156
157def hashFile(filePath: str) -> str:
158 """Hashes a file
159
160 Args:
161 filePath (str): Path to the file to hash
162
163 Returns:
164 str: HEX string of the file's hash
165 """
166 if os.path.exists(filePath):
167 if available_ram() <= LOW_RAM:
168 sha256 = hashlib.sha256()
169 with open(filePath, "rb") as f:
170 while True:
171 data = f.read(BUF_SIZE)
172 if not data:
173 break
174 sha256.update(data)
175 return sha256.digest()
176 else:
177 with open(filePath, "rb") as f:
178 return hashlib.sha256(f.read()).hexdigest()
179 return ""
Text styling functions.
Definition text.py:1
str hashFile(str filePath)
Hashes a file.
Definition util.py:157
None check_git_submodules(str file_types)
Checks for missing or uninitalized submodules within project.
Definition util.py:36
None touch(str rawpath)
Creates a directory tree.
Definition util.py:122
bool available_ram()
Get The amount of RAM available in GBs.
Definition util.py:138
dict[str, list] get_library_blacklist()
Get the library folder blacklist based on core model.
Definition util.py:64
None encode_log_map(str path)
Encodes the last generated log map into a z-lib compressed C binary array.
Definition util.py:15
bool sync_file(str filePath, str offset, str rawpath, str workingFilePath=None, bool suppress=False)
Syncs a file between directories.
Definition util.py:91