Files
Genarrative/scripts/ci-rust-cache.sh
T
lhk229 48eb3d5007
Project CI / AI game creator shell Rust crates (push) Successful in 2m22s
Project CI / AI game creator shell Rust smoke (push) Successful in 3m13s
Project CI / AI game creator shell Rust lane 2/2 (push) Successful in 8m28s
Project CI / AI game creator shell Rust lane 1/2 (push) Successful in 8m58s
Project CI / Backend tests (push) Successful in 7m16s
Project CI / Native shell tests (push) Successful in 8m10s
Project CI / Frontend tests (push) Successful in 3m49s
Project CI / Repository checks (push) Successful in 4m8s
Project CI / AI game creator shell web tests (push) Successful in 4m1s
Opt/ci (#456)
Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/456
Co-authored-by: Linghong <ink29535@proton.me>
Co-committed-by: Linghong <ink29535@proton.me>
2026-09-22 12:42:27 +08:00

87 lines
4.0 KiB
Bash

#!/usr/bin/env bash
# 仅消费镜像内的可信快照;所有写入留在当前容器的可写层。
set -euo pipefail
cache_root="${GENARRATIVE_CI_RUST_CACHE_ROOT:-/opt/genarrative-ci/rust-cache}"
cache_binary="${cache_root}/sccache"
state="${GENARRATIVE_CI_RUST_CACHE_STATE:-}"
configure_local_cache() {
# 不继承开发机/其它流水线的 OSS、S3、GHA 或 daemon 配置。
local variable
for variable in ${!SCCACHE_@}; do unset "${variable}"; done
export SCCACHE_CONF="${state}/config"
export SCCACHE_DIR="${cache_root}/objects"
export SCCACHE_CACHE_SIZE=2G
export SCCACHE_SERVER_UDS="${state}/server.sock"
# 单个不可缓存的链接/测试阶段可能超过一分钟;保持统计直到 report 显式停止。
export SCCACHE_IDLE_TIMEOUT=0
export SCCACHE_IGNORE_SERVER_IO_ERROR=1
}
case "${1:-}" in
prepare)
: "${GITHUB_ENV:?GITHUB_ENV is required}"
printf 'RUSTC_WRAPPER=\nCARGO_BUILD_RUSTC_WRAPPER=\nGENARRATIVE_CI_RUST_CACHE_STATE=\n' >> "${GITHUB_ENV}"
fallback() { printf '[rust-cache] mode=direct reason=%s\n' "$1"; exit 0; }
[[ -x "${cache_binary}" && -d "${cache_root}/objects" && -f "${cache_root}/rustc.txt" && -f "${cache_root}/source-commit.txt" && -f "${cache_root}/workspace.txt" ]] \
|| fallback snapshot-unavailable
if ! rustc -vV | cmp -s - "${cache_root}/rustc.txt"; then
fallback toolchain-mismatch
fi
if [[ "$(pwd -P)" != "$(cat "${cache_root}/workspace.txt")" ]]; then
fallback workspace-mismatch
fi
# 使用短 Unix socket 路径,避免共享固定端口或超出 sockaddr_un 长度。
state="$(mktemp -d /tmp/ci-rust-cache.XXXXXX)"
printf 'server_startup_timeout_ms = 5000\n' > "${state}/config"
configure_local_cache
# 探测必须暴露 daemon 故障;只有正式编译允许 sccache 的 IO 回退。
unset SCCACHE_IGNORE_SERVER_IO_ERROR
if ! timeout --kill-after=2 15 "${cache_binary}" "$(command -v rustc)" -vV > "${state}/probe.log" 2>&1; then
timeout --kill-after=2 5 "${cache_binary}" --stop-server >/dev/null 2>&1 || true
rm -rf -- "${state}"
fallback wrapper-probe-failed
fi
script_path="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)/$(basename "${BASH_SOURCE[0]}")"
# wrapper 路径也参与 Rust cache key;固定容器内路径,隔离由 job 容器保证。
wrapper_path="${cache_root}/rustc-wrapper"
printf '#!/usr/bin/env bash\nexec bash %q "$@"\n' "${script_path}" > "${wrapper_path}"
chmod 700 "${wrapper_path}"
{
printf 'GENARRATIVE_CI_RUST_CACHE_ROOT=%s\n' "${cache_root}"
printf 'GENARRATIVE_CI_RUST_CACHE_STATE=%s\n' "${state}"
printf 'RUSTC_WRAPPER=%s\nCARGO_BUILD_RUSTC_WRAPPER=%s\n' "${wrapper_path}" "${wrapper_path}"
} >> "${GITHUB_ENV}"
printf '[rust-cache] mode=sccache snapshot=%s\n' "$(cat "${cache_root}/source-commit.txt")"
;;
report)
if [[ -n "${state}" && -d "${state}" ]]; then
configure_local_cache
timeout --kill-after=2 5 "${cache_binary}" --show-stats || true
timeout --kill-after=2 5 "${cache_binary}" --stop-server >/dev/null 2>&1 || true
rm -rf -- "${state}"
else
printf '[rust-cache] mode=direct\n'
fi
;;
*)
# Cargo wrapper 协议:第一个参数是真实 rustc。失去缓存状态时仍执行原编译。
if [[ -z "${state}" || ! -f "${state}/config" || -f "${state}/disabled" || ! -x "${cache_binary}" ]]; then
exec "$@"
fi
configure_local_cache
status=0
"${cache_binary}" "$@" || status=$?
if [[ "${status}" == 2 ]]; then
# 固定 sccache 版本的自身错误码为 2;实际 rustc 失败通常为 1/101。
# 只重试这次编译,不重跑 Cargo 或测试,真实编译错误仍按 rustc 状态返回。
echo '[rust-cache] cache infrastructure failed; compiling directly' >&2
# 后续 crate 直接编译,避免坏 daemon 让每个 crate 都支付一次启动超时。
: > "${state}/disabled"
exec "$@"
fi
exit "${status}"
;;
esac