mirror of
https://github.com/openai/codex.git
synced 2026-05-29 23:40:29 +00:00
build: add Codex package builder (#23513)
## Why Codex CLI packaging is currently split across npm staging, standalone installers, and release bundle creation, which makes it hard to define and validate a single valid package directory. This adds the first standalone package builder so later release paths can converge on the same canonical layout. ## What changed - Added `scripts/build_codex_package.py` as the stable executable wrapper around `scripts/codex_package`. - Added modules for CLI parsing, target metadata, grouped cargo builds, package layout validation, and archive writing. - The builder creates a package directory with `codex-package.json`, `bin/`, `codex-resources/`, and `codex-path`, and can serialize it as `.tar.gz`, `.tar.zst`, or `.zip`. - Source-built artifacts are built by one grouped `cargo build`: `codex` for all targets, `bwrap` for Linux, and the Windows sandbox helpers for Windows. `rg` remains an input because it is vendored from upstream rather than built from this repo. - Added `scripts/codex_package/README.md` to document the package layout, source-built artifacts, and cargo profile behavior. ## Verification - Ran wrapper/module syntax compilation. - Ran `scripts/build_codex_package.py --help` from `/private/tmp`. - Ran fake-cargo package/archive builds for macOS, Linux, and Windows target layouts, including an assertion that generated tar archives contain no duplicate member names. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/23513). * #23526 * __->__ #23513
This commit is contained in:
105
scripts/codex_package/cli.py
Normal file
105
scripts/codex_package/cli.py
Normal file
@@ -0,0 +1,105 @@
|
||||
"""Command-line interface for building Codex package directories."""
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from .archive import write_archive
|
||||
from .cargo import build_source_binaries
|
||||
from .layout import build_package_dir
|
||||
from .layout import prepare_package_dir
|
||||
from .layout import validate_package_dir
|
||||
from .targets import TARGET_SPECS
|
||||
from .targets import PackageInputs
|
||||
from .targets import resolve_rg_bin
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Build a canonical Codex package directory and optional archive.",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--target",
|
||||
required=True,
|
||||
choices=sorted(TARGET_SPECS),
|
||||
help="Rust target triple for the package.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--version",
|
||||
default="0.0.0-dev",
|
||||
help="Codex version to record in codex-package.json.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--variant",
|
||||
default="codex",
|
||||
help="Package variant to record in codex-package.json.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--package-dir",
|
||||
type=Path,
|
||||
required=True,
|
||||
help="Output directory to create as the package root.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--archive-output",
|
||||
type=Path,
|
||||
help=(
|
||||
"Optional archive output path. Supported suffixes: .tar.gz, .tgz, "
|
||||
".tar.zst, .zip."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--force",
|
||||
action="store_true",
|
||||
help="Replace an existing package directory or archive output.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cargo",
|
||||
default="cargo",
|
||||
help="Cargo executable to use for source-built package artifacts.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cargo-profile",
|
||||
default="dev-small",
|
||||
help=(
|
||||
"Cargo profile for source-built package artifacts. Use release for "
|
||||
"release packages."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--rg-bin",
|
||||
type=Path,
|
||||
help="Path to the ripgrep executable to place in codex-path/.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
spec = TARGET_SPECS[args.target]
|
||||
package_dir = args.package_dir.resolve()
|
||||
|
||||
source_outputs = build_source_binaries(
|
||||
spec,
|
||||
cargo=args.cargo,
|
||||
profile=args.cargo_profile,
|
||||
)
|
||||
inputs = PackageInputs(
|
||||
codex_bin=source_outputs.codex_bin,
|
||||
rg_bin=resolve_rg_bin(spec, args.rg_bin),
|
||||
bwrap_bin=source_outputs.bwrap_bin,
|
||||
codex_command_runner_bin=source_outputs.codex_command_runner_bin,
|
||||
codex_windows_sandbox_setup_bin=source_outputs.codex_windows_sandbox_setup_bin,
|
||||
)
|
||||
prepare_package_dir(package_dir, force=args.force)
|
||||
build_package_dir(package_dir, args.version, args.variant, spec, inputs)
|
||||
validate_package_dir(package_dir, spec)
|
||||
|
||||
archive_output = args.archive_output
|
||||
if archive_output is not None:
|
||||
archive_path = archive_output.resolve()
|
||||
write_archive(package_dir, archive_path, force=args.force)
|
||||
print(f"Built Codex package archive at {archive_path}")
|
||||
|
||||
print(f"Built Codex package directory at {package_dir}")
|
||||
return 0
|
||||
Reference in New Issue
Block a user