#!/usr/bin/env python3 """Print host executable pins for Codex development commands.""" from collections.abc import Callable from collections.abc import Mapping from collections.abc import Sequence import json import os from pathlib import Path import shutil import sys # Keep this explicit: justfile recipes can delegate to scripts that invoke other tools. HOST_EXECUTABLES = ("cargo", "just", "bazel", "pnpm") GENERATED_HEADER = "# Generated by scripts/setup_dev_execpolicy.py. Do not edit." WINDOWS_EXECUTABLE_SUFFIXES = (".exe", ".cmd", ".bat", ".com") def executable_lookup_name(path: Path, *, windows: bool = os.name == "nt") -> str: name = path.name if not windows: return name name = name.lower() for suffix in WINDOWS_EXECUTABLE_SUFFIXES: if name.endswith(suffix): return name[: -len(suffix)] return name def absolute_without_resolving(path: str) -> Path: return Path(os.path.abspath(os.path.expanduser(path))) def discover_host_executables( names: Sequence[str] = HOST_EXECUTABLES, *, which: Callable[[str], str | None] = shutil.which, ) -> dict[str, Path]: executables: dict[str, Path] = {} missing: list[str] = [] for name in names: raw_path = which(name) if raw_path is None: missing.append(name) continue path = absolute_without_resolving(raw_path) if executable_lookup_name(path) != executable_lookup_name(Path(name)): raise RuntimeError( f"resolved path for {name!r} must retain that executable name: {path}" ) executables[name] = path if missing: raise RuntimeError( "missing required host executables on PATH: " + ", ".join(missing) ) return executables def render_host_executable_rules(executables: Mapping[str, Path]) -> str: blocks = [] for name, path in executables.items(): blocks.append( "\n".join( [ "host_executable(", f" name = {json.dumps(name)},", f" paths = [{json.dumps(str(path))}],", ")", ] ) ) return f"{GENERATED_HEADER}\n\n" + "\n\n".join(blocks) + "\n" def main() -> int: try: executables = discover_host_executables() except RuntimeError as error: print(f"error: {error}", file=sys.stderr) return 1 sys.stdout.write(render_host_executable_rules(executables)) return 0 if __name__ == "__main__": raise SystemExit(main())