mirror of
https://github.com/openai/codex.git
synced 2026-09-14 11:57:03 +00:00
WIP
This commit is contained in:
@@ -16,13 +16,14 @@ RESPONSES_API_PROXY_NPM_ROOT = REPO_ROOT / "codex-rs" / "responses-api-proxy" /
|
||||
CODEX_SDK_ROOT = REPO_ROOT / "sdk" / "typescript"
|
||||
|
||||
PACKAGE_NATIVE_COMPONENTS: dict[str, list[str]] = {
|
||||
"codex": ["codex", "rg"],
|
||||
"codex": ["codex", "codex-notifier", "rg"],
|
||||
"codex-responses-api-proxy": ["codex-responses-api-proxy"],
|
||||
"codex-sdk": ["codex"],
|
||||
}
|
||||
COMPONENT_DEST_DIR: dict[str, str] = {
|
||||
"codex": "codex",
|
||||
"codex-responses-api-proxy": "codex-responses-api-proxy",
|
||||
"codex-notifier": "codex-notifier",
|
||||
"rg": "path",
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,11 @@ BINARY_TARGETS = (
|
||||
@dataclass(frozen=True)
|
||||
class BinaryComponent:
|
||||
artifact_prefix: str # matches the artifact filename prefix (e.g. codex-<target>.zst)
|
||||
dest_dir: str # directory under vendor/<target>/ where the binary is installed
|
||||
binary_basename: str # executable name inside dest_dir (before optional .exe)
|
||||
dest_dir: str # directory under vendor/<target>/ where the binary/artifact is installed
|
||||
binary_basename: str # executable or directory name inside dest_dir (before optional .exe)
|
||||
archive_format: str = "zst" # one of "zst", "zip", "tar.gz"
|
||||
archive_member: str | None = None # optional archive member to extract
|
||||
supported_targets: tuple[str, ...] | None = None # restrict installation to these targets
|
||||
|
||||
|
||||
BINARY_COMPONENTS = {
|
||||
@@ -49,6 +52,15 @@ BINARY_COMPONENTS = {
|
||||
dest_dir="codex-responses-api-proxy",
|
||||
binary_basename="codex-responses-api-proxy",
|
||||
),
|
||||
"codex-notifier": BinaryComponent(
|
||||
artifact_prefix="codex-notifier",
|
||||
dest_dir="codex-notifier",
|
||||
binary_basename="codex-notifier",
|
||||
supported_targets=(
|
||||
"x86_64-apple-darwin",
|
||||
"aarch64-apple-darwin",
|
||||
),
|
||||
),
|
||||
}
|
||||
|
||||
RG_TARGET_PLATFORM_PAIRS: list[tuple[str, str]] = [
|
||||
@@ -101,7 +113,7 @@ def main() -> int:
|
||||
vendor_dir = codex_cli_root / VENDOR_DIR_NAME
|
||||
vendor_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
components = args.components or ["codex", "rg"]
|
||||
components = args.components or ["codex", "codex-notifier", "rg"]
|
||||
|
||||
workflow_url = (args.workflow_url or DEFAULT_WORKFLOW_URL).strip()
|
||||
if not workflow_url:
|
||||
@@ -218,11 +230,19 @@ def install_binary_components(
|
||||
return
|
||||
|
||||
for component in selected_components:
|
||||
component_targets = [
|
||||
target
|
||||
for target in targets
|
||||
if not component.supported_targets or target in component.supported_targets
|
||||
]
|
||||
if not component_targets:
|
||||
continue
|
||||
|
||||
print(
|
||||
f"Installing {component.binary_basename} binaries for targets: "
|
||||
+ ", ".join(targets)
|
||||
+ ", ".join(component_targets)
|
||||
)
|
||||
max_workers = min(len(targets), max(1, (os.cpu_count() or 1)))
|
||||
max_workers = min(len(component_targets), max(1, (os.cpu_count() or 1)))
|
||||
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||
futures = {
|
||||
executor.submit(
|
||||
@@ -232,7 +252,7 @@ def install_binary_components(
|
||||
target,
|
||||
component,
|
||||
): target
|
||||
for target in targets
|
||||
for target in component_targets
|
||||
}
|
||||
for future in as_completed(futures):
|
||||
installed_path = future.result()
|
||||
@@ -246,7 +266,7 @@ def _install_single_binary(
|
||||
component: BinaryComponent,
|
||||
) -> Path:
|
||||
artifact_subdir = artifacts_dir / target
|
||||
archive_name = _archive_name_for_target(component.artifact_prefix, target)
|
||||
archive_name = _archive_name_for_target(component, target)
|
||||
archive_path = artifact_subdir / archive_name
|
||||
if not archive_path.exists():
|
||||
raise FileNotFoundError(f"Expected artifact not found: {archive_path}")
|
||||
@@ -255,20 +275,29 @@ def _install_single_binary(
|
||||
dest_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
binary_name = (
|
||||
f"{component.binary_basename}.exe" if "windows" in target else component.binary_basename
|
||||
f"{component.binary_basename}.exe"
|
||||
if "windows" in target and component.archive_format == "zst"
|
||||
else component.binary_basename
|
||||
)
|
||||
dest = dest_dir / binary_name
|
||||
dest.unlink(missing_ok=True)
|
||||
extract_archive(archive_path, "zst", None, dest)
|
||||
if "windows" not in target:
|
||||
extract_archive(
|
||||
archive_path, component.archive_format, component.archive_member, dest
|
||||
)
|
||||
if "windows" not in target and dest.is_file():
|
||||
dest.chmod(0o755)
|
||||
return dest
|
||||
|
||||
|
||||
def _archive_name_for_target(artifact_prefix: str, target: str) -> str:
|
||||
def _archive_name_for_target(component: BinaryComponent, target: str) -> str:
|
||||
fmt = component.archive_format
|
||||
if fmt == "zip":
|
||||
return f"{component.artifact_prefix}-{target}.zip"
|
||||
if fmt == "tar.gz":
|
||||
return f"{component.artifact_prefix}-{target}.tar.gz"
|
||||
if "windows" in target:
|
||||
return f"{artifact_prefix}-{target}.exe.zst"
|
||||
return f"{artifact_prefix}-{target}.zst"
|
||||
return f"{component.artifact_prefix}-{target}.exe.zst"
|
||||
return f"{component.artifact_prefix}-{target}.zst"
|
||||
|
||||
|
||||
def _fetch_single_rg(
|
||||
@@ -346,16 +375,25 @@ def extract_archive(
|
||||
return
|
||||
|
||||
if archive_format == "zip":
|
||||
if not archive_member:
|
||||
raise RuntimeError("Missing 'path' for zip archive in DotSlash manifest.")
|
||||
with zipfile.ZipFile(archive_path) as archive:
|
||||
try:
|
||||
with archive.open(archive_member) as src, open(dest, "wb") as out:
|
||||
shutil.copyfileobj(src, out)
|
||||
except KeyError as exc:
|
||||
raise RuntimeError(
|
||||
f"Entry '{archive_member}' not found in archive {archive_path}."
|
||||
) from exc
|
||||
if archive_member:
|
||||
try:
|
||||
with archive.open(archive_member) as src, open(dest, "wb") as out:
|
||||
shutil.copyfileobj(src, out)
|
||||
except KeyError as exc:
|
||||
raise RuntimeError(
|
||||
f"Entry '{archive_member}' not found in archive {archive_path}."
|
||||
) from exc
|
||||
else:
|
||||
with tempfile.TemporaryDirectory() as tmp_dir_str:
|
||||
tmp_dir = Path(tmp_dir_str)
|
||||
archive.extractall(tmp_dir)
|
||||
entries = [p for p in tmp_dir.iterdir() if not p.name.startswith(".__")]
|
||||
if len(entries) != 1:
|
||||
raise RuntimeError(
|
||||
f"Expected a single top-level entry in {archive_path}, found {len(entries)}"
|
||||
)
|
||||
shutil.move(str(entries[0]), dest)
|
||||
return
|
||||
|
||||
raise RuntimeError(f"Unsupported archive format '{archive_format}'.")
|
||||
|
||||
Reference in New Issue
Block a user