app
adom-desktop-altium-bridge
Public Unreviewedby barrett-land
Adom Desktop bridge for Altium Designer — build and edit file-based symbol/footprint/Integrated libraries with LCSC/JLCPCB part numbers attached, and generate batch outputs (STEP, PDF, Gerber, BOM, CPL) from an OutJob, by driving Altium via DelphiScript.
master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
#!/usr/bin/env python3
"""check_wiring — prove the three halves of this bridge agree, before publishing.
The bridge is three files that each carry their own list of what exists:
bridge.json verbs[] what Adom Desktop advertises
server.py COMMAND_HANDLERS what the HTTP server routes
AdomAltium.pas Dispatch what Altium actually implements
Nothing enforced that they matched, and they drifted: the shipped package routed
verbs its own script could not run, and the repo's readable source was two verbs
behind the zip that was actually installed. Run this in deploy.sh so a mismatch
fails the build instead of shipping.
Pure static parsing (regex over the sources) so it runs in the Linux container,
where the Windows-only bridge modules cannot be imported.
Usage: python3 check_wiring.py [bridge-src-dir] -> exit 0 clean, 1 on mismatch
"""
import json
import re
import sys
from pathlib import Path
# Verbs the server answers itself, with no in-Altium counterpart to match against.
HOST_ONLY = {"altium_ping", "altium_detect", "altium_script_state",
"altium_install_extension"}
def routed_verbs(server_py: Path) -> dict:
"""{verb: pas_command_or_None} from COMMAND_HANDLERS plus each handler's body."""
text = server_py.read_text(encoding="utf-8")
table = re.search(r"COMMAND_HANDLERS\s*=\s*\{(.*?)\n\}", text, re.S)
if not table:
sys.exit("check_wiring: COMMAND_HANDLERS table not found in server.py")
pairs = re.findall(r'"(altium_[a-z_]+)"\s*:\s*(\w+)', table.group(1))
# Map handler function -> the addin_call command it issues (if any).
bodies = re.split(r"\ndef ", text)
handler_cmd = {}
for body in bodies:
name = re.match(r"(\w+)\s*\(", body)
if not name:
continue
call = re.search(r'addin_call\(\s*"([a-z_]+)"', body)
handler_cmd[name.group(1)] = call.group(1) if call else None
return {verb: handler_cmd.get(fn) for verb, fn in pairs}
def pas_commands(pas: Path) -> set:
"""Command strings the DelphiScript Dispatch procedure compares against."""
text = pas.read_text(encoding="utf-8", errors="replace")
block = re.search(r"procedure Dispatch;(.*?)\nend;", text, re.S)
if not block:
sys.exit("check_wiring: Dispatch procedure not found in AdomAltium.pas")
return set(re.findall(r"Cmd\s*=\s*'([a-z_]+)'", block.group(1)))
def main() -> int:
root = Path(sys.argv[1] if len(sys.argv) > 1 else Path(__file__).parent)
routed = routed_verbs(root / "server.py")
implemented = pas_commands(root / "addin" / "AdomAltium" / "AdomAltium.pas")
advertised = set(json.loads((root / "bridge.json").read_text())["verbs"])
problems = []
# 1. Every routed verb must reach a command the script implements.
for verb, cmd in sorted(routed.items()):
if verb in HOST_ONLY:
continue
if cmd is None:
problems.append(f"{verb}: handler issues no addin_call (host-only? add to HOST_ONLY)")
elif cmd not in implemented:
problems.append(f"{verb}: routes to '{cmd}', which AdomAltium.pas does not dispatch")
# 2. bridge.json is what Adom Desktop shows the user; an omission hides a verb.
for verb in sorted(set(routed) - advertised):
problems.append(f"{verb}: routed by server.py but missing from bridge.json verbs[]")
for verb in sorted(advertised - set(routed)):
problems.append(f"{verb}: advertised in bridge.json but not routed by server.py")
# 3. Script commands with no verb are dead weight — a warning, not a failure:
# 'add_lcsc_param' is legitimately reached via the altium_add_component verb.
unreachable = implemented - {c for c in routed.values() if c}
if unreachable:
print(f"note: script commands with no verb: {', '.join(sorted(unreachable))}")
if problems:
print(f"\nFAIL — {len(problems)} wiring mismatch(es):")
for p in problems:
print(f" - {p}")
return 1
print(f"OK — {len(routed)} verbs routed, {len(implemented)} script commands, bridge.json agrees.")
return 0
if __name__ == "__main__":
sys.exit(main())