Files
computer-playbook/scripts/meta/env/load.sh
T
kevinveenbirkenbachandClaude Opus 4.7 3fe215aaa6 fix(test-runner): source load.sh + prefer project venv over ambient VIRTUAL_ENV
`make test-unit` (docker runner) reached run.sh inside the container via
`bash --login`, which never sources the project's env-loader. PYTHON stayed
unset, so the test invocation fell back to the system python3 — which has
none of the runtime deps (ruamel, ansible, bcrypt, requests, certifi,
humanfriendly), producing 132+ ModuleNotFoundError errors.

run.sh now sources scripts/meta/env/load.sh itself (idempotent via
INFINITO_ENV_LOADED), so the env layer applies regardless of how the shell
was spawned.

While load.sh's detect.sh (now scripts/meta/env/python.sh) correctly walks
/opt/venvs and ~/.venvs to find the venv, an ambient VIRTUAL_ENV from a
different project (e.g. /root/.venvs/pkgmgr in pkgmgr's container) would
hijack the resolution. python.sh now scans the project-named venv candidates
first and only falls back to VIRTUAL_ENV when no project venv exists.

Also moves scripts/meta/python/detect.sh to scripts/meta/env/python.sh so the
env-related helpers live under one directory; updates the load.sh source
pragma and the lint-test path that scans it for INFINITO_* registrations.

`make test-unit` goes from 1262 tests / 132 errors to 1999 tests / 0 errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 14:55:10 +02:00

68 lines
2.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# shellcheck shell=bash
#
# Sources `.env` (auto-generates via `python -m cli.meta.env` if missing)
# with setdefault semantics: caller-set values win over `.env` defaults.
# Idempotent (INFINITO_ENV_LOADED). INFINITO_ENV_GENERATING short-circuits
# re-entry from generator subshells (BASH_ENV would otherwise recurse).
_infinito_env_repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
_infinito_env_dotenv="${_infinito_env_repo_root}/.env"
# Re-resolve PYTHON + PATH on every source so a venv created mid-chain takes over.
# shellcheck source=scripts/meta/env/python.sh
source "${_infinito_env_repo_root}/scripts/meta/env/python.sh"
if [[ -n "${VENV:-}" && -d "${VENV%/}/bin" ]]; then
case ":${PATH:-}:" in
*:"${VENV%/}/bin":*) ;;
*) export PATH="${VENV%/}/bin${PATH:+:${PATH}}" ;;
esac
fi
if [[ "${INFINITO_ENV_LOADED:-}" == "1" ]]; then # nocheck: env-loader-internal-guard
unset _infinito_env_repo_root _infinito_env_dotenv
return 0
fi
if [[ "${INFINITO_ENV_GENERATING:-}" == "1" ]]; then # nocheck: env-loader-internal-guard
unset _infinito_env_repo_root _infinito_env_dotenv
return 0
fi
if [[ ! -f "${_infinito_env_dotenv}" ]]; then
(
cd "${_infinito_env_repo_root}" || exit 1
export INFINITO_ENV_GENERATING=1
"${PYTHON}" -m cli.meta.env
) >&2
fi
# Snapshot caller-set values, restore them after the bulk source (setdefault).
declare -A _infinito_env_preserved=()
while IFS= read -r _infinito_env_line; do
case "${_infinito_env_line}" in
"" | "#"*) continue ;;
esac
_infinito_env_key="${_infinito_env_line%%=*}"
if [[ "${_infinito_env_key}" == "${_infinito_env_line}" ]]; then
continue
fi
if [[ -n "${!_infinito_env_key:-}" ]]; then
_infinito_env_preserved["${_infinito_env_key}"]="${!_infinito_env_key}"
fi
done <"${_infinito_env_dotenv}"
unset _infinito_env_line _infinito_env_key
set -a
# shellcheck disable=SC1090
source "${_infinito_env_dotenv}"
set +a
for _infinito_env_key in "${!_infinito_env_preserved[@]}"; do
declare -gx "${_infinito_env_key}=${_infinito_env_preserved[${_infinito_env_key}]}"
done
unset _infinito_env_key _infinito_env_preserved
export INFINITO_ENV_LOADED="1"
unset _infinito_env_repo_root _infinito_env_dotenv