Files
computer-playbook/scripts/install/venv.sh
T
kevinveenbirkenbachandClaude Opus 4.7 00c4246c3a refactor(env): introduce INFINITO_VENV_DIR SPOT, fix dev image build
Adds INFINITO_VENV_DIR=/opt/venvs/infinito to default.env (registered
in passthrough's STATIC_KEYS so make dotenv propagates it to .env) and
threads it through the build chain: compose.yml forwards it as a build
arg; scripts/image/push.sh asserts and --build-args it; the Dockerfile
declares the matching ARG/ENV and derives PYTHON/PIP/PATH from the
variable. scripts/meta/env/python.sh now prefers the value when set
before its fallback discovery so the SPOT is effective in env
resolution.

Fixes the dev image build regression where 'infinito --version' in
scripts/docker/entry.sh exited 127. Root cause: the Dockerfile RUN
SHELL uses bash -lc, which sources /etc/profile and resets PATH to
the Debian default, dropping ${INFINITO_VENV_DIR}/bin from it. The
fix invokes the script via its absolute path "${INFINITO_VENV_DIR}/bin/infinito"
so the post-install version check no longer depends on a PATH that
the login-shell init has just clobbered.

scripts/lint/wrapper.sh's existing PATH-reset note now references the
variable instead of the literal path. test-install-make.yml and
test-install-pkgmgr.yml read INFINITO_VENV_DIR from default.env up
front, pass it into their pkgmgr containers, and source the venv
activate script via the variable.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 22:12:19 +02:00

74 lines
2.5 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# ------------------------------------------------------------
# 🐍 Virtualenv bootstrap & setup
#
# This script is responsible for creating the Python virtualenv
# used by the entire Infinito.Nexus toolchain.
#
# Important design rule:
# ❗ The venv Python interpreter CANNOT be used before the venv exists.
# ❗ Therefore we must bootstrap using system python3 first.
#
# Lifecycle:
# 1) Use system python3 to create the venv
# 2) Afterwards, Makefile provides PYTHON=${VENV}/bin/python
# 3) All tooling runs inside the venv from then on
#
# This avoids chicken-and-egg failures in CI and on fresh machines.
# ------------------------------------------------------------
: "${VENV:?VENV not set; source scripts/meta/env/load.sh}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
DEV_PYTHON_INSTALLER="${REPO_ROOT}/roles/dev-python/files/install.sh"
install_venv() {
if [[ ! -f "${DEV_PYTHON_INSTALLER}" ]]; then
echo "❌ Missing installer: ${DEV_PYTHON_INSTALLER}" >&2
return 1
fi
# 🛠 Bootstrap interpreter (system Python, outside of venv)
# Used ONLY to CREATE the virtualenv.
local bootstrap_python
bootstrap_python="$(bash "${DEV_PYTHON_INSTALLER}" print)"
# 📦 Target interpreter inside the venv (may not exist yet!)
local venv_python="${VENV}/bin/python"
echo "🐍 Virtualenv target : ${VENV}"
echo "🛠 Bootstrap python : ${bootstrap_python}"
echo "🎯 Venv python target : ${venv_python}"
echo
# Probe dirname(VENV) so a non-writable legacy path can't trigger a spurious sudo (fatal under no_new_privs sandboxes).
local venv_parent
venv_parent="$(dirname "${VENV}")"
if [[ -n "${VIRTUAL_ENV:-}" && "${VIRTUAL_ENV}" == "${VENV}" ]]; then
: # active venv matches the target; nothing to prepare
elif [[ -d "${venv_parent}" && -w "${venv_parent}" ]]; then
: # venv parent exists and is writable; nothing to prepare
elif [[ "${EUID:-$(id -u)}" -eq 0 ]]; then
mkdir -p "${venv_parent}"
else
sudo mkdir -p "${venv_parent}"
sudo chown "${USER:-$(whoami)}" "${venv_parent}"
fi
# ------------------------------------------------------------
# Create venv if missing
# ------------------------------------------------------------
if [[ ! -x "${venv_python}" ]]; then
echo "→ Creating virtualenv ${VENV}"
"${bootstrap_python}" -m venv "${VENV}"
echo "✅ Virtualenv created"
else
echo "→ Virtualenv already exists"
fi
}
install_venv