diff --git a/Makefile b/Makefile index a1eaf394f..1cab33d0f 100644 --- a/Makefile +++ b/Makefile @@ -113,10 +113,10 @@ templates_check: ## check that coin lists are up to date make -C core templates_check solana_templates: ## rebuild Solana instruction template file - make -C core solana_templates + python tools/build_solana_templates.py solana_templates_check: ## check that Solana instruction template file is up to date - make -C core solana_templates_check + python tools/build_solana_templates.py --check icons: ## generate FIDO service icons python3 core/tools/build_icons.py diff --git a/core/src/apps/solana/transaction/programs.json b/common/defs/solana/programs.json similarity index 100% rename from core/src/apps/solana/transaction/programs.json rename to common/defs/solana/programs.json diff --git a/core/Makefile b/core/Makefile index b7d0a9167..dba27525e 100644 --- a/core/Makefile +++ b/core/Makefile @@ -225,12 +225,6 @@ translations_check: ## check that translations are up to date # spits out error if the stored merkle root is not up to date python ./translations/cli.py merkle-root > /dev/null -solana_templates: ## rebuild Solana instruction template file - ./tools/build_solana_templates - -solana_templates_check: ## check that Solana instruction template file is up to date - ./tools/build_solana_templates --check - ## build commands: build: build_boardloader build_bootloader build_firmware build_prodtest build_unix ## build all diff --git a/core/tools/build_solana_templates b/core/tools/build_solana_templates deleted file mode 100755 index 46675ebfe..000000000 --- a/core/tools/build_solana_templates +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env bash -set -e - -CWD=`dirname "$0"` -RENDER="python3 $CWD/build_solana_templates.py" - -PROGRAMS_FILE_PATH="$CWD/../src/apps/solana/transaction/programs.json" - -FW_PATH="$CWD/../src/apps/solana/transaction" -FW_TEMPLATE_PATH="$FW_PATH/instructions.py.mako" -FW_OUTPUT_PATH="$FW_PATH/instructions.py" - -TESTS_PATH="$CWD/../../tests/device_tests/solana/construct" -TESTS_TEMPLATE_PATH="$TESTS_PATH/instructions.py.mako" -TESTS_OUTPUT_PATH="$TESTS_PATH/instructions.py" - -format() { - isort $1 -q - black $1 -q - flake8 $1 -q -} - -check_results() { - TEMPLATE_PATH=$1 - OUTPUT_PATH=$2 - - CHECK_FAIL=0 - - TMP="./core/tools/solana_template_check$(date +%s).py" - touch $TMP - - TARGET=$OUTPUT_PATH - $RENDER $TEMPLATE_PATH -p $PROGRAMS_FILE_PATH -o $TMP - format $TMP - - if ! diff -u "$TARGET" "$TMP"; then - CHECK_FAIL=1 - fi - - rm $TMP - - exit $CHECK_FAIL -} - -set_output_timestamp() { - TEMPLATE_PATH=$1 - OUTPUT_PATH=$2 - - PROGRAMS_FILE_TIMESTAMP=$(date -r $PROGRAMS_FILE_PATH) - TEMPLATE_TIMESTAMP=$(date -r $TEMPLATE_PATH) - - if [[ "$PROGRAMS_FILE_TIMESTAMP" > "$TEMPLATE_TIMESTAMP" ]]; then - touch $OUTPUT_PATH -r $PROGRAMS_FILE_PATH - else - touch $OUTPUT_PATH -r $TEMPLATE_PATH - fi -} - -if [ "$1" = "--check" ]; then - check_results $FW_PATH $FW_OUTPUT_PATH - check_results $TESTS_PATH $TESTS_OUTPUT_PATH -else - $RENDER $FW_PATH -p $PROGRAMS_FILE_PATH -o $FW_OUTPUT_PATH - format $FW_OUTPUT_PATH - set_output_timestamp $FW_TEMPLATE_PATH $FW_OUTPUT_PATH - - $RENDER $TESTS_PATH -p "$PROGRAMS_FILE_PATH" -o $TESTS_OUTPUT_PATH - format $TESTS_OUTPUT_PATH - set_output_timestamp $TESTS_TEMPLATE_PATH $TESTS_OUTPUT_PATH -fi diff --git a/core/tools/build_solana_templates.py b/core/tools/build_solana_templates.py deleted file mode 100755 index fe0c52d56..000000000 --- a/core/tools/build_solana_templates.py +++ /dev/null @@ -1,22 +0,0 @@ -# !/usr/bin/env python3 -from json import load - -import click -from mako.template import Template -from munch import munchify - - -@click.command() -@click.argument("template_path", type=str) -@click.option("-p", "--programs-file", type=click.File(mode="r"), default="-") -@click.option("-o", "--out-file", type=click.File(mode="w"), default="-") -def render(template_path, programs_file, out_file): - programs = munchify(load(programs_file)) - - template = Template(filename=f"{template_path}/instructions.py.mako") - - out_file.write(template.render(programs=programs)) - - -if __name__ == "__main__": - render() diff --git a/tools/build_solana_templates.py b/tools/build_solana_templates.py new file mode 100755 index 000000000..12b734810 --- /dev/null +++ b/tools/build_solana_templates.py @@ -0,0 +1,82 @@ +# !/usr/bin/env python3 +import json +import os +import subprocess +import tempfile +from pathlib import Path + +import click +from mako.template import Template +from munch import munchify, Munch + +HERE = Path(__file__).parent +ROOT = HERE.parent.resolve() + +TEMPLATES = ( + ROOT / "core" / "src" / "apps" / "solana" / "transaction" / "instructions.py.mako", + ROOT / "tests" / "device_tests" / "solana" / "construct" / "instructions.py.mako", +) + +PROGRAMS_JSON = ROOT / "common" / "defs" / "solana" / "programs.json" + + +def _silent_call(*args): + subprocess.check_call(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + +def format(file: Path): + _silent_call("isort", file) + _silent_call("black", file) + _silent_call("flake8", file) + + +def render_single(template_path: Path, programs: Munch) -> str: + template = Template(filename=str(template_path.resolve())) + with tempfile.NamedTemporaryFile(mode="w", dir=template_path.parent) as f: + f.write(str(template.render(programs=programs))) + f.flush() + + # after flushing the contents, on-disk file will be formatted... + format(Path(f.name)) + # ...and we need to explicitly open it again to get the updated contents, + # otherwise we get cached results? + with open(f.name, "r") as new_f: + return new_f.read() + + +@click.command() +@click.option( + "-c", "--check", is_flag=True, help="Check if the templates are up to date" +) +def build_templates(check: bool): + programs = munchify(json.loads(PROGRAMS_JSON.read_text())) + prog_stat = PROGRAMS_JSON.stat() + + all_ok = True + for template_path in TEMPLATES: + assert template_path.suffix == ".mako" + dest_path = template_path.with_suffix("") + result = render_single(template_path, programs) + + if check: + if result != dest_path.read_text(): + print(f"{dest_path} is out of date") + all_ok = False + + else: + tmpl_stat = template_path.stat() + dest_path.write_text(result) + os.utime( + dest_path, + ns=( + max(tmpl_stat.st_atime_ns, prog_stat.st_atime_ns), + max(tmpl_stat.st_mtime_ns, prog_stat.st_mtime_ns), + ), + ) + + if not all_ok: + raise click.ClickException("Some templates are out of date") + + +if __name__ == "__main__": + build_templates()