# Copyright 1999-2026 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 EAPI=8 # NOTE: This package uses a pre-built crate tarball instead of listing individual # crates in CRATES="". This approach is required because: # 1. Codex has 800+ crate dependencies, which triggers Portage QA warnings: # "QA Notice: This package uses a very large number of CRATES. Please provide # a crate tarball instead and fetch it via SRC_URI." # 2. Stricter ebuild QA checks (e.g., in CI pipelines) fail with too many crates. # # The crate tarball is auto-generated by GitHub Actions at: # https://github.com/gentoo-zh-drafts/codex/ # Workflow source code for auditing: # https://github.com/gentoo-zh-drafts/codex/blob/crate-dist/.github/workflows/crates.yml # This allows anyone to review and verify the crate packaging process. CRATES=" " # Mirrors every "source = git+..." entry in codex-rs/Cargo.lock. Diff this block # against that file on every bump; an entry the lock no longer references only # costs a pointless fetch, but a stale rev is silent here. src_prepare rewrites # [patch.crates-io] as "path = ", and a path carries no revision, # so cargo never reports "can't checkout #" -- it just compiles the # previous release's source. That surfaces much later as unrelated-looking # errors in a consumer crate: 0.148.0 with the 0.147.0 crossterm failed with # E0425/E0433 in codex-tui for discard_buffered_input, buffer_input and # InputDiscardStatus, all added by the fork after f69a4a04. # Upstream moved crossterm from nornagon to openai-oss-forks in 0.147.0 and # dropped its ratatui fork back to crates.io. # # microsoft/mxc is one git repository holding eight workspace members, so it # gets eight entries pointing at the same commit. That is not redundancy: the # eclass emits one " = { path = ... }" line per key under a single # [patch.''] block, and a member with no key is left resolving to the git # source, which dies under --offline exactly like the un-patched one did. # SRC_URI and DISTDIR see the same tarball eight times and deduplicate it, the # way nucleo/nucleo-matcher already do below. # # Every one of them is dead code here -- codex-sandboxing declares # appcontainer_common under [target.'cfg(windows)'.dependencies], and KEYWORDS # is Linux-only. They are vendored anyway because cargo resolves the whole # dependency graph before it ever looks at the target, so a Windows-gated git # dependency still has to be fetchable. Deleting them from Cargo.toml instead # would work and would be a divergence from upstream's lock to re-apply, and # re-verify, on every bump; at 6 MB the tarball is the cheaper contract. declare -A GIT_CRATES=( [appcontainer_common]='https://github.com/microsoft/mxc;6cd3d58f05d3447e67109cfb75e042803b843ca4;mxc-%commit%/src/backends/appcontainer/common' [learning_mode_core]='https://github.com/microsoft/mxc;6cd3d58f05d3447e67109cfb75e042803b843ca4;mxc-%commit%/src/core/learning_mode_core' [learning_mode_windows]='https://github.com/microsoft/mxc;6cd3d58f05d3447e67109cfb75e042803b843ca4;mxc-%commit%/src/backends/learning_mode/windows' [mxc_config_contract]='https://github.com/microsoft/mxc;6cd3d58f05d3447e67109cfb75e042803b843ca4;mxc-%commit%/src/core/mxc_config_contract' [mxc_telemetry]='https://github.com/microsoft/mxc;6cd3d58f05d3447e67109cfb75e042803b843ca4;mxc-%commit%/src/mxc_telemetry' [process_security_environment_spec]='https://github.com/microsoft/mxc;6cd3d58f05d3447e67109cfb75e042803b843ca4;mxc-%commit%/src/core/generated/process_security_environment_specification' [sandbox_spec]='https://github.com/microsoft/mxc;6cd3d58f05d3447e67109cfb75e042803b843ca4;mxc-%commit%/src/core/generated/base_container_specification' [wxc_common]='https://github.com/microsoft/mxc;6cd3d58f05d3447e67109cfb75e042803b843ca4;mxc-%commit%/src/core/wxc_common' [crossterm]='https://github.com/openai-oss-forks/crossterm;45fecb9508105988f42fe6ff0441783ed3717f92;crossterm-%commit%' [nucleo-matcher]='https://github.com/helix-editor/nucleo;4253de9faabb4e5c6d81d946a5e35a90f87347ee;nucleo-%commit%/matcher' [nucleo]='https://github.com/helix-editor/nucleo;4253de9faabb4e5c6d81d946a5e35a90f87347ee;nucleo-%commit%' [runfiles]='https://github.com/dzbarsky/rules_rust;b56cbaa8465e74127f1ea216f813cd377295ad81;rules_rust-%commit%/rust/runfiles' [tokio-tungstenite]='https://github.com/openai-oss-forks/tokio-tungstenite;0e5b2d73aa18dd9f0a50ee9ff199d5aef7594186;tokio-tungstenite-%commit%' [tungstenite]='https://github.com/openai-oss-forks/tungstenite-rs;4fffad30fe373adbdcffab9545e9e9bf4f2fc19f;tungstenite-rs-%commit%' ) RUST_MIN_VER="1.95.0" # Tag of the crate tarball published by the crate-dist fork # (gentoo-zh-drafts/codex). It is derived from PV rather than written out, # because the failure mode of the two choices is not symmetric. Deriving it and # guessing wrong means the fetch 404s -- loud, before a single crate compiles. # Writing it out and forgetting to raise it vendors the PREVIOUS release's # crates, and cargo then dies deep in the build on whichever dependency moved # ("failed to select a version for the requirement"), reading like an upstream # bug rather than a stale pin. # # That is not hypothetical: it stayed at a literal rust-v0.150.0 across the # 0.151, 0.152 and 0.153 bumps, and that vendor directory is missing six crates # the 0.153.0 lock needs -- cidr, flatbuffers, tracelogging, tracelogging_macros, # unicode-general-category, winreg. # # Replace it with a literal ONLY when the fork published no tarball for this # release AND the two codex-rs/Cargo.lock files are byte-identical; say which # tag and why, as the 0.150.1 case did (both locks hashed # beb9a924bf01f03ecfa9fedbf50a602cbaa5399df5cbe57e2d6bd40529e055a6). MY_CRATES_TAG="rust-v${PV}" # Version of the prebuilt V8 static library, which MUST equal the version of # the "v8" crate the lock resolves -- the archive ships its own FFI bindings # (RUSTY_V8_SRC_BINDING_PATH), so a mismatched pair compiles against one ABI # and links against another. Upstream documents this as # ".github/scripts/rusty_v8_bazel.py resolved-v8-crate-version", but that # script is not runnable outside their Bazel checkout (it imports # run_bazel_with_buildbuddy). Read it off the lock instead: # # awk '/^name = "v8"$/{f=1} f&&/^version = /{print $3; exit}' codex-rs/Cargo.lock # # It was stale at 147.4.0 while the lock had already moved to 150.4.0. RUSTY_V8_TAG="150.4.0" inherit cargo DESCRIPTION="Codex CLI - OpenAI's AI-powered coding agent" HOMEPAGE="https://github.com/openai/codex" # The crate tarball URL uses ${PV} so it auto-updates when bumping versions. # This tarball is generated by: https://github.com/gentoo-zh-drafts/codex/ # See .github/workflows/crates.yml for the generation process. SRC_URI=" https://github.com/openai/${PN}/archive/rust-v${PV}.tar.gz -> ${P}.tar.gz https://github.com/gentoo-zh-drafts/codex/releases/download/${MY_CRATES_TAG}/codex-${MY_CRATES_TAG}-crates.tar.xz amd64? ( https://github.com/openai/codex/releases/download/rusty-v8-v${RUSTY_V8_TAG}/librusty_v8_release_x86_64-unknown-linux-musl.a.gz -> rusty_v8_${RUSTY_V8_TAG}_librusty_v8_release_x86_64-unknown-linux-musl.a.gz https://github.com/openai/codex/releases/download/rusty-v8-v${RUSTY_V8_TAG}/src_binding_release_x86_64-unknown-linux-musl.rs -> rusty_v8_${RUSTY_V8_TAG}_src_binding_release_x86_64-unknown-linux-musl.rs ) arm64? ( https://github.com/openai/codex/releases/download/rusty-v8-v${RUSTY_V8_TAG}/librusty_v8_release_aarch64-unknown-linux-musl.a.gz -> rusty_v8_${RUSTY_V8_TAG}_librusty_v8_release_aarch64-unknown-linux-musl.a.gz https://github.com/openai/codex/releases/download/rusty-v8-v${RUSTY_V8_TAG}/src_binding_release_aarch64-unknown-linux-musl.rs -> rusty_v8_${RUSTY_V8_TAG}_src_binding_release_aarch64-unknown-linux-musl.rs ) ${CARGO_CRATE_URIS} " S="${WORKDIR}/${PN}-rust-v${PV}/codex-rs" LICENSE="Apache-2.0" # Dependent crate licenses LICENSE+=" Apache-2.0 Apache-2.0-with-LLVM-exceptions BSD-2 BSD Boost-1.0 CC0-1.0 CDLA-Permissive-2.0 ISC MIT MPL-2.0 Unicode-3.0 ZLIB " SLOT="0" KEYWORDS="-* ~amd64 ~arm64" # Tests fail due to ring crate conflicts with system OpenSSL RESTRICT="test" DEPEND=" dev-libs/openssl:= sys-apps/dbus " RDEPEND="${DEPEND}" BDEPEND="virtual/pkgconfig" # rust does not use *FLAGS from make.conf, silence portage warning QA_FLAGS_IGNORED="usr/bin/${PN}" gen_git_crate_dir() { # https://github.com/gentoo/gentoo/blob/b09dd88412fe2d5eee5a8891e08bfa2d67848da3/eclass/cargo.eclass#L442 IFS=';' read -r crate_uri commit crate_dir <<<"${GIT_CRATES[$1]}" echo "${WORKDIR}/${crate_dir//%commit%/${commit}}" } src_prepare() { default # Fix tokio-tungstenite's git dependency on tungstenite sed -i '/^\[dependencies\.tungstenite\]/,/^$/{ s|git = "https://github.com/openai-oss-forks/tungstenite-rs"|path = "'"$(gen_git_crate_dir tungstenite)"'"| /^rev = /d }' "$(gen_git_crate_dir tokio-tungstenite)/Cargo.toml" || die # Remove the [patch.crates-io] section and add path-based patches sed -i '/^\[patch\.crates-io\]/,/^$/d' "${S}/Cargo.toml" || die sed -i '/^\[patch\."ssh:\/\/git@github\.com/,/^$/d' "${S}/Cargo.toml" || die # Add new patch section with local paths cat >> "${S}/Cargo.toml" <<-EOF || die [patch.crates-io] crossterm = { path = "$(gen_git_crate_dir crossterm)" } tokio-tungstenite = { path = "$(gen_git_crate_dir tokio-tungstenite)" } tungstenite = { path = "$(gen_git_crate_dir tungstenite)" } EOF } src_compile() { local rusty_v8_triple use amd64 && rusty_v8_triple=x86_64-unknown-linux-musl use arm64 && rusty_v8_triple=aarch64-unknown-linux-musl RUSTY_V8_ARCHIVE="${DISTDIR}/rusty_v8_${RUSTY_V8_TAG}_librusty_v8_release_${rusty_v8_triple}.a.gz" \ RUSTY_V8_SRC_BINDING_PATH="${DISTDIR}/rusty_v8_${RUSTY_V8_TAG}_src_binding_release_${rusty_v8_triple}.rs" \ cargo_src_compile --package codex-cli } src_install() { dobin "$(cargo_target_dir)/codex" einstalldocs }