mirror of
https://github.com/openai/codex.git
synced 2026-05-23 20:44:50 +00:00
## Why The package builder should describe the binaries it is actually packaging, not require callers to restate release metadata out of band. A caller-provided `--version` flag can drift from the workspace version, but running the target entrypoint to discover its version breaks cross-target packages when the produced binary cannot execute on the build host. This PR keeps package metadata tied to the repository source of truth by reading `[workspace.package].version` from `codex-rs/Cargo.toml`. It also prepares the package layout for `codex-app-server` packages: the same package structure can now represent either the CLI entrypoint or the app-server entrypoint while keeping shared sidecars such as `rg`, `bwrap`, and Windows sandbox helpers in the existing package directories. ## What changed - Removes the `--version` CLI flag from `scripts/build_codex_package.py`. - Adds Cargo.toml version discovery for `codex-package.json.version` via `codex-rs/Cargo.toml`. - Adds `--entrypoint-bin` so callers can package a prebuilt entrypoint instead of rebuilding it with Cargo. - Makes `--variant` an explicit choice between `codex` and `codex-app-server`, and uses it to select the cargo binary and packaged `bin/` entrypoint name. - Updates `scripts/codex_package/README.md` to document variants, prebuilt entrypoints, and Cargo.toml version detection. ## Verification - Compiled `scripts/build_codex_package.py` and `scripts/codex_package/*.py` with `PYTHONDONTWRITEBYTECODE=1`. - Ran `scripts/build_codex_package.py --help` and verified `--version` is gone while `--variant` and `--entrypoint-bin` are present. - Verified the package builder reads version `0.0.0` from `codex-rs/Cargo.toml`. - Built a fake cross-target `codex-app-server` package using a non-executable `--entrypoint-bin`; verified metadata records version `0.0.0`, variant `codex-app-server`, and `bin/codex-app-server` as the entrypoint.
164 lines
4.4 KiB
Python
164 lines
4.4 KiB
Python
"""Supported package targets and default binary discovery."""
|
|
|
|
import platform
|
|
import stat
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
|
|
|
|
SCRIPT_DIR = Path(__file__).resolve().parents[1]
|
|
REPO_ROOT = SCRIPT_DIR.parent
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class TargetSpec:
|
|
target: str
|
|
is_windows: bool
|
|
is_linux: bool
|
|
dotslash_platform: str
|
|
|
|
@property
|
|
def exe_suffix(self) -> str:
|
|
return ".exe" if self.is_windows else ""
|
|
|
|
@property
|
|
def rg_name(self) -> str:
|
|
return f"rg{self.exe_suffix}"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class PackageVariant:
|
|
name: str
|
|
cargo_bin: str
|
|
executable_stem: str
|
|
|
|
def entrypoint_name(self, spec: TargetSpec) -> str:
|
|
return f"{self.executable_stem}{spec.exe_suffix}"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class PackageInputs:
|
|
entrypoint_bin: Path
|
|
rg_bin: Path
|
|
bwrap_bin: Path | None
|
|
codex_command_runner_bin: Path | None
|
|
codex_windows_sandbox_setup_bin: Path | None
|
|
|
|
|
|
PACKAGE_VARIANTS: dict[str, PackageVariant] = {
|
|
"codex": PackageVariant(
|
|
name="codex",
|
|
cargo_bin="codex",
|
|
executable_stem="codex",
|
|
),
|
|
"codex-app-server": PackageVariant(
|
|
name="codex-app-server",
|
|
cargo_bin="codex-app-server",
|
|
executable_stem="codex-app-server",
|
|
),
|
|
}
|
|
|
|
|
|
TARGET_SPECS: dict[str, TargetSpec] = {
|
|
"x86_64-unknown-linux-gnu": TargetSpec(
|
|
target="x86_64-unknown-linux-gnu",
|
|
is_windows=False,
|
|
is_linux=True,
|
|
dotslash_platform="linux-x86_64",
|
|
),
|
|
"x86_64-unknown-linux-musl": TargetSpec(
|
|
target="x86_64-unknown-linux-musl",
|
|
is_windows=False,
|
|
is_linux=True,
|
|
dotslash_platform="linux-x86_64",
|
|
),
|
|
"aarch64-unknown-linux-gnu": TargetSpec(
|
|
target="aarch64-unknown-linux-gnu",
|
|
is_windows=False,
|
|
is_linux=True,
|
|
dotslash_platform="linux-aarch64",
|
|
),
|
|
"aarch64-unknown-linux-musl": TargetSpec(
|
|
target="aarch64-unknown-linux-musl",
|
|
is_windows=False,
|
|
is_linux=True,
|
|
dotslash_platform="linux-aarch64",
|
|
),
|
|
"x86_64-apple-darwin": TargetSpec(
|
|
target="x86_64-apple-darwin",
|
|
is_windows=False,
|
|
is_linux=False,
|
|
dotslash_platform="macos-x86_64",
|
|
),
|
|
"aarch64-apple-darwin": TargetSpec(
|
|
target="aarch64-apple-darwin",
|
|
is_windows=False,
|
|
is_linux=False,
|
|
dotslash_platform="macos-aarch64",
|
|
),
|
|
"x86_64-pc-windows-msvc": TargetSpec(
|
|
target="x86_64-pc-windows-msvc",
|
|
is_windows=True,
|
|
is_linux=False,
|
|
dotslash_platform="windows-x86_64",
|
|
),
|
|
"aarch64-pc-windows-msvc": TargetSpec(
|
|
target="aarch64-pc-windows-msvc",
|
|
is_windows=True,
|
|
is_linux=False,
|
|
dotslash_platform="windows-aarch64",
|
|
),
|
|
}
|
|
|
|
|
|
HOST_RELEASE_TARGETS: dict[tuple[str, str], str] = {
|
|
("darwin", "aarch64"): "aarch64-apple-darwin",
|
|
("darwin", "x86_64"): "x86_64-apple-darwin",
|
|
("linux", "aarch64"): "aarch64-unknown-linux-musl",
|
|
("linux", "x86_64"): "x86_64-unknown-linux-musl",
|
|
("windows", "aarch64"): "aarch64-pc-windows-msvc",
|
|
("windows", "x86_64"): "x86_64-pc-windows-msvc",
|
|
}
|
|
|
|
|
|
def default_target() -> str:
|
|
system = platform.system().lower()
|
|
machine = normalize_machine(platform.machine())
|
|
target = HOST_RELEASE_TARGETS.get((system, machine))
|
|
if target is None:
|
|
supported = ", ".join(sorted(TARGET_SPECS))
|
|
raise RuntimeError(
|
|
f"Unsupported host platform {platform.system()}/{platform.machine()}. "
|
|
f"Pass --target explicitly. Supported targets: {supported}"
|
|
)
|
|
return target
|
|
|
|
|
|
def resolve_input_path(
|
|
explicit_path: Path | None,
|
|
description: str,
|
|
flag_name: str,
|
|
) -> Path:
|
|
if explicit_path is not None:
|
|
path = explicit_path.resolve()
|
|
if not path.is_file():
|
|
raise RuntimeError(f"{description} does not exist: {path}")
|
|
if not is_executable(path):
|
|
raise RuntimeError(f"{description} is not executable: {path}")
|
|
return path
|
|
|
|
raise RuntimeError(f"Must specify {flag_name} for {description}.")
|
|
|
|
|
|
def is_executable(path: Path) -> bool:
|
|
return bool(path.stat().st_mode & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH))
|
|
|
|
|
|
def normalize_machine(machine: str) -> str:
|
|
machine = machine.lower()
|
|
if machine in ("amd64", "x86_64"):
|
|
return "x86_64"
|
|
if machine in ("aarch64", "arm64"):
|
|
return "aarch64"
|
|
return machine
|