chore(dev): isolate worktree builds and wire nextest into dev-test
scripts/dev-test.sh only mapped an area onto cargo test -p; a new
worktree still compiled into a private cold ./target. Add
scripts/dev-cache.sh and scripts/dev-cargo.sh so the measured isolated
build-dir topology is actually applied.
New worktrees get CARGO_BUILD_BUILD_DIR under
${CODEWHALE_CACHE_ROOT:-${XDG_CACHE_HOME:-$HOME/.cache}/codewhale}
with Cargo's {workspace-path-hash} (passed as --config so the
template expands). sccache wraps rustc only when incremental is
already off; a missing binary is a printed fallback, not an error.
Cargo older than 1.91 falls back to a per-workspace CARGO_TARGET_DIR.
Already-set CARGO_TARGET_DIR / CARGO_BUILD_BUILD_DIR / RUSTC_WRAPPER
are left alone. Defaults contain no machine-local path.
dev-test.sh now routes every workspace crate, prefers cargo-nextest
when installed (CODEWHALE_DEV_NEXTEST=0 forces libtest), and exports
RUST_MIN_STACK=16MiB when unset. nextest retries stay 0. Hermetic
checks: scripts/dev-cache.test.sh (22) and scripts/dev-test.test.sh
(27), passing under both /bin/sh and dash.
This commit is contained in:
@@ -19,6 +19,8 @@ slow-timeout = { period = "30s" }
|
||||
retries = 0
|
||||
fail-fast = false
|
||||
final-status-level = "slow"
|
||||
# RUST_MIN_STACK is not a nextest.toml key. CI and scripts/dev-test.sh
|
||||
# export 16 MiB so local nextest matches the product thread stack.
|
||||
|
||||
[test-groups]
|
||||
pty = { max-threads = 1 }
|
||||
|
||||
Executable
+437
@@ -0,0 +1,437 @@
|
||||
#!/bin/sh
|
||||
# Portable opt-in Cargo cache topology for Codewhale worktrees.
|
||||
#
|
||||
# Isolated per-workspace intermediates (Cargo build-dir + {workspace-path-hash})
|
||||
# plus optional shared sccache. Never hard-codes a machine path. Does not
|
||||
# change product behavior. This file is safe to source from other /bin/sh
|
||||
# helpers; the CLI path is the only one that calls `set -eu` and `exit`.
|
||||
#
|
||||
# Usage:
|
||||
# . scripts/dev-cache.sh && codewhale_dev_cache_apply
|
||||
# scripts/dev-cache.sh --status
|
||||
# scripts/dev-cache.sh --self-check
|
||||
# scripts/dev-cache.sh --print-exports
|
||||
# scripts/dev-cache.sh --help
|
||||
#
|
||||
# Environment:
|
||||
# CODEWHALE_CACHE_ROOT cache root (default:
|
||||
# ${XDG_CACHE_HOME:-$HOME/.cache}/codewhale)
|
||||
# CODEWHALE_DEV_CACHE auto|1|force|0 (default auto)
|
||||
# auto = isolated build-dir only when ./target
|
||||
# is absent (new worktree)
|
||||
# 1/force = always isolated (still respects an
|
||||
# already-set CARGO_TARGET_DIR /
|
||||
# CARGO_BUILD_BUILD_DIR)
|
||||
# 0 = do nothing
|
||||
# CODEWHALE_SCCACHE auto|1|0 (default auto)
|
||||
# auto = wrap rustc only when incremental is
|
||||
# already off and sccache is on PATH
|
||||
# 1 = request CARGO_INCREMENTAL=0 (unless
|
||||
# the caller already set it to on) and
|
||||
# wrap if sccache exists
|
||||
# 0 = never wrap
|
||||
# CODEWHALE_DEV_CACHE_QUIET 1 to suppress the one-line status
|
||||
# CODEWHALE_DEV_CACHE_REPO_ROOT
|
||||
# workspace root used for ./target detection
|
||||
# (default: $PWD)
|
||||
# CODEWHALE_RUSTC_COMMIT override the rustc commit used to namespace
|
||||
# SCCACHE_DIR (tests / offline hosts)
|
||||
#
|
||||
# sccache cannot cache incremental units. This helper never enables the
|
||||
# wrapper while CARGO_INCREMENTAL is on, and it never turns incremental off
|
||||
# unless CODEWHALE_SCCACHE=1. Everyday edits stay on cargo's incremental
|
||||
# default. New-worktree / CI-like rebuilds that already set
|
||||
# CARGO_INCREMENTAL=0 get the measured shared-compiler-output path.
|
||||
|
||||
codewhale_dev_cache_truthy() {
|
||||
case ${1:-} in
|
||||
1|true|yes|on|force) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
codewhale_dev_cache_falsey() {
|
||||
case ${1:-} in
|
||||
0|false|no|off|never|disabled) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
codewhale_dev_cache_root() {
|
||||
if [ -n "${CODEWHALE_CACHE_ROOT:-}" ]; then
|
||||
printf '%s\n' "$CODEWHALE_CACHE_ROOT"
|
||||
return
|
||||
fi
|
||||
if [ -n "${XDG_CACHE_HOME:-}" ]; then
|
||||
printf '%s\n' "$XDG_CACHE_HOME/codewhale"
|
||||
return
|
||||
fi
|
||||
if [ -n "${HOME:-}" ]; then
|
||||
printf '%s\n' "$HOME/.cache/codewhale"
|
||||
return
|
||||
fi
|
||||
printf '%s\n' "${TMPDIR:-/tmp}/codewhale-cache"
|
||||
}
|
||||
|
||||
codewhale_dev_cache_repo_root() {
|
||||
if [ -n "${CODEWHALE_DEV_CACHE_REPO_ROOT:-}" ]; then
|
||||
printf '%s\n' "$CODEWHALE_DEV_CACHE_REPO_ROOT"
|
||||
return
|
||||
fi
|
||||
pwd
|
||||
}
|
||||
|
||||
codewhale_dev_cache_rustc_commit() {
|
||||
if [ -n "${CODEWHALE_RUSTC_COMMIT:-}" ]; then
|
||||
printf '%s\n' "$CODEWHALE_RUSTC_COMMIT"
|
||||
return
|
||||
fi
|
||||
# rustc -vV is cheap and does not start a compile.
|
||||
_cw_out=$(rustc -vV 2>/dev/null || true)
|
||||
_cw_commit=$(printf '%s\n' "$_cw_out" | awk '/^commit-hash:/{print $2; exit}')
|
||||
if [ -n "$_cw_commit" ]; then
|
||||
printf '%s\n' "$_cw_commit"
|
||||
else
|
||||
printf '%s\n' "unknown"
|
||||
fi
|
||||
}
|
||||
|
||||
codewhale_dev_cache_cargo_version_mm() {
|
||||
# cargo 1.97.0 -> 1097. Empty if cargo is missing or unparsable.
|
||||
cargo --version 2>/dev/null | awk '{
|
||||
split($2, a, ".")
|
||||
if (a[1] ~ /^[0-9]+$/ && a[2] ~ /^[0-9]+$/)
|
||||
printf "%d\n", a[1]*1000+a[2]
|
||||
}'
|
||||
}
|
||||
|
||||
# Stable 16-hex-char fingerprint of a path. Used only for the pre-1.91
|
||||
# CARGO_TARGET_DIR fallback; Cargo 1.91+ expands {workspace-path-hash}.
|
||||
codewhale_dev_cache_path_fingerprint() {
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
printf '%s' "$1" | sha256sum | awk '{print substr($1,1,16)}'
|
||||
elif command -v shasum >/dev/null 2>&1; then
|
||||
printf '%s' "$1" | shasum -a 256 | awk '{print substr($1,1,16)}'
|
||||
elif command -v openssl >/dev/null 2>&1; then
|
||||
printf '%s' "$1" | openssl dgst -sha256 | awk '{print substr($NF,1,16)}'
|
||||
else
|
||||
printf '%s' "$1" | cksum | awk '{printf "%s%08s\n", $1, $2}' | tr ' ' '0'
|
||||
fi
|
||||
}
|
||||
|
||||
codewhale_dev_cache_has_local_target() {
|
||||
_cw_repo=$(codewhale_dev_cache_repo_root)
|
||||
[ -d "$_cw_repo/target" ]
|
||||
}
|
||||
|
||||
codewhale_dev_cache_incremental_off() {
|
||||
case ${CARGO_INCREMENTAL:-} in
|
||||
0|false|no|off) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
codewhale_dev_cache_incremental_on() {
|
||||
case ${CARGO_INCREMENTAL:-} in
|
||||
1|true|yes|on) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
codewhale_dev_cache_sccache_bin() {
|
||||
command -v sccache 2>/dev/null || true
|
||||
}
|
||||
|
||||
codewhale_dev_cache_log() {
|
||||
if [ "${CODEWHALE_DEV_CACHE_QUIET:-}" = 1 ]; then
|
||||
return 0
|
||||
fi
|
||||
printf 'dev-cache: %s\n' "$*" >&2
|
||||
}
|
||||
|
||||
# Apply the topology to the current shell. Idempotent. Never overrides an
|
||||
# already-set CARGO_TARGET_DIR, CARGO_BUILD_BUILD_DIR, RUSTC_WRAPPER, or
|
||||
# SCCACHE_DIR.
|
||||
codewhale_dev_cache_apply() {
|
||||
CODEWHALE_DEV_CACHE_MODE=${CODEWHALE_DEV_CACHE_MODE:-}
|
||||
# Re-entry after a previous apply in this shell: keep the first decision
|
||||
# unless the caller unset the mode (tests do that between cases).
|
||||
if [ -n "${CODEWHALE_DEV_CACHE_APPLIED:-}" ] && [ -n "${CODEWHALE_DEV_CACHE_MODE:-}" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
_cw_want=${CODEWHALE_DEV_CACHE:-auto}
|
||||
_cw_root=$(codewhale_dev_cache_root)
|
||||
_cw_sccache_want=${CODEWHALE_SCCACHE:-auto}
|
||||
_cw_commit=$(codewhale_dev_cache_rustc_commit)
|
||||
CODEWHALE_DEV_CACHE_SCCACHE_DIR=${SCCACHE_DIR:-${_cw_root}/sccache/${_cw_commit}}
|
||||
CODEWHALE_DEV_CACHE_BUILD_DIR=${_cw_root}/build/'{workspace-path-hash}'
|
||||
CODEWHALE_DEV_CACHE_LEGACY_TARGET_DIR=${_cw_root}/target/$(codewhale_dev_cache_path_fingerprint "$(codewhale_dev_cache_repo_root)")
|
||||
|
||||
if codewhale_dev_cache_falsey "$_cw_want"; then
|
||||
CODEWHALE_DEV_CACHE_MODE=disabled
|
||||
CODEWHALE_DEV_CACHE_SCCACHE=disabled
|
||||
CODEWHALE_DEV_CACHE_APPLIED=1
|
||||
export CODEWHALE_DEV_CACHE_MODE CODEWHALE_DEV_CACHE_SCCACHE
|
||||
codewhale_dev_cache_log "disabled (CODEWHALE_DEV_CACHE=${_cw_want})"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -n "${CARGO_TARGET_DIR:-}" ]; then
|
||||
CODEWHALE_DEV_CACHE_MODE=inherited-target-dir
|
||||
elif [ -n "${CARGO_BUILD_BUILD_DIR:-}" ]; then
|
||||
CODEWHALE_DEV_CACHE_MODE=inherited-build-dir
|
||||
elif codewhale_dev_cache_truthy "$_cw_want"; then
|
||||
CODEWHALE_DEV_CACHE_MODE=force-isolated
|
||||
elif codewhale_dev_cache_has_local_target; then
|
||||
CODEWHALE_DEV_CACHE_MODE=existing-target
|
||||
else
|
||||
CODEWHALE_DEV_CACHE_MODE=isolated-build-dir
|
||||
fi
|
||||
|
||||
case $CODEWHALE_DEV_CACHE_MODE in
|
||||
force-isolated|isolated-build-dir)
|
||||
_cw_mm=$(codewhale_dev_cache_cargo_version_mm)
|
||||
if [ -n "$_cw_mm" ] && [ "$_cw_mm" -lt 1091 ]; then
|
||||
# Cargo 1.91 introduced build.build-dir. Older cargo only isolates
|
||||
# via CARGO_TARGET_DIR; keep that fallback per-workspace.
|
||||
if [ -z "${CARGO_TARGET_DIR:-}" ]; then
|
||||
CARGO_TARGET_DIR=$CODEWHALE_DEV_CACHE_LEGACY_TARGET_DIR
|
||||
export CARGO_TARGET_DIR
|
||||
fi
|
||||
CODEWHALE_DEV_CACHE_MODE=${CODEWHALE_DEV_CACHE_MODE}-legacy-target-dir
|
||||
else
|
||||
CARGO_BUILD_BUILD_DIR=$CODEWHALE_DEV_CACHE_BUILD_DIR
|
||||
export CARGO_BUILD_BUILD_DIR
|
||||
mkdir -p "$_cw_root/build" 2>/dev/null || true
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# sccache: never wrap incremental rustc. Missing binary is a fallback,
|
||||
# not an error.
|
||||
if codewhale_dev_cache_falsey "$_cw_sccache_want"; then
|
||||
CODEWHALE_DEV_CACHE_SCCACHE=disabled
|
||||
elif [ -n "${RUSTC_WRAPPER:-}" ]; then
|
||||
case $RUSTC_WRAPPER in
|
||||
*sccache*) CODEWHALE_DEV_CACHE_SCCACHE=external-sccache ;;
|
||||
*) CODEWHALE_DEV_CACHE_SCCACHE=external-wrapper ;;
|
||||
esac
|
||||
else
|
||||
if codewhale_dev_cache_truthy "$_cw_sccache_want" && ! codewhale_dev_cache_incremental_on; then
|
||||
# Request the measured new-worktree / CI-like topology.
|
||||
if [ -z "${CARGO_INCREMENTAL:-}" ]; then
|
||||
CARGO_INCREMENTAL=0
|
||||
export CARGO_INCREMENTAL
|
||||
fi
|
||||
fi
|
||||
if ! codewhale_dev_cache_incremental_off; then
|
||||
CODEWHALE_DEV_CACHE_SCCACHE=skipped-incremental
|
||||
else
|
||||
_cw_bin=$(codewhale_dev_cache_sccache_bin)
|
||||
if [ -z "$_cw_bin" ]; then
|
||||
CODEWHALE_DEV_CACHE_SCCACHE=not-found
|
||||
else
|
||||
RUSTC_WRAPPER=$_cw_bin
|
||||
export RUSTC_WRAPPER
|
||||
if [ -z "${SCCACHE_DIR:-}" ]; then
|
||||
SCCACHE_DIR=$CODEWHALE_DEV_CACHE_SCCACHE_DIR
|
||||
export SCCACHE_DIR
|
||||
fi
|
||||
mkdir -p "$SCCACHE_DIR" 2>/dev/null || true
|
||||
CODEWHALE_DEV_CACHE_SCCACHE=enabled
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
CODEWHALE_DEV_CACHE_APPLIED=1
|
||||
export CODEWHALE_DEV_CACHE_MODE CODEWHALE_DEV_CACHE_SCCACHE
|
||||
export CODEWHALE_DEV_CACHE_SCCACHE_DIR
|
||||
|
||||
_cw_line="mode=${CODEWHALE_DEV_CACHE_MODE} sccache=${CODEWHALE_DEV_CACHE_SCCACHE}"
|
||||
case $CODEWHALE_DEV_CACHE_MODE in
|
||||
isolated-build-dir*|force-isolated*)
|
||||
_cw_line="${_cw_line} build-dir=${CARGO_BUILD_BUILD_DIR:-${CARGO_TARGET_DIR:-unset}}"
|
||||
;;
|
||||
inherited-target-dir)
|
||||
_cw_line="${_cw_line} CARGO_TARGET_DIR=${CARGO_TARGET_DIR}"
|
||||
;;
|
||||
inherited-build-dir)
|
||||
_cw_line="${_cw_line} CARGO_BUILD_BUILD_DIR=${CARGO_BUILD_BUILD_DIR}"
|
||||
;;
|
||||
existing-target)
|
||||
_cw_line="${_cw_line} using ./target (set CODEWHALE_DEV_CACHE=1 to isolate)"
|
||||
;;
|
||||
esac
|
||||
if [ "${CODEWHALE_DEV_CACHE_SCCACHE}" = enabled ]; then
|
||||
_cw_line="${_cw_line} SCCACHE_DIR=${SCCACHE_DIR} rustc=${_cw_commit}"
|
||||
fi
|
||||
codewhale_dev_cache_log "$_cw_line"
|
||||
}
|
||||
|
||||
codewhale_dev_cache_status() {
|
||||
_cw_tmpl=${CODEWHALE_DEV_CACHE_BUILD_DIR:-}
|
||||
if [ -z "$_cw_tmpl" ]; then
|
||||
_cw_tmpl=$(codewhale_dev_cache_root)/build/'{workspace-path-hash}'
|
||||
fi
|
||||
printf '%s\n' \
|
||||
"cache_root=$(codewhale_dev_cache_root)" \
|
||||
"repo_root=$(codewhale_dev_cache_repo_root)" \
|
||||
"mode=${CODEWHALE_DEV_CACHE_MODE:-unset}" \
|
||||
"sccache=${CODEWHALE_DEV_CACHE_SCCACHE:-unset}" \
|
||||
"build_dir_template=${_cw_tmpl}" \
|
||||
"CARGO_BUILD_BUILD_DIR=${CARGO_BUILD_BUILD_DIR:-<unset>}" \
|
||||
"CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-<unset>}" \
|
||||
"CARGO_INCREMENTAL=${CARGO_INCREMENTAL:-<unset>}" \
|
||||
"RUSTC_WRAPPER=${RUSTC_WRAPPER:-<unset>}" \
|
||||
"SCCACHE_DIR=${SCCACHE_DIR:-<unset>}" \
|
||||
"rustc_commit=$(codewhale_dev_cache_rustc_commit)" \
|
||||
"sccache_bin=$(codewhale_dev_cache_sccache_bin)"
|
||||
}
|
||||
|
||||
# Extra cargo CLI flags that force template expansion of build-dir.
|
||||
# CARGO_BUILD_BUILD_DIR is still exported for nested tools; --config is
|
||||
# what Cargo documents as supporting {workspace-path-hash}.
|
||||
codewhale_dev_cache_exec_cargo() {
|
||||
case ${CODEWHALE_DEV_CACHE_MODE:-} in
|
||||
isolated-build-dir|force-isolated)
|
||||
if [ -n "${CARGO_BUILD_BUILD_DIR:-}" ]; then
|
||||
exec cargo --config "build.build-dir = \"${CARGO_BUILD_BUILD_DIR}\"" "$@"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
exec cargo "$@"
|
||||
}
|
||||
|
||||
codewhale_dev_cache_print_exports() {
|
||||
[ -n "${CARGO_BUILD_BUILD_DIR:-}" ] && printf 'export CARGO_BUILD_BUILD_DIR=%s\n' "$CARGO_BUILD_BUILD_DIR"
|
||||
[ -n "${CARGO_TARGET_DIR:-}" ] && printf 'export CARGO_TARGET_DIR=%s\n' "$CARGO_TARGET_DIR"
|
||||
[ -n "${CARGO_INCREMENTAL:-}" ] && printf 'export CARGO_INCREMENTAL=%s\n' "$CARGO_INCREMENTAL"
|
||||
[ -n "${RUSTC_WRAPPER:-}" ] && printf 'export RUSTC_WRAPPER=%s\n' "$RUSTC_WRAPPER"
|
||||
[ -n "${SCCACHE_DIR:-}" ] && printf 'export SCCACHE_DIR=%s\n' "$SCCACHE_DIR"
|
||||
[ -n "${CODEWHALE_DEV_CACHE_MODE:-}" ] && printf 'export CODEWHALE_DEV_CACHE_MODE=%s\n' "$CODEWHALE_DEV_CACHE_MODE"
|
||||
[ -n "${CODEWHALE_DEV_CACHE_SCCACHE:-}" ] && printf 'export CODEWHALE_DEV_CACHE_SCCACHE=%s\n' "$CODEWHALE_DEV_CACHE_SCCACHE"
|
||||
}
|
||||
|
||||
codewhale_dev_cache_self_check() {
|
||||
_cw_fail=0
|
||||
_cw_root=$(codewhale_dev_cache_root)
|
||||
_cw_home=${HOME:-}
|
||||
_cw_xdg=${XDG_CACHE_HOME:-}
|
||||
|
||||
if [ -z "${CODEWHALE_CACHE_ROOT:-}" ]; then
|
||||
if [ -n "$_cw_xdg" ]; then
|
||||
case $_cw_root in
|
||||
"$_cw_xdg"/codewhale) ;;
|
||||
*)
|
||||
printf 'self-check: expected XDG default %s/codewhale, got %s\n' "$_cw_xdg" "$_cw_root" >&2
|
||||
_cw_fail=1
|
||||
;;
|
||||
esac
|
||||
elif [ -n "$_cw_home" ]; then
|
||||
case $_cw_root in
|
||||
"$_cw_home"/.cache/codewhale) ;;
|
||||
*)
|
||||
printf 'self-check: expected HOME default %s/.cache/codewhale, got %s\n' "$_cw_home" "$_cw_root" >&2
|
||||
_cw_fail=1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
case ${CARGO_BUILD_BUILD_DIR:-} in
|
||||
*'{workspace-path-hash}'*)
|
||||
;;
|
||||
'')
|
||||
case ${CODEWHALE_DEV_CACHE_MODE:-} in
|
||||
isolated-build-dir|force-isolated)
|
||||
printf 'self-check: isolated mode did not set CARGO_BUILD_BUILD_DIR\n' >&2
|
||||
_cw_fail=1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
case ${CODEWHALE_DEV_CACHE_MODE:-} in
|
||||
isolated-build-dir|force-isolated)
|
||||
printf 'self-check: isolated build-dir lacks {workspace-path-hash}: %s\n' "$CARGO_BUILD_BUILD_DIR" >&2
|
||||
_cw_fail=1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "${CODEWHALE_DEV_CACHE_SCCACHE:-}" = enabled ]; then
|
||||
if ! codewhale_dev_cache_incremental_off; then
|
||||
printf 'self-check: sccache enabled while incremental is not off\n' >&2
|
||||
_cw_fail=1
|
||||
fi
|
||||
case ${RUSTC_WRAPPER:-} in
|
||||
*sccache*) ;;
|
||||
*)
|
||||
printf 'self-check: sccache enabled but RUSTC_WRAPPER=%s\n' "${RUSTC_WRAPPER:-<unset>}" >&2
|
||||
_cw_fail=1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ "${CODEWHALE_DEV_CACHE_SCCACHE:-}" = not-found ]; then
|
||||
if [ -n "${RUSTC_WRAPPER:-}" ]; then
|
||||
printf 'self-check: missing sccache must not set RUSTC_WRAPPER (%s)\n' "$RUSTC_WRAPPER" >&2
|
||||
_cw_fail=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$_cw_fail" -eq 0 ]; then
|
||||
printf 'dev-cache: self-check ok\n'
|
||||
return 0
|
||||
fi
|
||||
printf 'dev-cache: self-check FAILED\n' >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
codewhale_dev_cache_usage() {
|
||||
cat <<'EOF'
|
||||
usage: scripts/dev-cache.sh --status|--self-check|--print-exports|--help
|
||||
|
||||
Portable opt-in Cargo cache topology. Source this file and call
|
||||
codewhale_dev_cache_apply from scripts/dev-test.sh / scripts/dev-cargo.sh.
|
||||
|
||||
--status apply (if needed) and print key=value status
|
||||
--self-check apply and check portable defaults / sccache fallback
|
||||
--print-exports apply and print export statements for eval
|
||||
--help this message
|
||||
|
||||
Environment overrides are documented at the top of this file. Defaults
|
||||
never contain a machine-specific absolute path.
|
||||
EOF
|
||||
}
|
||||
|
||||
# CLI only when this file is the executed program, not when sourced.
|
||||
case ${0##*/} in
|
||||
dev-cache.sh)
|
||||
set -eu
|
||||
_cw_cmd=${1:---status}
|
||||
case $_cw_cmd in
|
||||
--status|-s)
|
||||
codewhale_dev_cache_apply
|
||||
codewhale_dev_cache_status
|
||||
;;
|
||||
--self-check)
|
||||
codewhale_dev_cache_apply
|
||||
codewhale_dev_cache_status
|
||||
codewhale_dev_cache_self_check
|
||||
;;
|
||||
--print-exports)
|
||||
codewhale_dev_cache_apply
|
||||
codewhale_dev_cache_print_exports
|
||||
;;
|
||||
--help|-h)
|
||||
codewhale_dev_cache_usage
|
||||
;;
|
||||
*)
|
||||
codewhale_dev_cache_usage >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
Executable
+294
@@ -0,0 +1,294 @@
|
||||
#!/bin/sh
|
||||
# Hermetic tests for scripts/dev-cache.sh. No cargo compile, no cache
|
||||
# deletion. Exercises portable defaults, overrides, missing-sccache
|
||||
# fallback, incremental gating, and new-vs-existing worktree policy.
|
||||
set -eu
|
||||
|
||||
repo_root=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
DEV_CACHE=$repo_root/scripts/dev-cache.sh
|
||||
DEV_CARGO=$repo_root/scripts/dev-cargo.sh
|
||||
|
||||
fail=0
|
||||
pass=0
|
||||
|
||||
ok() {
|
||||
pass=$((pass + 1))
|
||||
printf 'ok - %s\n' "$1"
|
||||
}
|
||||
|
||||
bad() {
|
||||
fail=$((fail + 1))
|
||||
printf 'FAIL - %s\n' "$1"
|
||||
if [ -n "${2:-}" ]; then
|
||||
printf '%s\n' "$2" | sed 's/^/ /'
|
||||
fi
|
||||
}
|
||||
|
||||
work=$(mktemp -d "${TMPDIR:-/tmp}/codewhale-dev-cache.XXXXXX")
|
||||
cleanup() { rm -rf "$work"; }
|
||||
trap cleanup EXIT INT HUP TERM
|
||||
|
||||
HOME_DIR=$work/home
|
||||
mkdir -p "$HOME_DIR"
|
||||
FAKEBIN=$work/bin
|
||||
mkdir -p "$FAKEBIN"
|
||||
NEW_WT=$work/new-wt
|
||||
OLD_WT=$work/old-wt
|
||||
mkdir -p "$NEW_WT" "$OLD_WT/target"
|
||||
|
||||
# cargo/rustc/sccache are injected per case. Keep the base PATH hermetic.
|
||||
BASE_PATH=$FAKEBIN:/usr/bin:/bin
|
||||
|
||||
run_apply() {
|
||||
env -i \
|
||||
PATH="$BASE_PATH" \
|
||||
HOME="$HOME_DIR" \
|
||||
CODEWHALE_DEV_CACHE_QUIET=1 \
|
||||
DEV_CACHE="$DEV_CACHE" \
|
||||
"$@" \
|
||||
/bin/sh -c '
|
||||
set -eu
|
||||
. "$DEV_CACHE"
|
||||
codewhale_dev_cache_apply
|
||||
codewhale_dev_cache_status
|
||||
' # shellcheck disable=SC2016 -- $DEV_CACHE expands in the child.
|
||||
}
|
||||
|
||||
contains() {
|
||||
printf '%s' "$1" | grep -qF -- "$2"
|
||||
}
|
||||
|
||||
# 1. Portable default root is $HOME/.cache/codewhale, never a desk path.
|
||||
out=$(run_apply CODEWHALE_DEV_CACHE=0 CODEWHALE_DEV_CACHE_REPO_ROOT="$NEW_WT")
|
||||
if contains "$out" "cache_root=$HOME_DIR/.cache/codewhale"; then
|
||||
ok "default cache root is HOME/.cache/codewhale"
|
||||
else
|
||||
bad "default cache root is HOME/.cache/codewhale" "$out"
|
||||
fi
|
||||
if printf '%s\n' "$out" | grep -v '^repo_root=' | grep -qF /Volumes/VIXinSSD; then
|
||||
bad "default paths must not mention /Volumes/VIXinSSD" "$out"
|
||||
else
|
||||
ok "default paths do not mention /Volumes/VIXinSSD"
|
||||
fi
|
||||
if grep -E '/Users/hunterbown|/Volumes/VIXinSSD' "$DEV_CACHE" "$DEV_CARGO" >/dev/null; then
|
||||
bad "helper source must not hard-code a desk path"
|
||||
else
|
||||
ok "helper source has no desk-local absolute paths"
|
||||
fi
|
||||
|
||||
# 2. XDG_CACHE_HOME and CODEWHALE_CACHE_ROOT win in that documented order.
|
||||
out=$(run_apply CODEWHALE_DEV_CACHE=0 XDG_CACHE_HOME="$work/xdg")
|
||||
if contains "$out" "cache_root=$work/xdg/codewhale"; then
|
||||
ok "XDG_CACHE_HOME/codewhale is the default when set"
|
||||
else
|
||||
bad "XDG_CACHE_HOME/codewhale is the default when set" "$out"
|
||||
fi
|
||||
out=$(run_apply CODEWHALE_DEV_CACHE=0 \
|
||||
XDG_CACHE_HOME="$work/xdg" \
|
||||
CODEWHALE_CACHE_ROOT="$work/explicit-root")
|
||||
if contains "$out" "cache_root=$work/explicit-root"; then
|
||||
ok "CODEWHALE_CACHE_ROOT overrides XDG and HOME"
|
||||
else
|
||||
bad "CODEWHALE_CACHE_ROOT overrides XDG and HOME" "$out"
|
||||
fi
|
||||
|
||||
# 3. Disabled mode leaves Cargo/sccache vars alone.
|
||||
out=$(run_apply CODEWHALE_DEV_CACHE=0)
|
||||
if contains "$out" "mode=disabled" \
|
||||
&& contains "$out" "CARGO_BUILD_BUILD_DIR=<unset>" \
|
||||
&& contains "$out" "RUSTC_WRAPPER=<unset>"; then
|
||||
ok "CODEWHALE_DEV_CACHE=0 does not set cargo or sccache vars"
|
||||
else
|
||||
bad "CODEWHALE_DEV_CACHE=0 does not set cargo or sccache vars" "$out"
|
||||
fi
|
||||
|
||||
# 4. New worktree (no ./target) gets isolated build-dir with the cargo template.
|
||||
out=$(run_apply \
|
||||
CODEWHALE_DEV_CACHE_REPO_ROOT="$NEW_WT" \
|
||||
CODEWHALE_CACHE_ROOT="$work/cache")
|
||||
if contains "$out" "mode=isolated-build-dir" \
|
||||
&& contains "$out" "CARGO_BUILD_BUILD_DIR=$work/cache/build/{workspace-path-hash}"; then
|
||||
ok "new worktree uses isolated build-dir template"
|
||||
else
|
||||
bad "new worktree uses isolated build-dir template" "$out"
|
||||
fi
|
||||
if contains "$out" "CARGO_INCREMENTAL=<unset>"; then
|
||||
ok "isolated default does not turn incremental off"
|
||||
else
|
||||
bad "isolated default does not turn incremental off" "$out"
|
||||
fi
|
||||
if contains "$out" "sccache=skipped-incremental"; then
|
||||
ok "sccache stays off while incremental is on"
|
||||
else
|
||||
bad "sccache stays off while incremental is on" "$out"
|
||||
fi
|
||||
|
||||
# 5. Existing ./target is left alone under auto.
|
||||
out=$(run_apply \
|
||||
CODEWHALE_DEV_CACHE_REPO_ROOT="$OLD_WT" \
|
||||
CODEWHALE_CACHE_ROOT="$work/cache")
|
||||
if contains "$out" "mode=existing-target" \
|
||||
&& contains "$out" "CARGO_BUILD_BUILD_DIR=<unset>"; then
|
||||
ok "existing ./target is not moved under auto"
|
||||
else
|
||||
bad "existing ./target is not moved under auto" "$out"
|
||||
fi
|
||||
|
||||
# 6. CODEWHALE_DEV_CACHE=1 isolates even when ./target exists.
|
||||
out=$(run_apply \
|
||||
CODEWHALE_DEV_CACHE=1 \
|
||||
CODEWHALE_DEV_CACHE_REPO_ROOT="$OLD_WT" \
|
||||
CODEWHALE_CACHE_ROOT="$work/cache")
|
||||
if contains "$out" "mode=force-isolated" \
|
||||
&& contains "$out" "CARGO_BUILD_BUILD_DIR=$work/cache/build/{workspace-path-hash}"; then
|
||||
ok "CODEWHALE_DEV_CACHE=1 isolates an existing worktree"
|
||||
else
|
||||
bad "CODEWHALE_DEV_CACHE=1 isolates an existing worktree" "$out"
|
||||
fi
|
||||
|
||||
# 7. Already-set CARGO_TARGET_DIR / CARGO_BUILD_BUILD_DIR are respected.
|
||||
out=$(run_apply \
|
||||
CODEWHALE_DEV_CACHE=1 \
|
||||
CARGO_TARGET_DIR="$work/user-target" \
|
||||
CODEWHALE_DEV_CACHE_REPO_ROOT="$NEW_WT")
|
||||
if contains "$out" "mode=inherited-target-dir" \
|
||||
&& contains "$out" "CARGO_TARGET_DIR=$work/user-target" \
|
||||
&& contains "$out" "CARGO_BUILD_BUILD_DIR=<unset>"; then
|
||||
ok "existing CARGO_TARGET_DIR is not overwritten"
|
||||
else
|
||||
bad "existing CARGO_TARGET_DIR is not overwritten" "$out"
|
||||
fi
|
||||
out=$(run_apply \
|
||||
CARGO_BUILD_BUILD_DIR="$work/user-build" \
|
||||
CODEWHALE_DEV_CACHE_REPO_ROOT="$NEW_WT")
|
||||
if contains "$out" "mode=inherited-build-dir" \
|
||||
&& contains "$out" "CARGO_BUILD_BUILD_DIR=$work/user-build"; then
|
||||
ok "existing CARGO_BUILD_BUILD_DIR is not overwritten"
|
||||
else
|
||||
bad "existing CARGO_BUILD_BUILD_DIR is not overwritten" "$out"
|
||||
fi
|
||||
|
||||
# 8. Missing sccache is a fallback, not a failure, even when requested.
|
||||
out=$(run_apply \
|
||||
CODEWHALE_SCCACHE=1 \
|
||||
CODEWHALE_DEV_CACHE_REPO_ROOT="$NEW_WT" \
|
||||
CODEWHALE_CACHE_ROOT="$work/cache")
|
||||
if contains "$out" "sccache=not-found" \
|
||||
&& contains "$out" "RUSTC_WRAPPER=<unset>" \
|
||||
&& contains "$out" "CARGO_INCREMENTAL=0"; then
|
||||
ok "missing sccache falls back without setting RUSTC_WRAPPER"
|
||||
else
|
||||
bad "missing sccache falls back without setting RUSTC_WRAPPER" "$out"
|
||||
fi
|
||||
|
||||
# 9. sccache wraps only when incremental is off and the binary exists.
|
||||
printf '%s\n' '#!/bin/sh' 'exit 0' >"$FAKEBIN/sccache"
|
||||
chmod +x "$FAKEBIN/sccache"
|
||||
|
||||
out=$(run_apply \
|
||||
CARGO_INCREMENTAL=0 \
|
||||
CODEWHALE_DEV_CACHE_REPO_ROOT="$NEW_WT" \
|
||||
CODEWHALE_CACHE_ROOT="$work/cache" \
|
||||
CODEWHALE_RUSTC_COMMIT=abc123deadbeef)
|
||||
if contains "$out" "sccache=enabled" \
|
||||
&& contains "$out" "RUSTC_WRAPPER=$FAKEBIN/sccache" \
|
||||
&& contains "$out" "SCCACHE_DIR=$work/cache/sccache/abc123deadbeef"; then
|
||||
ok "sccache wraps rustc when incremental is off"
|
||||
else
|
||||
bad "sccache wraps rustc when incremental is off" "$out"
|
||||
fi
|
||||
|
||||
out=$(run_apply \
|
||||
CARGO_INCREMENTAL=1 \
|
||||
CODEWHALE_SCCACHE=1 \
|
||||
CODEWHALE_DEV_CACHE_REPO_ROOT="$NEW_WT" \
|
||||
CODEWHALE_CACHE_ROOT="$work/cache")
|
||||
if contains "$out" "sccache=skipped-incremental" \
|
||||
&& contains "$out" "RUSTC_WRAPPER=<unset>" \
|
||||
&& contains "$out" "CARGO_INCREMENTAL=1"; then
|
||||
ok "explicit incremental=1 wins over CODEWHALE_SCCACHE=1"
|
||||
else
|
||||
bad "explicit incremental=1 wins over CODEWHALE_SCCACHE=1" "$out"
|
||||
fi
|
||||
|
||||
out=$(run_apply \
|
||||
CODEWHALE_SCCACHE=1 \
|
||||
CODEWHALE_DEV_CACHE_REPO_ROOT="$NEW_WT" \
|
||||
CODEWHALE_CACHE_ROOT="$work/cache" \
|
||||
CODEWHALE_RUSTC_COMMIT=abc123deadbeef)
|
||||
if contains "$out" "sccache=enabled" \
|
||||
&& contains "$out" "CARGO_INCREMENTAL=0"; then
|
||||
ok "CODEWHALE_SCCACHE=1 requests incremental=0 and wraps"
|
||||
else
|
||||
bad "CODEWHALE_SCCACHE=1 requests incremental=0 and wraps" "$out"
|
||||
fi
|
||||
|
||||
out=$(run_apply \
|
||||
RUSTC_WRAPPER=/usr/bin/true \
|
||||
CARGO_INCREMENTAL=0 \
|
||||
CODEWHALE_DEV_CACHE_REPO_ROOT="$NEW_WT")
|
||||
if contains "$out" "sccache=external-wrapper" \
|
||||
&& contains "$out" "RUSTC_WRAPPER=/usr/bin/true"; then
|
||||
ok "existing RUSTC_WRAPPER is left alone"
|
||||
else
|
||||
bad "existing RUSTC_WRAPPER is left alone" "$out"
|
||||
fi
|
||||
|
||||
# 10. Cargo older than 1.91 falls back to a per-workspace CARGO_TARGET_DIR.
|
||||
printf '%s\n' '#!/bin/sh' 'echo "cargo 1.88.0 (test)"' >"$FAKEBIN/cargo"
|
||||
chmod +x "$FAKEBIN/cargo"
|
||||
out=$(run_apply \
|
||||
CODEWHALE_DEV_CACHE=1 \
|
||||
CODEWHALE_DEV_CACHE_REPO_ROOT="$NEW_WT" \
|
||||
CODEWHALE_CACHE_ROOT="$work/cache")
|
||||
if contains "$out" "legacy-target-dir" \
|
||||
&& contains "$out" "CARGO_BUILD_BUILD_DIR=<unset>" \
|
||||
&& contains "$out" "CARGO_TARGET_DIR=$work/cache/target/"; then
|
||||
ok "cargo 1.88 falls back to an isolated CARGO_TARGET_DIR"
|
||||
else
|
||||
bad "cargo 1.88 falls back to an isolated CARGO_TARGET_DIR" "$out"
|
||||
fi
|
||||
rm -f "$FAKEBIN/cargo"
|
||||
|
||||
# 11. CLI self-check passes for a new worktree with portable HOME.
|
||||
cli_out=$(
|
||||
env -i \
|
||||
PATH="$BASE_PATH" \
|
||||
HOME="$HOME_DIR" \
|
||||
PWD="$NEW_WT" \
|
||||
CODEWHALE_DEV_CACHE_QUIET=1 \
|
||||
CODEWHALE_DEV_CACHE_REPO_ROOT="$NEW_WT" \
|
||||
CODEWHALE_CACHE_ROOT="$work/cache" \
|
||||
/bin/sh "$DEV_CACHE" --self-check
|
||||
) || cli_rc=$?
|
||||
cli_rc=${cli_rc:-0}
|
||||
if [ "$cli_rc" -eq 0 ] && contains "$cli_out" "dev-cache: self-check ok"; then
|
||||
ok "CLI --self-check passes on a new worktree"
|
||||
else
|
||||
bad "CLI --self-check passes on a new worktree" "$cli_out"
|
||||
fi
|
||||
|
||||
# 12. Two worktree paths produce different legacy fingerprints.
|
||||
# shellcheck source=scripts/dev-cache.sh
|
||||
. "$DEV_CACHE"
|
||||
fp_a=$(codewhale_dev_cache_path_fingerprint "$NEW_WT")
|
||||
fp_b=$(codewhale_dev_cache_path_fingerprint "$OLD_WT")
|
||||
if [ -n "$fp_a" ] && [ -n "$fp_b" ] && [ "$fp_a" != "$fp_b" ]; then
|
||||
ok "path fingerprints differ across worktrees"
|
||||
else
|
||||
bad "path fingerprints differ across worktrees" "a=$fp_a b=$fp_b"
|
||||
fi
|
||||
|
||||
# 13. dev-cargo.sh --status is the same helper.
|
||||
if /bin/sh "$DEV_CARGO" --help | grep -q 'dev-cache'; then
|
||||
ok "dev-cargo.sh --help delegates to the cache helper"
|
||||
else
|
||||
bad "dev-cargo.sh --help delegates to the cache helper"
|
||||
fi
|
||||
|
||||
if [ "$fail" -eq 0 ]; then
|
||||
printf 'dev-cache.test.sh: all %s checks passed\n' "$pass"
|
||||
exit 0
|
||||
fi
|
||||
printf 'dev-cache.test.sh: %s/%s checks failed\n' "$fail" "$((pass + fail))" >&2
|
||||
exit 1
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/bin/sh
|
||||
# Run cargo with the portable Codewhale cache topology applied.
|
||||
#
|
||||
# scripts/dev-cargo.sh test -p codewhale-config --lib --locked
|
||||
# scripts/dev-cargo.sh --status
|
||||
# scripts/dev-cargo.sh --self-check
|
||||
#
|
||||
# This is the everyday compile entry point. It does not change product
|
||||
# behavior. See scripts/dev-cache.sh and docs/BUILD_PERFORMANCE.md.
|
||||
set -eu
|
||||
|
||||
repo_root=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
cd "$repo_root"
|
||||
|
||||
# shellcheck source=scripts/dev-cache.sh
|
||||
. "$repo_root/scripts/dev-cache.sh"
|
||||
|
||||
case ${1:-} in
|
||||
--status|--self-check|--print-exports|--help|-h)
|
||||
exec "$repo_root/scripts/dev-cache.sh" "$1"
|
||||
;;
|
||||
esac
|
||||
|
||||
codewhale_dev_cache_apply
|
||||
# Match CI / the product's 16 MiB owner-thread stack so local cargo test
|
||||
# and nextest do not abort on the default ~2 MiB (Windows ~1 MiB) stack.
|
||||
if [ -z "${RUST_MIN_STACK:-}" ]; then
|
||||
RUST_MIN_STACK=16777216
|
||||
export RUST_MIN_STACK
|
||||
fi
|
||||
codewhale_dev_cache_exec_cargo "$@"
|
||||
+90
-33
@@ -1,24 +1,36 @@
|
||||
#!/bin/sh
|
||||
# Map a workspace area or source path to the fastest cargo test for that
|
||||
# area. Developer iteration aid only; no product behavior.
|
||||
# Map a workspace area or source path to the fastest cargo/nextest
|
||||
# invocation for that area, and apply the portable cache topology so a
|
||||
# new worktree actually gets isolated build-dir (+ sccache only when
|
||||
# incremental is already off). Developer iteration aid only; no product
|
||||
# behavior.
|
||||
#
|
||||
# Usage:
|
||||
# scripts/dev-test.sh <area|path> [filter...]
|
||||
# scripts/dev-test.sh --list
|
||||
# scripts/dev-test.sh --status
|
||||
#
|
||||
# Examples:
|
||||
# scripts/dev-test.sh config
|
||||
# scripts/dev-test.sh tui elapsed::
|
||||
# scripts/dev-test.sh crates/tui/src/elapsed.rs
|
||||
# scripts/dev-test.sh tui-pty qa_pty
|
||||
#
|
||||
# Environment:
|
||||
# CODEWHALE_DEV_NEXTEST auto|1|0 (default auto: use cargo-nextest when
|
||||
# it is on PATH; 0 forces cargo test)
|
||||
# Cache knobs are documented in scripts/dev-cache.sh.
|
||||
set -eu
|
||||
|
||||
repo_root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
repo_root=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
cd "$repo_root"
|
||||
|
||||
# shellcheck source=scripts/dev-cache.sh
|
||||
. "$repo_root/scripts/dev-cache.sh"
|
||||
|
||||
usage() {
|
||||
printf '%s\n' "usage: scripts/dev-test.sh <area|path> [filter...]" >&2
|
||||
printf '%s\n' " scripts/dev-test.sh --list" >&2
|
||||
printf '%s\n' " scripts/dev-test.sh --list|--status|--self-check" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
@@ -26,29 +38,34 @@ list_areas() {
|
||||
cat <<'EOF'
|
||||
area command
|
||||
---- -------
|
||||
config cargo test -p codewhale-config --lib --locked
|
||||
protocol cargo test -p codewhale-protocol --lib --locked
|
||||
execpolicy cargo test -p codewhale-execpolicy --lib --locked
|
||||
paths cargo test -p codewhale-paths --lib --locked
|
||||
secrets cargo test -p codewhale-secrets --lib --locked
|
||||
agent cargo test -p codewhale-agent --lib --locked
|
||||
app-server cargo test -p codewhale-app-server --lib --locked
|
||||
build-support cargo test -p codewhale-build-support --lib --locked
|
||||
cli cargo test -p codewhale-cli --lib --locked
|
||||
command-contract cargo test -p codewhale-command-contract --lib --locked
|
||||
config cargo test -p codewhale-config --lib --locked
|
||||
core cargo test -p codewhale-core --lib --locked
|
||||
execpolicy cargo test -p codewhale-execpolicy --lib --locked
|
||||
hooks cargo test -p codewhale-hooks --lib --locked
|
||||
lane cargo test -p codewhale-lane --lib --locked
|
||||
mcp cargo test -p codewhale-mcp --lib --locked
|
||||
paths cargo test -p codewhale-paths --lib --locked
|
||||
protocol cargo test -p codewhale-protocol --lib --locked
|
||||
release cargo test -p codewhale-release --lib --locked
|
||||
secrets cargo test -p codewhale-secrets --lib --locked
|
||||
state cargo test -p codewhale-state --lib --locked
|
||||
telemetry cargo test -p codewhale-telemetry --lib --locked
|
||||
tools cargo test -p codewhale-tools --lib --locked
|
||||
tui cargo test -p codewhale-tui --lib --locked
|
||||
tui-integration cargo test -p codewhale-tui --test integration --locked
|
||||
tui-pty cargo test -p codewhale-tui --test pty --locked
|
||||
tui-cucumber cargo test -p codewhale-tui --test cucumber --locked
|
||||
workflow cargo test -p codewhale-workflow --lib --locked
|
||||
workflow-js cargo test -p codewhale-workflow-js --lib --locked
|
||||
|
||||
path prefix area / extra filter
|
||||
----------- -------------------
|
||||
crates/config/ config
|
||||
crates/protocol/ protocol
|
||||
crates/execpolicy/ execpolicy
|
||||
crates/paths/ paths
|
||||
crates/secrets/ secrets
|
||||
crates/cli/ cli
|
||||
crates/core/ core
|
||||
crates/tools/ tools
|
||||
crates/<crate>/ <crate>
|
||||
crates/tui/src/tui/ tui tui::
|
||||
crates/tui/src/tools/ tui tools::
|
||||
crates/tui/src/core/ tui core::
|
||||
@@ -59,8 +76,13 @@ crates/tui/tests/pty/ tui-pty <stem>
|
||||
crates/tui/tests/cucumber/ tui-cucumber <stem>
|
||||
crates/tui/tests/ tui-integration
|
||||
|
||||
Do not use cargo test --workspace for a single-area edit. --lib and
|
||||
--tests are disjoint; a green --lib run does not cover crates/tui/tests/.
|
||||
When cargo-nextest is on PATH, the run stage is `cargo nextest run`
|
||||
instead of `cargo test` (same binaries; process per test). Set
|
||||
CODEWHALE_DEV_NEXTEST=0 to force libtest. New worktrees get an isolated
|
||||
Cargo build-dir via scripts/dev-cache.sh; sccache wraps rustc only when
|
||||
incremental is already off. Do not use cargo test --workspace for a
|
||||
single-area edit. --lib and --tests are disjoint; a green --lib run does
|
||||
not cover crates/tui/tests/.
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -71,6 +93,10 @@ if [ "$1" = "--list" ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$1" = "--status" ] || [ "$1" = "--self-check" ]; then
|
||||
exec "$repo_root/scripts/dev-cache.sh" "$1"
|
||||
fi
|
||||
|
||||
area=$1
|
||||
shift
|
||||
|
||||
@@ -80,14 +106,6 @@ if [ -e "$area" ] || printf '%s' "$area" | grep -q /; then
|
||||
rel=${area#./}
|
||||
extra=
|
||||
case $rel in
|
||||
crates/config/*|crates/config) area=config ;;
|
||||
crates/protocol/*|crates/protocol) area=protocol ;;
|
||||
crates/execpolicy/*|crates/execpolicy) area=execpolicy ;;
|
||||
crates/paths/*|crates/paths) area=paths ;;
|
||||
crates/secrets/*|crates/secrets) area=secrets ;;
|
||||
crates/cli/*|crates/cli) area=cli ;;
|
||||
crates/core/*|crates/core) area=core ;;
|
||||
crates/tools/*|crates/tools) area=tools ;;
|
||||
crates/tui/tests/integration/*)
|
||||
area=tui-integration
|
||||
extra=$(basename "$rel" .rs)
|
||||
@@ -147,15 +165,27 @@ fi
|
||||
pkg=
|
||||
target=--lib
|
||||
case $area in
|
||||
config) pkg=codewhale-config ;;
|
||||
protocol) pkg=codewhale-protocol ;;
|
||||
execpolicy) pkg=codewhale-execpolicy ;;
|
||||
paths) pkg=codewhale-paths ;;
|
||||
secrets) pkg=codewhale-secrets ;;
|
||||
agent) pkg=codewhale-agent ;;
|
||||
app-server) pkg=codewhale-app-server ;;
|
||||
build-support) pkg=codewhale-build-support ;;
|
||||
cli) pkg=codewhale-cli ;;
|
||||
command-contract) pkg=codewhale-command-contract ;;
|
||||
config) pkg=codewhale-config ;;
|
||||
core) pkg=codewhale-core ;;
|
||||
execpolicy) pkg=codewhale-execpolicy ;;
|
||||
hooks) pkg=codewhale-hooks ;;
|
||||
lane) pkg=codewhale-lane ;;
|
||||
mcp) pkg=codewhale-mcp ;;
|
||||
paths) pkg=codewhale-paths ;;
|
||||
protocol) pkg=codewhale-protocol ;;
|
||||
release) pkg=codewhale-release ;;
|
||||
secrets) pkg=codewhale-secrets ;;
|
||||
state) pkg=codewhale-state ;;
|
||||
telemetry) pkg=codewhale-telemetry ;;
|
||||
tools) pkg=codewhale-tools ;;
|
||||
tui) pkg=codewhale-tui ;;
|
||||
workflow) pkg=codewhale-workflow ;;
|
||||
workflow-js) pkg=codewhale-workflow-js ;;
|
||||
tui-integration)
|
||||
pkg=codewhale-tui
|
||||
target=--test
|
||||
@@ -177,11 +207,38 @@ case $area in
|
||||
;;
|
||||
esac
|
||||
|
||||
codewhale_dev_cache_apply
|
||||
if [ -z "${RUST_MIN_STACK:-}" ]; then
|
||||
RUST_MIN_STACK=16777216
|
||||
export RUST_MIN_STACK
|
||||
fi
|
||||
|
||||
use_nextest=0
|
||||
_cw_nextest=${CODEWHALE_DEV_NEXTEST:-auto}
|
||||
if codewhale_dev_cache_falsey "$_cw_nextest"; then
|
||||
use_nextest=0
|
||||
elif command -v cargo-nextest >/dev/null 2>&1; then
|
||||
use_nextest=1
|
||||
elif codewhale_dev_cache_truthy "$_cw_nextest"; then
|
||||
printf '%s\n' "dev-test: CODEWHALE_DEV_NEXTEST=${_cw_nextest} but cargo-nextest is not on PATH" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ "$target" = "--test" ]; then
|
||||
if [ "$use_nextest" -eq 1 ]; then
|
||||
set -- nextest run -p "$pkg" --test "$harness" --locked "$@"
|
||||
printf '+ cargo %s\n' "$*"
|
||||
codewhale_dev_cache_exec_cargo "$@"
|
||||
fi
|
||||
set -- test -p "$pkg" --test "$harness" --locked "$@"
|
||||
else
|
||||
if [ "$use_nextest" -eq 1 ]; then
|
||||
set -- nextest run -p "$pkg" --lib --locked "$@"
|
||||
printf '+ cargo %s\n' "$*"
|
||||
codewhale_dev_cache_exec_cargo "$@"
|
||||
fi
|
||||
set -- test -p "$pkg" --lib --locked "$@"
|
||||
fi
|
||||
|
||||
printf '+ cargo %s\n' "$*"
|
||||
exec cargo "$@"
|
||||
codewhale_dev_cache_exec_cargo "$@"
|
||||
|
||||
Executable
+216
@@ -0,0 +1,216 @@
|
||||
#!/bin/sh
|
||||
# Hermetic tests for scripts/dev-test.sh: area routing, nextest vs
|
||||
# libtest selection, and that the cache helper is actually applied.
|
||||
# Uses a fake cargo; does not compile anything.
|
||||
set -eu
|
||||
|
||||
repo_root=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
DEV_TEST=$repo_root/scripts/dev-test.sh
|
||||
|
||||
fail=0
|
||||
pass=0
|
||||
|
||||
ok() {
|
||||
pass=$((pass + 1))
|
||||
printf 'ok - %s\n' "$1"
|
||||
}
|
||||
|
||||
bad() {
|
||||
fail=$((fail + 1))
|
||||
printf 'FAIL - %s\n' "$1"
|
||||
if [ -n "${2:-}" ]; then
|
||||
printf '%s\n' "$2" | sed 's/^/ /'
|
||||
fi
|
||||
}
|
||||
|
||||
work=$(mktemp -d "${TMPDIR:-/tmp}/codewhale-dev-test.XXXXXX")
|
||||
cleanup() { rm -rf "$work"; }
|
||||
trap cleanup EXIT INT HUP TERM
|
||||
|
||||
FAKEBIN=$work/bin
|
||||
mkdir -p "$FAKEBIN"
|
||||
NEW_WT=$work/new-wt
|
||||
mkdir -p "$NEW_WT"
|
||||
|
||||
cat >"$FAKEBIN/cargo" <<'EOF'
|
||||
#!/bin/sh
|
||||
printf 'CARGO:%s\n' "$*"
|
||||
printf 'CARGO_BUILD_BUILD_DIR=%s\n' "${CARGO_BUILD_BUILD_DIR-<unset>}"
|
||||
printf 'RUSTC_WRAPPER=%s\n' "${RUSTC_WRAPPER-<unset>}"
|
||||
printf 'CARGO_INCREMENTAL=%s\n' "${CARGO_INCREMENTAL-<unset>}"
|
||||
printf 'RUST_MIN_STACK=%s\n' "${RUST_MIN_STACK-<unset>}"
|
||||
exit 0
|
||||
EOF
|
||||
chmod +x "$FAKEBIN/cargo"
|
||||
|
||||
BASE_PATH=$FAKEBIN:/usr/bin:/bin
|
||||
|
||||
run_dev_test() {
|
||||
# Leading KEY=VAL pairs are extra env; the rest are script arguments.
|
||||
_extra=$work/extra-env
|
||||
: >"$_extra"
|
||||
while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
*=*)
|
||||
printf '%s\n' "$1" >>"$_extra"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
# env -i + env-file keeps values with spaces intact and never treats
|
||||
# --list as an env(1) option.
|
||||
set -- /bin/sh "$DEV_TEST" "$@"
|
||||
while IFS= read -r _line; do
|
||||
set -- "$_line" "$@"
|
||||
done <"$_extra"
|
||||
env -i \
|
||||
PATH="$BASE_PATH" \
|
||||
HOME="$work/home" \
|
||||
CODEWHALE_DEV_CACHE_QUIET=1 \
|
||||
CODEWHALE_DEV_CACHE_REPO_ROOT="$NEW_WT" \
|
||||
CODEWHALE_CACHE_ROOT="$work/cache" \
|
||||
"$@"
|
||||
}
|
||||
|
||||
contains() {
|
||||
printf '%s' "$1" | grep -qF -- "$2"
|
||||
}
|
||||
|
||||
# --list names every workspace crate family, including the ones the old
|
||||
# mapper dropped on the floor.
|
||||
list_out=$(run_dev_test --list)
|
||||
for needle in \
|
||||
"codewhale-agent" \
|
||||
"codewhale-app-server" \
|
||||
"codewhale-build-support" \
|
||||
"codewhale-command-contract" \
|
||||
"codewhale-hooks" \
|
||||
"codewhale-lane" \
|
||||
"codewhale-mcp" \
|
||||
"codewhale-release" \
|
||||
"codewhale-state" \
|
||||
"codewhale-telemetry" \
|
||||
"codewhale-workflow" \
|
||||
"codewhale-workflow-js" \
|
||||
"codewhale-tui --lib" \
|
||||
"codewhale-tui --test pty"
|
||||
do
|
||||
if contains "$list_out" "$needle"; then
|
||||
ok "--list mentions $needle"
|
||||
else
|
||||
bad "--list mentions $needle" "$list_out"
|
||||
fi
|
||||
done
|
||||
|
||||
# Narrow routing: libtest forced so we assert cargo test argv.
|
||||
out=$(run_dev_test CODEWHALE_DEV_NEXTEST=0 config)
|
||||
if contains "$out" "+ cargo test -p codewhale-config --lib --locked" \
|
||||
&& contains "$out" "test -p codewhale-config --lib --locked"; then
|
||||
ok "area config maps to codewhale-config --lib"
|
||||
else
|
||||
bad "area config maps to codewhale-config --lib" "$out"
|
||||
fi
|
||||
|
||||
out=$(run_dev_test CODEWHALE_DEV_NEXTEST=0 crates/tui/src/elapsed.rs)
|
||||
if contains "$out" "test -p codewhale-tui --lib --locked elapsed::"; then
|
||||
ok "path crates/tui/src/elapsed.rs invents elapsed::"
|
||||
else
|
||||
bad "path crates/tui/src/elapsed.rs invents elapsed::" "$out"
|
||||
fi
|
||||
|
||||
out=$(run_dev_test CODEWHALE_DEV_NEXTEST=0 crates/workflow-js/src/eval.rs)
|
||||
if contains "$out" "test -p codewhale-workflow-js --lib --locked"; then
|
||||
ok "path crates/workflow-js maps to codewhale-workflow-js"
|
||||
else
|
||||
bad "path crates/workflow-js maps to codewhale-workflow-js" "$out"
|
||||
fi
|
||||
|
||||
out=$(run_dev_test CODEWHALE_DEV_NEXTEST=0 crates/app-server/src/lib.rs)
|
||||
if contains "$out" "test -p codewhale-app-server --lib --locked"; then
|
||||
ok "path crates/app-server maps to codewhale-app-server"
|
||||
else
|
||||
bad "path crates/app-server maps to codewhale-app-server" "$out"
|
||||
fi
|
||||
|
||||
out=$(run_dev_test CODEWHALE_DEV_NEXTEST=0 tui-pty qa_pty)
|
||||
if contains "$out" "test -p codewhale-tui --test pty --locked qa_pty"; then
|
||||
ok "tui-pty maps to the pty harness"
|
||||
else
|
||||
bad "tui-pty maps to the pty harness" "$out"
|
||||
fi
|
||||
|
||||
# Unknown area fails closed.
|
||||
rc=0
|
||||
out=$(run_dev_test CODEWHALE_DEV_NEXTEST=0 not-a-crate 2>&1) || rc=$?
|
||||
if [ "$rc" -ne 0 ] && contains "$out" "unknown area"; then
|
||||
ok "unknown area fails closed"
|
||||
else
|
||||
bad "unknown area fails closed" "rc=$rc $out"
|
||||
fi
|
||||
|
||||
# New worktree applies the isolated build-dir (compile-time topology).
|
||||
out=$(run_dev_test CODEWHALE_DEV_NEXTEST=0 config)
|
||||
if contains "$out" "CARGO_BUILD_BUILD_DIR=$work/cache/build/{workspace-path-hash}" \
|
||||
&& contains "$out" '--config build.build-dir = "'; then
|
||||
ok "dev-test applies isolated build-dir on a new worktree"
|
||||
else
|
||||
bad "dev-test applies isolated build-dir on a new worktree" "$out"
|
||||
fi
|
||||
if contains "$out" "RUST_MIN_STACK=16777216"; then
|
||||
ok "dev-test sets RUST_MIN_STACK when unset"
|
||||
else
|
||||
bad "dev-test sets RUST_MIN_STACK when unset" "$out"
|
||||
fi
|
||||
if contains "$out" "RUSTC_WRAPPER=<unset>"; then
|
||||
ok "dev-test does not wrap rustc on the incremental default"
|
||||
else
|
||||
bad "dev-test does not wrap rustc on the incremental default" "$out"
|
||||
fi
|
||||
|
||||
# CODEWHALE_DEV_CACHE=0 really disables the topology.
|
||||
out=$(run_dev_test CODEWHALE_DEV_NEXTEST=0 CODEWHALE_DEV_CACHE=0 config)
|
||||
if contains "$out" "CARGO_BUILD_BUILD_DIR=<unset>" \
|
||||
&& ! contains "$out" '--config build.build-dir'; then
|
||||
ok "CODEWHALE_DEV_CACHE=0 skips the cache topology"
|
||||
else
|
||||
bad "CODEWHALE_DEV_CACHE=0 skips the cache topology" "$out"
|
||||
fi
|
||||
|
||||
# nextest is used when cargo-nextest is on PATH (test-runtime).
|
||||
printf '%s\n' '#!/bin/sh' 'exit 0' >"$FAKEBIN/cargo-nextest"
|
||||
chmod +x "$FAKEBIN/cargo-nextest"
|
||||
out=$(run_dev_test tui elapsed::)
|
||||
if contains "$out" "+ cargo nextest run -p codewhale-tui --lib --locked elapsed::" \
|
||||
&& contains "$out" "nextest run -p codewhale-tui --lib --locked elapsed::"; then
|
||||
ok "nextest is used when cargo-nextest is installed"
|
||||
else
|
||||
bad "nextest is used when cargo-nextest is installed" "$out"
|
||||
fi
|
||||
|
||||
out=$(run_dev_test CODEWHALE_DEV_NEXTEST=0 tui elapsed::)
|
||||
if contains "$out" "+ cargo test -p codewhale-tui --lib --locked elapsed::" \
|
||||
&& contains "$out" "test -p codewhale-tui --lib --locked elapsed::"; then
|
||||
ok "CODEWHALE_DEV_NEXTEST=0 forces cargo test"
|
||||
else
|
||||
bad "CODEWHALE_DEV_NEXTEST=0 forces cargo test" "$out"
|
||||
fi
|
||||
|
||||
# Forced nextest without the binary fails closed instead of silent cargo.
|
||||
rm -f "$FAKEBIN/cargo-nextest"
|
||||
rc=0
|
||||
out=$(run_dev_test CODEWHALE_DEV_NEXTEST=1 config 2>&1) || rc=$?
|
||||
if [ "$rc" -ne 0 ] && contains "$out" "cargo-nextest is not on PATH"; then
|
||||
ok "CODEWHALE_DEV_NEXTEST=1 without nextest fails closed"
|
||||
else
|
||||
bad "CODEWHALE_DEV_NEXTEST=1 without nextest fails closed" "rc=$rc $out"
|
||||
fi
|
||||
|
||||
if [ "$fail" -eq 0 ]; then
|
||||
printf 'dev-test.test.sh: all %s checks passed\n' "$pass"
|
||||
exit 0
|
||||
fi
|
||||
printf 'dev-test.test.sh: %s/%s checks failed\n' "$fail" "$((pass + fail))" >&2
|
||||
exit 1
|
||||
Reference in New Issue
Block a user