"""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())