1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-19 05:58:09 +00:00

feat(common/cointool): use support.json as a source of the list of supported models

This commit is contained in:
matejcik 2024-09-02 10:15:13 +02:00 committed by matejcik
parent 491647085f
commit 1f20b2984f
3 changed files with 33 additions and 55 deletions

View File

@ -26,32 +26,13 @@ ROOT = Path(__file__).resolve().parent.parent
DEFS_DIR = ROOT / "defs" DEFS_DIR = ROOT / "defs"
class SupportItemBool(TypedDict):
supported: dict[str, bool]
unsupported: dict[str, bool]
class SupportItemVersion(TypedDict): class SupportItemVersion(TypedDict):
supported: dict[str, str] supported: dict[str, str]
unsupported: dict[str, str] unsupported: dict[str, str]
class SupportData(TypedDict): SupportData = Dict[str, SupportItemVersion]
connect: SupportItemBool SupportInfoItem = Dict[str, Literal[False] | str]
suite: SupportItemBool
t1b1: SupportItemVersion
t2t1: SupportItemVersion
t2b1: SupportItemVersion
class SupportInfoItem(TypedDict):
connect: bool
suite: bool
t1b1: Literal[False] | str
t2t1: Literal[False] | str
t2b1: Literal[False] | str
SupportInfo = Dict[str, SupportInfoItem] SupportInfo = Dict[str, SupportInfoItem]
@ -449,8 +430,6 @@ def _load_fido_apps() -> FidoApps:
# ====== support info ====== # ====== support info ======
RELEASES_URL = "https://data.trezor.io/firmware/{}/releases.json" RELEASES_URL = "https://data.trezor.io/firmware/{}/releases.json"
MISSING_SUPPORT_MEANS_NO = ("connect", "suite")
VERSIONED_SUPPORT_INFO = ("T1B1", "T2T1", "T2B1", "T3T1", "T3B1")
def get_support_data() -> SupportData: def get_support_data() -> SupportData:
@ -458,14 +437,18 @@ def get_support_data() -> SupportData:
return load_json("support.json") return load_json("support.json")
def get_models() -> list[str]:
"""Get all models from `support.json`."""
return list(get_support_data().keys())
def latest_releases() -> dict[str, Any]: def latest_releases() -> dict[str, Any]:
"""Get latest released firmware versions for all models""" """Get latest released firmware versions for all models"""
if not requests: if not requests:
raise RuntimeError("requests library is required for getting release info") raise RuntimeError("requests library is required for getting release info")
latest: dict[str, Any] = {} latest: dict[str, Any] = {}
for model in VERSIONED_SUPPORT_INFO: for model in get_models():
# TODO: support new UPPERCASE model names in RELEASES_URL
url_model = model.lower() # need to be e.g. t1b1 for now url_model = model.lower() # need to be e.g. t1b1 for now
releases = requests.get(RELEASES_URL.format(url_model)).json() releases = requests.get(RELEASES_URL.format(url_model)).json()
latest[model] = max(tuple(r["version"]) for r in releases) latest[model] = max(tuple(r["version"]) for r in releases)
@ -492,8 +475,6 @@ def support_info_single(support_data: SupportData, coin: Coin) -> SupportInfoIte
support_value: Any = False support_value: Any = False
elif key in values["supported"]: elif key in values["supported"]:
support_value = values["supported"][key] support_value = values["supported"][key]
elif device in MISSING_SUPPORT_MEANS_NO:
support_value = False
else: else:
support_value = None support_value = None
support_info_item[device] = support_value support_info_item[device] = support_value

View File

@ -160,6 +160,7 @@ def render_file(
ROOT=ROOT, ROOT=ROOT,
**coins, **coins,
**MAKO_FILTERS, **MAKO_FILTERS,
ALL_MODELS=coin_info.get_models(),
) )
dst.write_text(str(result)) dst.write_text(str(result))
src_stat = src.stat() src_stat = src.stat()

View File

@ -11,6 +11,7 @@ import click
import coin_info import coin_info
SUPPORT_INFO = coin_info.get_support_data() SUPPORT_INFO = coin_info.get_support_data()
MODELS = coin_info.get_models()
VERSION_RE = re.compile(r"\d+.\d+.\d+") VERSION_RE = re.compile(r"\d+.\d+.\d+")
@ -64,7 +65,7 @@ def set_unsupported(device, key, value):
def print_support(coin): def print_support(coin):
def support_value(where, key, missing_means_no=False): def support_value(where, key):
if "supported" in where and key in where["supported"]: if "supported" in where and key in where["supported"]:
val = where["supported"][key] val = where["supported"][key]
if val is True: if val is True:
@ -76,8 +77,6 @@ def print_support(coin):
elif "unsupported" in where and key in where["unsupported"]: elif "unsupported" in where and key in where["unsupported"]:
val = where["unsupported"][key] val = where["unsupported"][key]
return f"NO (reason: {val})" return f"NO (reason: {val})"
elif missing_means_no:
return "NO"
else: else:
return "support info missing" return "support info missing"
@ -86,8 +85,7 @@ def print_support(coin):
if coin.get("duplicate"): if coin.get("duplicate"):
print(" * DUPLICATE SYMBOL") print(" * DUPLICATE SYMBOL")
for dev, where in SUPPORT_INFO.items(): for dev, where in SUPPORT_INFO.items():
missing_means_no = dev in coin_info.MISSING_SUPPORT_MEANS_NO print(" *", dev, ":", support_value(where, key))
print(" *", dev, ":", support_value(where, key, missing_means_no))
# ====== validation functions ====== # # ====== validation functions ====== #
@ -111,12 +109,7 @@ def check_support_values():
else: else:
for key, value in supported.items(): for key, value in supported.items():
try: try:
if device in coin_info.VERSIONED_SUPPORT_INFO: _check_value_version_soon(value)
_check_value_version_soon(value)
else:
if value is not True:
raise ValueError(f"only allowed is True, but found {value}")
if key in unsupported: if key in unsupported:
raise ValueError(f"{key} is both supported and unsupported") raise ValueError(f"{key} is both supported and unsupported")
@ -135,7 +128,7 @@ def check_support_values():
def find_unsupported_coins(coins_dict): def find_unsupported_coins(coins_dict):
result = {} result = {}
for device in coin_info.VERSIONED_SUPPORT_INFO: for device in MODELS:
supported, unsupported = support_dicts(device) supported, unsupported = support_dicts(device)
support_set = set(supported.keys()) support_set = set(supported.keys())
support_set.update(unsupported.keys()) support_set.update(unsupported.keys())
@ -253,10 +246,8 @@ def release(
key: val for key, val in (release.split("=") for release in releases) key: val for key, val in (release.split("=") for release in releases)
} }
for key in user_releases_dict: for key in user_releases_dict:
if key not in coin_info.VERSIONED_SUPPORT_INFO: if key not in MODELS:
raise click.ClickException( raise click.ClickException(f"Unknown device: {key} - allowed are: {MODELS}")
f"Unknown device: {key} - allowed are: {coin_info.VERSIONED_SUPPORT_INFO}"
)
def bump_version(version_tuple: tuple[int]) -> str: def bump_version(version_tuple: tuple[int]) -> str:
version_list = list(version_tuple) version_list = list(version_tuple)
@ -267,7 +258,7 @@ def release(
# Take version either from user or guess it from latest releases info # Take version either from user or guess it from latest releases info
device_release_version: dict[str, str] = {} device_release_version: dict[str, str] = {}
for device in coin_info.VERSIONED_SUPPORT_INFO: for device in MODELS:
if device in user_releases_dict: if device in user_releases_dict:
device_release_version[device] = user_releases_dict[device] device_release_version[device] = user_releases_dict[device]
else: else:
@ -355,15 +346,18 @@ def set_support_value(key, entries, reason):
"""Set a support info variable. """Set a support info variable.
Examples: Examples:
support.py set coin:BTC T1B1=1.10.5 T2T1=2.4.7 suite=yes connect=no support.py set coin:BTC T1B1=1.10.5 T2T1=2.4.7 T2B1=no
support.py set coin:LTC T1B1=yes connect=
Setting a variable to "yes", "true" or "1" sets support to true.
Setting a variable to "no", "false" or "0" sets support to false.
(or null, in case of T1B1/T2T1)
Setting variable to empty ("T1B1=") will set to null, or clear the entry.
Setting a variable to a particular version string (e.g., "2.4.7") will set that Setting a variable to a particular version string (e.g., "2.4.7") will set that
particular version. particular version as the earliest supported.
Setting a variable to "yes", "true" or "1" sets support to the upcoming release,
as fetched via `coin_info.latest_releases()`.
Setting a variable to "no", "false" or "0" sets support to false. You will need to
provide a reason for unsupporting, either via the `-r` option, or interactively.
Setting variable to empty ("T1B1=") will set to null, or clear the entry.
""" """
defs, _ = coin_info.coin_info_with_duplicates() defs, _ = coin_info.coin_info_with_duplicates()
coins = defs.as_dict() coins = defs.as_dict()
@ -372,6 +366,11 @@ def set_support_value(key, entries, reason):
click.echo("Use 'support.py show' to search for the right one.") click.echo("Use 'support.py show' to search for the right one.")
sys.exit(1) sys.exit(1)
latest_releases = coin_info.latest_releases()
next_releases = {
k: (maj, min, pat + 1) for k, (maj, min, pat) in latest_releases.items()
}
for entry in entries: for entry in entries:
try: try:
device, value = entry.split("=", maxsplit=1) device, value = entry.split("=", maxsplit=1)
@ -383,11 +382,8 @@ def set_support_value(key, entries, reason):
raise click.ClickException(f"unknown device: {device}") raise click.ClickException(f"unknown device: {device}")
if value in ("yes", "true", "1"): if value in ("yes", "true", "1"):
set_supported(device, key, True) set_supported(device, key, next_releases[device])
elif value in ("no", "false", "0"): elif value in ("no", "false", "0"):
if device in coin_info.MISSING_SUPPORT_MEANS_NO:
click.echo(f"Setting explicitly unsupported for {device}.")
click.echo(f"Perhaps you meant removing support, i.e., '{device}=' ?")
if not reason: if not reason:
reason = click.prompt(f"Enter reason for not supporting on {device}:") reason = click.prompt(f"Enter reason for not supporting on {device}:")
set_unsupported(device, key, reason) set_unsupported(device, key, reason)