"""Transport for the `blender` domain — args in, delegate, format out.""" from __future__ import annotations import typer from tooling.core import cli, console from tooling.core.command import command from tooling.domains.blender import service app = cli.domain("blender", "Run the Blender payloads — the one carve-out.") @app.callback() def _domain() -> None: """Keeps `blender` a group (Typer collapses a single-command app).""" @app.command("list") @command def list_payloads() -> None: """List every payload `run` accepts. Worth a verb of its own: the payload names are not guessable and this is the only place the vocabulary is written down. """ names = service.payloads() for name in names: console.out(name) console.verdict(f"{len(names)} payload(s) in {service.payload_dir().name}/") @app.command("which") @command def which() -> None: """Report which Blender would be used, without launching it.""" invocation = service.resolve_blender() console.out(f"kind {invocation.kind}") console.out(f"command {' '.join(invocation.argv_prefix)}") console.verdict( "flatpak — paths are absolutised before they cross the sandbox" if invocation.sandboxed else "native install — preferred when both are present" ) @app.command("run", context_settings={"allow_extra_args": True, "ignore_unknown_options": True}) @command def run( ctx: typer.Context, payload: str = typer.Argument( ..., help="Payload name (see `reach blender list`), or a path to any script." ), background: bool = typer.Option( True, "--background/--no-background", help="Headless, or open the Blender GUI." ), ) -> None: """Run a payload under Blender, passing any remaining arguments through. Extra arguments go to the payload after `--`, and any that name an existing path are made absolute first — flatpak's sandbox resolves relative paths against a different root, and the resulting file-not-found comes from inside Blender, a long way from its cause. """ service.run_payload(payload, list(ctx.args), background=background)