# Copyright 2026 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

EAPI=8

CRATES=""

declare -A GIT_CRATES=(
	[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"
RUSTY_V8_VER="150.4.0"

# Chromium host clang 23 + rust-toolchain (Linux_x64) from rusty_v8 ${RUSTY_V8_VER} DEPS.
CLANG_DIST="clang-llvmorg-23-init-10931-g20b6ec66-11.tar.xz"
RUST_TC_DIST="rust-toolchain-4c4205163abcbd08948b3efab796c543ba1ea687-4-llvmorg-23-init-10931-g20b6ec66.tar.xz"

inherit cargo check-reqs shell-completion toolchain-funcs

CHECKREQS_MEMORY="15G"
CHECKREQS_DISK_BUILD="20G"

DESCRIPTION="OpenAI Codex CLI (from-source rusty_v8)"
HOMEPAGE="https://github.com/openai/codex"
SRC_URI="
	https://github.com/openai/${PN}/archive/refs/tags/rust-v${PV}.tar.gz
		-> ${P}.tar.gz
	https://github.com/0x6d6e647a/mndz-overlay-assets/releases/download/codex-${PV}/${PN}-${PV}-crates.tar.xz
	https://github.com/0x6d6e647a/mndz-overlay-assets/releases/download/rusty-v8-${RUSTY_V8_VER}/rusty-v8-${RUSTY_V8_VER}-with-submodules.tar.xz
	https://commondatastorage.googleapis.com/chromium-browser-clang/Linux_x64/${CLANG_DIST}
	https://commondatastorage.googleapis.com/chromium-browser-clang/Linux_x64/${RUST_TC_DIST}
	${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"
IUSE="bash-completion fish-completion test zsh-completion"
RESTRICT="!test? ( test )"

RDEPEND="
	dev-libs/openssl:=
	sys-apps/bubblewrap
"
BDEPEND="
	dev-build/gn
	dev-build/ninja
	dev-lang/python
	dev-libs/protobuf
	llvm-core/clang:22
	virtual/pkgconfig
"

QA_FLAGS_IGNORED="
	usr/bin/codex
	usr/bin/codex-code-mode-host
"

pkg_pretend() {
	check-reqs_pkg_pretend
}

pkg_setup() {
	check-reqs_pkg_setup
	rust_pkg_setup
}

src_unpack() {
	cargo_src_unpack

	mkdir -p "${WORKDIR}/rusty_v8" || die
	tar -C "${WORKDIR}/rusty_v8" --strip-components=1 \
		-xf "${DISTDIR}/rusty-v8-${RUSTY_V8_VER}-with-submodules.tar.xz" || die

	mkdir -p "${WORKDIR}/chromium-clang" || die
	tar -C "${WORKDIR}/chromium-clang" \
		-xf "${DISTDIR}/${CLANG_DIST}" || die

	# Archive root is VERSION + bin/ + lib/ (Chromium layout). Do not
	# --strip-components=1: that drops VERSION (gn rust.gni reads it) and
	# flattens bin/lib so rustc cannot find librustc_driver.
	mkdir -p "${WORKDIR}/rusty_v8/third_party/rust-toolchain" || die
	tar -C "${WORKDIR}/rusty_v8/third_party/rust-toolchain" \
		-xf "${DISTDIR}/${RUST_TC_DIST}" || die
	[[ -f ${WORKDIR}/rusty_v8/third_party/rust-toolchain/VERSION ]] ||
		die "Chromium rust-toolchain VERSION missing after unpack"
	[[ -x ${WORKDIR}/rusty_v8/third_party/rust-toolchain/bin/rustc ]] ||
		die "Chromium rust-toolchain bin/rustc missing after unpack"
	# rusty_v8 tools/rust_toolchain.py skips GCS if this sentinel equals the
	# exact object URL (no trailing newline).
	printf '%s' \
		"https://storage.googleapis.com/chromium-browser-clang/Linux_x64/${RUST_TC_DIST}" \
		>"${WORKDIR}/rusty_v8/third_party/rust-toolchain/.rusty_v8_version" || die
}

src_prepare() {
	default

	local marker='protoc_bin_vendored::protoc_bin_path'
	local build_rs="${S}/code-mode-protocol/build.rs"
	grep -q "${marker}" "${build_rs}" ||
		die "vendored protoc marker missing from ${build_rs}; update src_prepare"
	# Point tonic at system protoc ($PROTOC or /usr/bin/protoc). Keep the
	# protoc-bin-vendored crates in the lock/tarball so --offline --locked resolves.
	# '#' delimiter: the replacement contains '|_|', which breaks s||| .
	# Match the trailing '?' so a String is not used as Result.
	sed -i \
		-e "s#${marker}()?#std::env::var(\"PROTOC\").unwrap_or_else(|_| \"/usr/bin/protoc\".into())#" \
		"${build_rs}" || die

	# Windows-only microsoft/mxc is omitted from GIT_CRATES, but Cargo still
	# resolves the workspace git pin for appcontainer_common --offline.
	mkdir -p "${WORKDIR}/appcontainer_common_stub/src" || die
	cat > "${WORKDIR}/appcontainer_common_stub/Cargo.toml" <<-EOF || die
		[package]
		name = "appcontainer_common"
		version = "0.8.0"
		edition = "2021"
	EOF
	: > "${WORKDIR}/appcontainer_common_stub/src/lib.rs" || die

	# crates.io v8 is not a from-source tree; path-patch onto the rusty_v8 snapshot.
	# cargo.eclass writes [patch] into CARGO_HOME/config.toml, but Cargo 1.96
	# ignores that and still fetches [patch.crates-io] git= remotes --offline.
	# Rewrite those git pins (and workspace git deps) to unpacked GIT_CRATES paths.
	python3 - "${WORKDIR}" "${S}/Cargo.toml" <<'PY' || die "rewrite Cargo.toml git crates to paths"
import sys
from pathlib import Path

workdir, toml_path = sys.argv[1], Path(sys.argv[2])
text = toml_path.read_text()
subs = [
    (
        'crossterm = { git = "https://github.com/openai-oss-forks/crossterm", rev = "45fecb9508105988f42fe6ff0441783ed3717f92" }',
        f'crossterm = {{ path = "{workdir}/crossterm-45fecb9508105988f42fe6ff0441783ed3717f92" }}',
    ),
    (
        'tokio-tungstenite = { git = "https://github.com/openai-oss-forks/tokio-tungstenite", rev = "0e5b2d73aa18dd9f0a50ee9ff199d5aef7594186" }',
        f'tokio-tungstenite = {{ path = "{workdir}/tokio-tungstenite-0e5b2d73aa18dd9f0a50ee9ff199d5aef7594186" }}',
    ),
    (
        'tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev = "4fffad30fe373adbdcffab9545e9e9bf4f2fc19f" }',
        f'tungstenite = {{ path = "{workdir}/tungstenite-rs-4fffad30fe373adbdcffab9545e9e9bf4f2fc19f" }}',
    ),
    (
        'nucleo = { git = "https://github.com/helix-editor/nucleo.git", rev = "4253de9faabb4e5c6d81d946a5e35a90f87347ee" }',
        f'nucleo = {{ path = "{workdir}/nucleo-4253de9faabb4e5c6d81d946a5e35a90f87347ee" }}',
    ),
    (
        'runfiles = { git = "https://github.com/dzbarsky/rules_rust", rev = "b56cbaa8465e74127f1ea216f813cd377295ad81" }',
        f'runfiles = {{ path = "{workdir}/rules_rust-b56cbaa8465e74127f1ea216f813cd377295ad81/rust/runfiles" }}',
    ),
    (
        'appcontainer_common = { git = "https://github.com/microsoft/mxc", rev = "6cd3d58f05d3447e67109cfb75e042803b843ca4" }',
        f'appcontainer_common = {{ path = "{workdir}/appcontainer_common_stub" }}',
    ),
]
for old, new in subs:
    if old not in text:
        sys.exit(f"expected git crate snippet missing from Cargo.toml: {old}")
    text = text.replace(old, new)
needle = "[patch.crates-io]\n"
if needle not in text:
    sys.exit("Cargo.toml missing [patch.crates-io]")
text = text.replace(
    needle,
    needle + f'v8 = {{ path = "{workdir}/rusty_v8" }}\n',
    1,
)
toml_path.write_text(text)
PY
	local git_toml
	for git_toml in \
		"${WORKDIR}/crossterm-45fecb9508105988f42fe6ff0441783ed3717f92/Cargo.toml" \
		"${WORKDIR}/tokio-tungstenite-0e5b2d73aa18dd9f0a50ee9ff199d5aef7594186/Cargo.toml" \
		"${WORKDIR}/tungstenite-rs-4fffad30fe373adbdcffab9545e9e9bf4f2fc19f/Cargo.toml" \
		"${WORKDIR}/nucleo-4253de9faabb4e5c6d81d946a5e35a90f87347ee/Cargo.toml" \
		"${WORKDIR}/nucleo-4253de9faabb4e5c6d81d946a5e35a90f87347ee/matcher/Cargo.toml" \
		"${WORKDIR}/rules_rust-b56cbaa8465e74127f1ea216f813cd377295ad81/rust/runfiles/Cargo.toml" \
		"${WORKDIR}/rusty_v8/Cargo.toml"
	do
		[[ -f ${git_toml} ]] || die "unpacked git crate missing ${git_toml}"
	done
}

src_compile() {
	export V8_FROM_SOURCE=1
	# rusty_v8 gn uses this tree; do not export it as CC/CXX — cc-rs (ring)
	# would then compile with Chromium clang, which rejects Portage CFLAGS
	# such as -mabm.
	export CLANG_BASE_PATH="${WORKDIR}/chromium-clang"
	# Chromium clang has no 64-bit libclang.so; Gentoo clang:22 lib64 does.
	export LIBCLANG_PATH="/usr/lib/llvm/22/$(get_libdir)"
	export RUST_MIN_STACK=16777216

	cargo_src_compile --bin codex --bin codex-code-mode-host
}

src_test() {
	export V8_FROM_SOURCE=1
	export RUST_MIN_STACK=16777216
	# Skip network, sandbox, and known-failing crates under Portage FEATURES=test.
	# Remaining workspace members run via cargo.eclass.
	local CARGO_SKIP_TESTS=(
		# network
		codex-login
		# sandbox / bubblewrap host assumptions
		codex-linux-sandbox
	)
	export CARGO_SKIP_TESTS
	cargo_src_test
}

src_install() {
	dobin "$(cargo_target_dir)/codex"
	dobin "$(cargo_target_dir)/codex-code-mode-host"

	local cdir
	cdir="$(cargo_target_dir)"
	if use bash-completion; then
		"${cdir}/codex" completion bash > codex.bash || die
		newbashcomp codex.bash codex
	fi
	if use zsh-completion; then
		"${cdir}/codex" completion zsh > codex.zsh || die
		newzshcomp codex.zsh _codex
	fi
	if use fish-completion; then
		"${cdir}/codex" completion fish > codex.fish || die
		newfishcomp codex.fish codex.fish
	fi
}