mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-08 19:56:53 +00:00
Three repository rules, one new target, and CI found all three. `argparse` is used only in annotations here, so with postponed evaluation it belongs in a type-checking block; ruff calls that TC003 and the lint job went red. up.py keeps the plain import because it constructs an argparse.Namespace at runtime, which is the distinction the rule is about. Make targets are defined in ascending order, so binfmt moves above bond. Every make target carries a shell alias, the aliases are themselves sorted, and an alias name may not hold more than two adjacent consonants. `i8bi` was free and satisfies all three. Verified: ruff clean, the two lint files pass, and `make binfmt arch=arm64` still registers emulation, which is what proves the import really is annotation-only rather than merely accepted by the linter. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
103 lines
2.5 KiB
Python
103 lines
2.5 KiB
Python
"""Register the emulation an architecture-pinned deploy needs."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import platform
|
|
import subprocess
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
import argparse
|
|
|
|
PROBE_IMAGE = "alpine:3"
|
|
INSTALLER_IMAGE = "tonistiigi/binfmt"
|
|
|
|
_HOST_ALIASES = {
|
|
"x86_64": "amd64",
|
|
"amd64": "amd64",
|
|
"aarch64": "arm64",
|
|
"arm64": "arm64",
|
|
}
|
|
|
|
|
|
def host_architecture() -> str:
|
|
machine = platform.machine().lower()
|
|
return _HOST_ALIASES.get(machine, machine)
|
|
|
|
|
|
def _can_execute(architecture: str) -> bool:
|
|
return (
|
|
subprocess.run(
|
|
[
|
|
"docker",
|
|
"run",
|
|
"--rm",
|
|
"--platform",
|
|
f"linux/{architecture}",
|
|
PROBE_IMAGE,
|
|
"true",
|
|
],
|
|
stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.DEVNULL,
|
|
check=False,
|
|
).returncode
|
|
== 0
|
|
)
|
|
|
|
|
|
def ensure(platform_ref: str | None = None) -> None:
|
|
"""No-op when nothing is pinned or it is the host's own; raises SystemExit
|
|
when the handler cannot be registered."""
|
|
raw = (
|
|
platform_ref
|
|
if platform_ref is not None
|
|
else os.environ.get("INFINITO_DOCKER_PLATFORM")
|
|
)
|
|
pinned = (raw or "").strip()
|
|
if not pinned:
|
|
return
|
|
|
|
architecture = pinned.rsplit("/", 1)[-1]
|
|
if architecture == host_architecture() or _can_execute(architecture):
|
|
return
|
|
|
|
print(f">>> Registering binfmt emulation for {pinned}")
|
|
subprocess.run(
|
|
[
|
|
"docker",
|
|
"run",
|
|
"--privileged",
|
|
"--rm",
|
|
INSTALLER_IMAGE,
|
|
"--install",
|
|
architecture,
|
|
],
|
|
stdout=subprocess.DEVNULL,
|
|
check=False,
|
|
)
|
|
|
|
if not _can_execute(architecture):
|
|
raise SystemExit(
|
|
f"linux/{architecture} still cannot execute after registering a handler. "
|
|
"Check whether this host permits --privileged containers."
|
|
)
|
|
|
|
|
|
def add_parser(sub: argparse._SubParsersAction) -> None:
|
|
p = sub.add_parser(
|
|
"binfmt", help="Make an architecture executable here through emulation."
|
|
)
|
|
p.add_argument(
|
|
"--architecture",
|
|
default="",
|
|
help="amd64 | arm64; empty takes the platform from INFINITO_DOCKER_PLATFORM.",
|
|
)
|
|
p.set_defaults(_handler=handler)
|
|
|
|
|
|
def handler(args: argparse.Namespace) -> int:
|
|
named = args.architecture.strip()
|
|
ensure(f"linux/{named}" if named else None)
|
|
return 0
|