diff --git a/scripts/codex_package/cli.py b/scripts/codex_package/cli.py index fa569e9ae7..de081fe148 100644 --- a/scripts/codex_package/cli.py +++ b/scripts/codex_package/cli.py @@ -45,6 +45,10 @@ def parse_package_version(value: str) -> str: def parse_args() -> argparse.Namespace: + return create_parser().parse_args() + + +def create_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( description="Build a canonical Codex package directory and optional archive.", formatter_class=argparse.ArgumentDefaultsHelpFormatter, @@ -169,11 +173,18 @@ def parse_args() -> argparse.Namespace: "scripts/codex_package/rg." ), ) - return parser.parse_args() + return parser def main() -> int: args = parse_args() + package_dir = assemble_package(args) + archive_package(package_dir, args) + return 0 + + +def assemble_package(args: argparse.Namespace) -> Path: + """Build the directory before optional downstream additions and archiving.""" spec = TARGET_SPECS[getattr(args, "target", None) or default_target()] variant = PACKAGE_VARIANTS[args.variant] package_dir_arg = getattr(args, "package_dir", None) @@ -228,14 +239,16 @@ def main() -> int: validate_package_dir( package_dir, variant, spec, include_zsh=inputs.zsh_bin is not None ) + return package_dir + +def archive_package(package_dir: Path, args: argparse.Namespace) -> None: for archive_output in args.archive_output: 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 def resolve_optional_input_path( diff --git a/scripts/codex_package/dotslash.py b/scripts/codex_package/dotslash.py index 9252ae29f1..ba0adbe244 100644 --- a/scripts/codex_package/dotslash.py +++ b/scripts/codex_package/dotslash.py @@ -1,5 +1,6 @@ """Fetch executable artifacts from checked-in DotSlash manifests.""" +import gzip import hashlib import json import shutil @@ -184,6 +185,11 @@ def extract_archive_member( dest.parent.mkdir(parents=True, exist_ok=True) dest.unlink(missing_ok=True) + if artifact.archive_format == "gz": + with gzip.open(archive_path, "rb") as extracted, open(dest, "wb") as out: + shutil.copyfileobj(extracted, out) + return + if artifact.archive_format == "tar.gz": with tarfile.open(archive_path, "r:gz") as archive: try: @@ -218,5 +224,5 @@ def extract_archive_member( raise RuntimeError( f"Unsupported {artifact_label} archive format {artifact.archive_format!r}; " - "expected tar.gz or zip" + "expected gz, tar.gz or zip" ) diff --git a/scripts/codex_package/test_zsh.py b/scripts/codex_package/test_zsh.py index 86d3c9fea8..20fa5dcd90 100644 --- a/scripts/codex_package/test_zsh.py +++ b/scripts/codex_package/test_zsh.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +import gzip import hashlib import json from pathlib import Path @@ -31,46 +32,51 @@ class ResolveZshBinTest(unittest.TestCase): fetch.assert_not_called() def test_uses_manifest_override(self) -> None: - with tempfile.TemporaryDirectory() as temp_dir: - root = Path(temp_dir) - archive = root / "codex-zsh.tar.gz" - source = root / "zsh" - source.write_bytes(b"standalone zsh") - with tarfile.open(archive, "w:gz") as tar: - tar.add(source, arcname="codex-zsh/bin/zsh") + for archive_format in ("tar.gz", "gz"): + with self.subTest(archive_format=archive_format): + with tempfile.TemporaryDirectory() as temp_dir: + root = Path(temp_dir) + archive = root / f"codex-zsh.{archive_format}" + source = root / "zsh" + source.write_bytes(b"standalone zsh") + if archive_format == "gz": + archive.write_bytes(gzip.compress(source.read_bytes())) + else: + with tarfile.open(archive, "w:gz") as tar: + tar.add(source, arcname="codex-zsh/bin/zsh") - manifest = root / "codex-zsh" - manifest.write_text( - json.dumps( - { - "platforms": { - "linux-x86_64": { - "size": archive.stat().st_size, - "hash": "sha256", - "digest": hashlib.sha256( - archive.read_bytes() - ).hexdigest(), - "format": "tar.gz", - "path": "codex-zsh/bin/zsh", - "providers": [{"url": archive.as_uri()}], + manifest = root / "codex-zsh" + manifest.write_text( + json.dumps( + { + "platforms": { + "linux-x86_64": { + "size": archive.stat().st_size, + "hash": "sha256", + "digest": hashlib.sha256( + archive.read_bytes() + ).hexdigest(), + "format": archive_format, + "path": "codex-zsh/bin/zsh", + "providers": [{"url": archive.as_uri()}], + } + } } - } - } - ), - encoding="utf-8", - ) + ), + encoding="utf-8", + ) - with patch( - "codex_package.dotslash.default_cache_root", - return_value=root / "cache", - ): - zsh_bin = resolve_zsh_bin( - TARGET_SPECS["x86_64-unknown-linux-musl"], manifest - ) + with patch( + "codex_package.dotslash.default_cache_root", + return_value=root / "cache", + ): + zsh_bin = resolve_zsh_bin( + TARGET_SPECS["x86_64-unknown-linux-musl"], manifest + ) - self.assertIsNotNone(zsh_bin) - assert zsh_bin is not None - self.assertEqual(zsh_bin.read_bytes(), b"standalone zsh") + self.assertIsNotNone(zsh_bin) + assert zsh_bin is not None + self.assertEqual(zsh_bin.read_bytes(), b"standalone zsh") if __name__ == "__main__":