Files
rustfs/scripts/test_python_bin.sh
唐小鸭andGitHub 1dcdfe4817 build(make): resolve a Python 3.11+ interpreter for guard scripts (#7004)
scripts/check_test_wiring.py and scripts/check_security_coverage.py import
tomllib, which landed in Python 3.11. macOS ships /usr/bin/python3 at 3.9, so
`make pre-commit` failed on a clean machine with `ModuleNotFoundError: No
module named 'tomllib'` in test-wiring-check, even though the checkers
themselves are fine.

Add scripts/python_bin.sh, which resolves an interpreter (explicit
RUSTFS_PYTHON, then python3.14..3.11/python3/python on PATH, then a
`uv run --python 3.12 --no-project` fallback) and execs it, failing with the
concrete remediation when nothing usable exists. Route the Make call sites
through RUSTFS_PYTHON_BIN. CI workflows keep calling python3 directly because
their runners already provide 3.11+.
2026-09-01 19:09:36 +08:00

82 lines
3.2 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/sh
# Tests for scripts/python_bin.sh: the interpreter resolver that keeps
# `make pre-commit` working on machines whose `python3` is older than 3.11
# (notably macOS, which ships /usr/bin/python3 at 3.9).
set -eu
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
REPO_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)
RESOLVER="$REPO_ROOT/scripts/python_bin.sh"
TMP_ROOT=$(mktemp -d)
trap 'rm -rf "$TMP_ROOT"' EXIT HUP INT TERM
fail() {
echo "❌ $1" >&2
exit 1
}
# A resolved interpreter must be able to import tomllib, which is the module
# the repository's checkers need and the reason the resolver exists.
"$RESOLVER" -c 'import tomllib, sys; assert sys.version_info >= (3, 11)' \
|| fail "resolver produced an interpreter without tomllib"
"$RESOLVER" --print-interpreter >/dev/null \
|| fail "--print-interpreter failed"
# An explicit RUSTFS_PYTHON override wins over PATH discovery.
selected=$("$RESOLVER" --print-interpreter)
RUSTFS_PYTHON="$selected" "$RESOLVER" -c 'import tomllib' \
|| fail "RUSTFS_PYTHON override rejected a valid interpreter"
# A too-old RUSTFS_PYTHON must fail loudly instead of silently falling back to
# a newer interpreter, so the operator learns their override is unusable.
mkdir -p "$TMP_ROOT/bin"
cat > "$TMP_ROOT/bin/fake-old-python" <<'STUB'
#!/bin/sh
# Pretends to be Python 3.9: the version probe exits non-zero.
exit 1
STUB
chmod +x "$TMP_ROOT/bin/fake-old-python"
if RUSTFS_PYTHON="$TMP_ROOT/bin/fake-old-python" "$RESOLVER" -c 'pass' \
>"$TMP_ROOT/old.out" 2>"$TMP_ROOT/old.err"; then
fail "resolver accepted a too-old RUSTFS_PYTHON"
fi
grep -q 'older than Python' "$TMP_ROOT/old.err" \
|| fail "too-old RUSTFS_PYTHON did not explain the version requirement"
# A missing RUSTFS_PYTHON must be reported as such.
if RUSTFS_PYTHON="$TMP_ROOT/bin/definitely-absent" "$RESOLVER" -c 'pass' \
>"$TMP_ROOT/absent.out" 2>"$TMP_ROOT/absent.err"; then
fail "resolver accepted a nonexistent RUSTFS_PYTHON"
fi
grep -q 'is not an executable command' "$TMP_ROOT/absent.err" \
|| fail "nonexistent RUSTFS_PYTHON did not explain what was wrong"
# With no usable interpreter and no uv on PATH, the failure must name the fix
# rather than surfacing a bare ModuleNotFoundError from a 3.9 interpreter.
cat > "$TMP_ROOT/bin/python3" <<'STUB'
#!/bin/sh
exit 1
STUB
chmod +x "$TMP_ROOT/bin/python3"
SANDBOX_PATH="$TMP_ROOT/bin:/usr/bin:/bin"
if PATH="$SANDBOX_PATH" command -v uv >/dev/null 2>&1; then
# uv is reachable even from the sandbox PATH, so the resolver would
# legitimately fall back to it instead of failing. Skip this case.
echo "️ uv is on the sandbox PATH; skipping the no-interpreter case"
else
if PATH="$SANDBOX_PATH" "$RESOLVER" -c 'pass' \
>"$TMP_ROOT/none.out" 2>"$TMP_ROOT/none.err"; then
fail "resolver succeeded with no usable interpreter on PATH"
fi
grep -q 'No Python 3.11+ interpreter found' "$TMP_ROOT/none.err" \
|| fail "missing-interpreter failure did not name the requirement"
grep -q 'RUSTFS_PYTHON=' "$TMP_ROOT/none.err" \
|| fail "missing-interpreter failure did not point at the override"
fi
echo "✅ scripts/python_bin.sh resolver checks passed"