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:
parent
491647085f
commit
1f20b2984f
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user