mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-25 17:09:44 +00:00
089db2cadf
[no changelog]
187 lines
4.9 KiB
Python
Executable File
187 lines
4.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
CORE_DIR = Path(__file__).resolve().parent.parent
|
|
EXTMOD_PATH = CORE_DIR / "embed" / "upymod"
|
|
RUSTMOD_PATH = CORE_DIR / "embed" / "rust" / "src"
|
|
MOCKS_PATH = CORE_DIR / "mocks" / "generated"
|
|
|
|
COMMENT_PREFIX_SHORT = "///"
|
|
COMMENT_PREFIX = COMMENT_PREFIX_SHORT + " "
|
|
|
|
current_indent = 0
|
|
current_class = None
|
|
current_method = None
|
|
current_package = None
|
|
current_method_is_overload = False
|
|
|
|
|
|
def split_to_parts(line, mod_desc=None):
|
|
global current_indent
|
|
global current_class
|
|
global current_method
|
|
global current_package
|
|
global current_method_is_overload
|
|
|
|
if line.startswith("package: "):
|
|
current_package = line[9:].strip()
|
|
return
|
|
|
|
if line.startswith("mock:global"):
|
|
current_indent = 0
|
|
current_class = None
|
|
return
|
|
|
|
if line == "@overload\n":
|
|
current_method_is_overload = True
|
|
return
|
|
|
|
if line.startswith("class "):
|
|
current_class = line[6:].split("(")[0].strip(":")
|
|
current_indent = 0
|
|
|
|
yield (current_package, "\n\n")
|
|
yield (current_package, "# " + mod_desc + "\n")
|
|
|
|
elif line.startswith("def "):
|
|
current_method = line[4:].split("(")[0]
|
|
|
|
if current_class is None:
|
|
yield (current_package, "\n\n")
|
|
yield (current_package, "# " + mod_desc + "\n")
|
|
else:
|
|
yield (current_package, "\n")
|
|
current_indent = 4
|
|
|
|
if current_method_is_overload:
|
|
yield (current_package, current_indent * " " + "@overload\n")
|
|
current_method_is_overload = False
|
|
|
|
if not line.strip():
|
|
yield (current_package, "\n")
|
|
else:
|
|
line = current_indent * " " + line
|
|
yield (current_package, line)
|
|
|
|
|
|
def store_to_file(dest, parts):
|
|
for package, line in parts:
|
|
package = package.replace(".", "/")
|
|
dirpath = dest / os.path.dirname(package)
|
|
filename = os.path.basename(package) + ".pyi"
|
|
filepath = dirpath / filename
|
|
|
|
dirpath.mkdir(parents=True, exist_ok=True)
|
|
|
|
if (dest / package).is_dir():
|
|
if not line.strip():
|
|
continue
|
|
print(f"Package exists: {package}")
|
|
print(f"You should set 'package:' in {line.strip()}")
|
|
sys.exit(1)
|
|
|
|
if not filepath.exists():
|
|
filepath.write_text("from typing import *\n")
|
|
|
|
with open(filepath, "a") as f:
|
|
f.write(line)
|
|
|
|
|
|
def build_module(mod_file, dest):
|
|
global current_indent
|
|
global current_class
|
|
global current_package
|
|
|
|
assert mod_file.name.startswith("mod")
|
|
assert mod_file.suffix in (".c", ".h")
|
|
# modfoobar-xyz.h -> foobar-xyz
|
|
name = mod_file.name[3:-2]
|
|
|
|
current_indent = 0
|
|
current_class = None
|
|
current_package = name.split("-")[0]
|
|
mod_desc = str(mod_file.relative_to(CORE_DIR / "embed"))
|
|
|
|
for l in open(mod_file):
|
|
if not l.startswith(COMMENT_PREFIX_SHORT):
|
|
continue
|
|
l = l[len(COMMENT_PREFIX) :] # .strip()
|
|
|
|
store_to_file(dest, split_to_parts(l, mod_desc))
|
|
|
|
|
|
def build_rsmodule(mod_file, dest):
|
|
global current_indent
|
|
global current_class
|
|
global current_package
|
|
|
|
assert mod_file.suffix == ".rs"
|
|
|
|
start_prefix = "pub static mp_module_"
|
|
comment_prefix = f" {COMMENT_PREFIX}"
|
|
in_module = False
|
|
current_indent = 0
|
|
current_class = None
|
|
mod_desc = str(mod_file.relative_to(CORE_DIR / "embed"))
|
|
|
|
for l in open(mod_file):
|
|
if l.startswith(start_prefix):
|
|
in_module = True
|
|
current_package = l[len(start_prefix) : ].split(":")[0]
|
|
elif l.startswith("}"):
|
|
in_module = False
|
|
|
|
if not in_module:
|
|
continue
|
|
|
|
if not l.startswith(comment_prefix):
|
|
continue
|
|
|
|
l = l[len(comment_prefix) :]
|
|
store_to_file(dest, split_to_parts(l, mod_desc))
|
|
|
|
|
|
def place_symlinks(dest):
|
|
# make symlinks for the non-generated files
|
|
for pyi in MOCKS_PATH.glob("../*.pyi"):
|
|
dest_file = dest / pyi.name
|
|
dest_file.symlink_to(os.path.relpath(pyi.resolve(), dest))
|
|
|
|
|
|
def build_directory(dest):
|
|
for modfile in sorted(EXTMOD_PATH.glob("**/mod*.[ch]")):
|
|
build_module(modfile, dest)
|
|
for modfile in sorted(RUSTMOD_PATH.glob("**/*.rs")):
|
|
build_rsmodule(modfile, dest)
|
|
place_symlinks(dest)
|
|
|
|
|
|
def do_check():
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
build_directory(Path(tmpdir))
|
|
diff_out = subprocess.run(
|
|
["diff", "-ur", str(MOCKS_PATH), tmpdir],
|
|
stdout=subprocess.PIPE,
|
|
universal_newlines=True,
|
|
).stdout
|
|
if diff_out.strip():
|
|
print(diff_out, end="")
|
|
sys.exit(1)
|
|
|
|
|
|
def do_generate():
|
|
shutil.rmtree(MOCKS_PATH)
|
|
build_directory(MOCKS_PATH)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) > 1 and sys.argv[1] == "--check":
|
|
do_check()
|
|
else:
|
|
do_generate()
|