Files
templates/tools/firmware-publish/firmware_db.py

83 lines
3.9 KiB
Python

"""Standalone firmware database CLI; requires Python 3.10+, no SETGUI."""
from __future__ import annotations
import argparse
import json
import os
import sys
from dataclasses import asdict
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "python"))
from setprotocol.firmware_database import (
Credentials, FirmwareDatabase, GiteaFirmwarePublisher, GiteaRepository,
)
from setprotocol.firmware_publish import FirmwarePublication, SUPPORTED_TRANSPORTS
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--server", required=True, help="Gitea HTTPS URL")
parser.add_argument("--owner", required=True)
parser.add_argument("--repo", required=True)
parser.add_argument("--branch", default="main")
parser.add_argument("--manifest", default="update.json")
commands = parser.add_subparsers(dest="command", required=True)
catalog = commands.add_parser("list")
catalog.add_argument("--product")
catalog.add_argument("--transport", choices=sorted(SUPPORTED_TRANSPORTS))
download = commands.add_parser("download")
download.add_argument("--product", required=True)
download.add_argument("--version-code", type=lambda v: int(v, 0), required=True)
download.add_argument("--transport", choices=sorted(SUPPORTED_TRANSPORTS), required=True)
download.add_argument("--cache", type=Path, default=Path("firmware"))
for name in ("preflight", "publish"):
command = commands.add_parser(name)
command.add_argument("--file", type=Path, required=True)
command.add_argument("--product", required=True)
command.add_argument("--version", required=True)
command.add_argument("--version-code", type=lambda v: int(v, 0), required=True)
command.add_argument("--transport", choices=sorted(SUPPORTED_TRANSPORTS), required=True)
command.add_argument("--base-address", type=lambda v: int(v, 0))
command.add_argument("--notes", default="")
args = parser.parse_args()
try:
repository = GiteaRepository(args.server, args.owner, args.repo, args.branch, args.manifest)
login = os.environ.get("FIRMWARE_DB_LOGIN")
password = os.environ.get("FIRMWARE_DB_PASSWORD")
credentials = Credentials(login, password) if login and password else None
if args.command in ("list", "download"):
database = FirmwareDatabase(repository.manifest_url,
getattr(args, "cache", Path("firmware")),
credentials=credentials)
rows = database.read_catalog(product=args.product, transport=args.transport)
if args.command == "list":
print(json.dumps([asdict(row) for row in rows], ensure_ascii=False, indent=2))
else:
rows = [row for row in rows if row.version_code == args.version_code]
if len(rows) != 1:
raise ValueError("Expected exactly one matching firmware release")
print(database.download(rows[0]))
else:
publication = FirmwarePublication(args.file.resolve(), args.product, args.version,
args.version_code, args.transport,
args.base_address, args.notes)
publisher = GiteaFirmwarePublisher(repository, credentials)
if args.command == "publish":
if credentials is None:
raise ValueError("Set FIRMWARE_DB_LOGIN and FIRMWARE_DB_PASSWORD for publication")
result = publisher.publish(publication)
else:
result = publisher.preflight(publication)
print(json.dumps(result, ensure_ascii=False, indent=2))
except (OSError, ValueError, RuntimeError) as error:
print(f"Firmware database: {error}", file=sys.stderr)
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())