Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions .github/workflows/rust-release-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -258,16 +258,12 @@ jobs:

stage_dir="${RUNNER_TEMP}/openai-codex-cli-bin-${{ matrix.target }}"
wheel_dir="${GITHUB_WORKSPACE}/python-runtime-dist/${{ matrix.target }}"
# Keep the helpers next to codex.exe in the runtime wheel so Windows
# sandbox/elevation lookup matches the standalone release zip.
python "${GITHUB_WORKSPACE}/sdk/python/scripts/update_sdk_artifacts.py" \
stage-runtime \
"$stage_dir" \
"${GITHUB_WORKSPACE}/codex-rs/target/${{ matrix.target }}/release/codex.exe" \
"dist/${{ matrix.target }}/codex-package-${{ matrix.target }}.tar.gz" \
--codex-version "${GITHUB_REF_NAME}" \
--platform-tag "$platform_tag" \
--resource-binary "${GITHUB_WORKSPACE}/codex-rs/target/${{ matrix.target }}/release/codex-command-runner.exe" \
--resource-binary "${GITHUB_WORKSPACE}/codex-rs/target/${{ matrix.target }}/release/codex-windows-sandbox-setup.exe"
--platform-tag "$platform_tag"
"${RUNNER_TEMP}/python-runtime-build-venv/Scripts/python.exe" -m build --wheel --outdir "$wheel_dir" "$stage_dir"

- name: Upload Python runtime wheel
Expand Down
40 changes: 16 additions & 24 deletions .github/workflows/rust-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -569,18 +569,10 @@ jobs:
"${GITHUB_WORKSPACE}/sdk/python/scripts/update_sdk_artifacts.py"
stage-runtime
"$stage_dir"
"${GITHUB_WORKSPACE}/codex-rs/target/${{ matrix.target }}/release/codex"
"dist/${{ matrix.target }}/codex-package-${{ matrix.target }}.tar.gz"
--codex-version "${GITHUB_REF_NAME}"
--platform-tag "$platform_tag"
)
if [[ "${{ matrix.target }}" == *linux* ]]; then
# Keep bwrap in the runtime wheel so Linux sandbox fallback behavior
# matches the standalone release bundle on hosts without system bwrap.
stage_runtime_args+=(
--resource-binary
"${GITHUB_WORKSPACE}/codex-rs/target/${{ matrix.target }}/release/bwrap"
)
fi
python3 "${stage_runtime_args[@]}"
"${RUNNER_TEMP}/python-runtime-build-venv/bin/python" -m build --wheel --outdir "$wheel_dir" "$stage_dir"

Expand Down Expand Up @@ -800,6 +792,20 @@ jobs:
cp "$dmg_source" "$dest/$dmg_name"
fi

- name: Build Codex package archive
shell: bash
env:
TARGET: ${{ matrix.target }}
BUNDLE: ${{ matrix.bundle }}
run: |
set -euo pipefail
bash "${GITHUB_WORKSPACE}/.github/scripts/build-codex-package-archive.sh" \
--target "$TARGET" \
--bundle "$BUNDLE" \
--entrypoint-dir "dist/${TARGET}" \
--archive-dir "dist/${TARGET}" \
--target-suffixed-entrypoint

- name: Build Python runtime wheel
if: ${{ matrix.bundle == 'primary' }}
shell: bash
Expand Down Expand Up @@ -828,25 +834,11 @@ jobs:
"${GITHUB_WORKSPACE}/sdk/python/scripts/update_sdk_artifacts.py" \
stage-runtime \
"$stage_dir" \
"${GITHUB_WORKSPACE}/codex-rs/dist/${{ matrix.target }}/codex-${{ matrix.target }}" \
"dist/${{ matrix.target }}/codex-package-${{ matrix.target }}.tar.gz" \
--codex-version "${GITHUB_REF_NAME}" \
--platform-tag "$platform_tag"
"${RUNNER_TEMP}/python-runtime-build-venv/bin/python" -m build --wheel --outdir "$wheel_dir" "$stage_dir"

- name: Build Codex package archive
shell: bash
env:
TARGET: ${{ matrix.target }}
BUNDLE: ${{ matrix.bundle }}
run: |
set -euo pipefail
bash "${GITHUB_WORKSPACE}/.github/scripts/build-codex-package-archive.sh" \
--target "$TARGET" \
--bundle "$BUNDLE" \
--entrypoint-dir "dist/${TARGET}" \
--archive-dir "dist/${TARGET}" \
--target-suffixed-entrypoint

- name: Upload Python runtime wheel
if: ${{ matrix.bundle == 'primary' }}
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
Expand Down
7 changes: 6 additions & 1 deletion sdk/python-runtime/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ exclude = [

[tool.hatch.build.targets.wheel]
packages = ["src/codex_cli_bin"]
include = ["src/codex_cli_bin/bin/**"]
include = [
"src/codex_cli_bin/codex-package.json",
"src/codex_cli_bin/bin/**",
"src/codex_cli_bin/codex-resources/**",
"src/codex_cli_bin/codex-path/**",
]

[tool.hatch.build.targets.wheel.hooks.custom]

Expand Down
27 changes: 23 additions & 4 deletions sdk/python-runtime/src/codex_cli_bin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,38 @@
from __future__ import annotations

import os
from pathlib import Path

PACKAGE_NAME = "openai-codex-cli-bin"
PACKAGE_METADATA_FILENAME = "codex-package.json"


def bundled_package_dir() -> Path:
path = Path(__file__).resolve().parent
metadata_path = path / PACKAGE_METADATA_FILENAME
if not metadata_path.is_file():
raise FileNotFoundError(
f"{PACKAGE_NAME} is installed but missing its package metadata at {metadata_path}"
)
return path


def bundled_codex_path() -> Path:
exe = "codex.exe" if os.name == "nt" else "codex"
path = Path(__file__).resolve().parent / "bin" / exe
path = bundled_package_dir() / "bin" / exe
if not path.is_file():
raise FileNotFoundError(
f"{PACKAGE_NAME} is installed but missing its packaged codex binary at {path}"
)
return path


__all__ = ["PACKAGE_NAME", "bundled_codex_path"]
def bundled_path_dir() -> Path | None:
path = bundled_package_dir() / "codex-path"
return path if path.is_dir() else None


__all__ = [
"PACKAGE_NAME",
"bundled_codex_path",
"bundled_package_dir",
"bundled_path_dir",
]
59 changes: 9 additions & 50 deletions sdk/python/_runtime_setup.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from __future__ import annotations

import importlib
import importlib.metadata
import importlib.util
Expand All @@ -10,11 +8,9 @@
import shutil
import subprocess
import sys
import tarfile
import tempfile
import urllib.error
import urllib.request
import zipfile
from pathlib import Path

PACKAGE_NAME = "openai-codex-cli-bin"
Expand Down Expand Up @@ -65,11 +61,10 @@ def ensure_runtime_package_installed(
with tempfile.TemporaryDirectory(prefix="codex-python-runtime-") as temp_root_str:
temp_root = Path(temp_root_str)
archive_path = _download_release_archive(requested_version, temp_root)
runtime_binary = _extract_runtime_binary(archive_path, temp_root)
staged_runtime_dir = _stage_runtime_package(
sdk_python_dir,
requested_version,
runtime_binary,
archive_path,
temp_root / "runtime-stage",
)
_install_runtime_package(python_executable, staged_runtime_dir, install_target)
Expand Down Expand Up @@ -98,30 +93,26 @@ def platform_asset_name() -> str:

if system == "darwin":
if machine in {"arm64", "aarch64"}:
return "codex-aarch64-apple-darwin.tar.gz"
return "codex-package-aarch64-apple-darwin.tar.gz"
if machine in {"x86_64", "amd64"}:
return "codex-x86_64-apple-darwin.tar.gz"
return "codex-package-x86_64-apple-darwin.tar.gz"
elif system == "linux":
if machine in {"aarch64", "arm64"}:
return "codex-aarch64-unknown-linux-musl.tar.gz"
return "codex-package-aarch64-unknown-linux-musl.tar.gz"
if machine in {"x86_64", "amd64"}:
return "codex-x86_64-unknown-linux-musl.tar.gz"
return "codex-package-x86_64-unknown-linux-musl.tar.gz"
elif system == "windows":
if machine in {"aarch64", "arm64"}:
return "codex-aarch64-pc-windows-msvc.exe.zip"
return "codex-package-aarch64-pc-windows-msvc.tar.gz"
if machine in {"x86_64", "amd64"}:
return "codex-x86_64-pc-windows-msvc.exe.zip"
return "codex-package-x86_64-pc-windows-msvc.tar.gz"

raise RuntimeSetupError(
f"Unsupported runtime artifact platform: system={platform.system()!r}, "
f"machine={platform.machine()!r}"
)


def runtime_binary_name() -> str:
return "codex.exe" if platform.system().lower() == "windows" else "codex"


def _installed_runtime_version(python_executable: str | Path) -> str | None:
snippet = (
"import importlib.metadata, json, sys\n"
Expand Down Expand Up @@ -260,49 +251,17 @@ def _download_release_archive(version: str, temp_root: Path) -> Path:
return archive_path


def _extract_runtime_binary(archive_path: Path, temp_root: Path) -> Path:
extract_dir = temp_root / "extracted"
extract_dir.mkdir(parents=True, exist_ok=True)
if archive_path.name.endswith(".tar.gz"):
with tarfile.open(archive_path, "r:gz") as tar:
try:
tar.extractall(extract_dir, filter="data")
except TypeError:
tar.extractall(extract_dir)
elif archive_path.suffix == ".zip":
with zipfile.ZipFile(archive_path) as zip_file:
zip_file.extractall(extract_dir)
else:
raise RuntimeSetupError(f"Unsupported release archive format: {archive_path.name}")

binary_name = runtime_binary_name()
archive_stem = archive_path.name.removesuffix(".tar.gz").removesuffix(".zip")
candidates = [
path
for path in extract_dir.rglob("*")
if path.is_file()
and (
path.name == binary_name or path.name == archive_stem or path.name.startswith("codex-")
)
]
if not candidates:
raise RuntimeSetupError(
f"Failed to find {binary_name} in extracted runtime archive {archive_path.name}."
)
return candidates[0]


def _stage_runtime_package(
sdk_python_dir: Path,
runtime_version: str,
runtime_binary: Path,
runtime_package_archive: Path,
staging_dir: Path,
) -> Path:
script_module = _load_update_script_module(sdk_python_dir)
return script_module.stage_python_runtime_package( # type: ignore[no-any-return]
staging_dir,
runtime_version,
runtime_binary.resolve(),
runtime_package_archive.resolve(),
)


Expand Down
Loading
Loading