install_erplibre.sh bâtissait .venv.erplibre avec le python3 du système, quelle que soit sa version : un 3.10 y donnait un venv que l'outillage ne sait pas charger. Il délègue à install_venv.sh, qui obtient la version par mise, pyenv ou la distribution, et rebâtit un venv hors service. Le PATCH ne borne que le venv d'Odoo, dont le pyproject exige « >=3.12.10,<3.13 » : l'exiger ailleurs écartait un Python de distribution d'un cran en retard — NixOS 25.11 livre 3.14.2 — et faisait compiler CPython pour rien. Le module NixOS déclare désormais les DEUX Python, substitués depuis les fichiers de version. Vérifié : 15 tests sur des venvs factices, conservés, rebâtis ou refusés selon leur état, et un chemin sans pyvenv.cfg garde son contenu. --- EN --- install_erplibre.sh built .venv.erplibre with the system python3, whatever its version: a 3.10 gave a venv the tooling cannot load. It delegates to install_venv.sh, which obtains the version through mise, pyenv or the distribution, and rebuilds a venv out of service. The PATCH bounds only Odoo's venv, whose pyproject requires ">=3.12.10,<3.13": requiring it elsewhere turned away a distribution Python one step behind — NixOS 25.11 ships 3.14.2 — and compiled CPython for nothing. The NixOS module now declares BOTH Pythons, substituted from the version files. Checked: 15 tests on stub venvs, kept, rebuilt or refused by their state, and a path without pyvenv.cfg keeps its content. Assisted-by: Claude Opus 5
176 lines
6.9 KiB
Bash
Executable file
176 lines
6.9 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
# Check if all 3 parameters are present
|
|
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then
|
|
echo "Error: One or more parameters are missing."
|
|
echo "Usage: $0 <Context> <Venv_Path> <Python_Version>"
|
|
exit 1
|
|
fi
|
|
|
|
# Assign arguments to variables
|
|
CONTEXT="$1"
|
|
# Sans « / » final : « rm -rf lien/ » viderait la cible d'un lien.
|
|
VENV_PATH="${2%"${2##*[!/]}"}"
|
|
PYTHON_VERSION="$3"
|
|
if [ -z "${VENV_PATH}" ]; then
|
|
echo "Error: Venv_Path '$2' designates the root."
|
|
exit 1
|
|
fi
|
|
|
|
# Display variables (for verification)
|
|
echo "Context: $CONTEXT"
|
|
echo "Venv Path: $VENV_PATH"
|
|
echo "Python Version: $PYTHON_VERSION"
|
|
|
|
# Le CHOIX du fournisseur (mise ou pyenv) vit dans la bibliothèque : ce script
|
|
# ne connaît qu'un chemin d'interpréteur.
|
|
# shellcheck source=script/install/lib_python_provider.sh
|
|
. ./script/install/lib_python_provider.sh
|
|
|
|
# Ce qui borne le PATCH, et pour qui.
|
|
#
|
|
# Le venv d'Odoo est contraint par son pyproject (« >=3.12.10,<3.13 ») : un
|
|
# patch inférieur y serait refusé par Poetry. Rien n'épingle celui de
|
|
# l'outillage — exiger le patch y écarte le Python des distributions dès
|
|
# qu'il est d'un cran en retard, et force pyenv à compiler CPython pour rien.
|
|
EXIGENCE="patch"
|
|
[ "${CONTEXT}" = "ERPLibre" ] && EXIGENCE="mineure"
|
|
|
|
# Version RÉELLE d'un venv : celle que rend son interpréteur, jamais celle
|
|
# qu'annonce pyvenv.cfg, figée à la création et que rien ne revalide. Rien
|
|
# n'est rendu quand bin/python ne s'exécute plus — un venv bâti sur un CPython
|
|
# depuis retiré garde un lien mort, et c'est justement un venv à rebâtir.
|
|
el_venv_python_version() {
|
|
local py="$1/bin/python"
|
|
[ -x "${py}" ] || return 1
|
|
"${py}" -c 'import platform;print(platform.python_version())' 2> /dev/null
|
|
}
|
|
|
|
# Le venv est-il HORS SERVICE — non pas d'une autre version, mais inutilisable
|
|
# tel quel ? Ce qui suit ne se répare pas : on rebâtit, quel que soit l'appelant.
|
|
el_venv_hors_service() {
|
|
local py="$1/bin/python"
|
|
if [[ ! -f "$1/pyvenv.cfg" ]]; then
|
|
echo "aucun pyvenv.cfg"
|
|
elif [[ -z "$(el_venv_python_version "$1")" ]]; then
|
|
echo "son interpreteur ne s'execute plus"
|
|
elif [[ ! -f "$1/bin/activate" ]] || ! "${py}" -m pip --version > /dev/null 2>&1; then
|
|
# Ce que laisse un « python -m venv » sans ensurepip.
|
|
echo "bin/activate ou pip manquant"
|
|
fi
|
|
}
|
|
|
|
# Le venv tourne, mais pas sur la version demandée. La version est celle que
|
|
# rend bin/python, pas celle de pyvenv.cfg, figée à la création. Compatible et
|
|
# non identique : un python de distribution d'un patch plus récent convient, et
|
|
# l'égalité stricte rebâtirait à chaque appel.
|
|
el_venv_version_autre() {
|
|
if ! el_python_is_compatible \
|
|
"$1/bin/python" "${PYTHON_VERSION}" "${EXIGENCE}"; then
|
|
echo "bin/python en $(el_venv_python_version "$1"), ${PYTHON_VERSION} exige"
|
|
fi
|
|
}
|
|
|
|
# Ce qui oblige à rebâtir, ou rien.
|
|
#
|
|
# Une version qui diffère ne vaut destruction que pour le venv d'OUTILLAGE :
|
|
# le rebâtir coûte une installation pip, quand celui d'Odoo représente une
|
|
# installation Poetry entière — des centaines de paquets, dont certains se
|
|
# compilent. Un écart de patch ne l'empêche pas de servir ; on le dit, et on le
|
|
# laisse. Hors service, en revanche, il ne sert plus personne.
|
|
el_venv_a_rebatir() {
|
|
local cause
|
|
cause="$(el_venv_hors_service "$1")"
|
|
if [[ -n "${cause}" ]]; then
|
|
echo "${cause}"
|
|
return
|
|
fi
|
|
cause="$(el_venv_version_autre "$1")"
|
|
if [[ -n "${cause}" ]] && [[ "${CONTEXT}" == "ERPLibre" ]]; then
|
|
echo "${cause}"
|
|
fi
|
|
}
|
|
|
|
# Un checkout MONTÉ depuis une autre machine porte le venv de cette machine.
|
|
# Son interpréteur ne démarre pas ici — un CPython précompilé cherche sa
|
|
# bibliothèque standard sous le préfixe de sa construction —, ce qui le fait
|
|
# passer pour défectueux. Le détruire effacerait, à travers le réseau,
|
|
# l'installation de la machine à qui il appartient.
|
|
# findmnt vient d'util-linux : absent ailleurs, le contrôle s'abstient plutôt
|
|
# que de refuser à tort.
|
|
el_venv_est_distant() {
|
|
local fs
|
|
command -v findmnt > /dev/null 2>&1 || return 1
|
|
fs="$(findmnt -n -o FSTYPE --target "$1" 2> /dev/null)"
|
|
case "${fs}" in
|
|
fuse* | sshfs | nfs* | cifs | smb*) return 0 ;;
|
|
*) return 1 ;;
|
|
esac
|
|
}
|
|
|
|
PYTHON_EXEC="$(el_python_exec "${PYTHON_VERSION}" "${EXIGENCE}")"
|
|
if [[ -z "${PYTHON_EXEC}" ]] || [[ ! -x "${PYTHON_EXEC}" ]]; then
|
|
echo "Aucun interpreteur Python ${PYTHON_VERSION} n'a pu etre obtenu."
|
|
echo " Fournisseur demande : ${EL_PYTHON_PROVIDER:-auto}"
|
|
if command -v mise > /dev/null 2>&1; then
|
|
echo " Voir : mise install python@${PYTHON_VERSION} (reseau requis)"
|
|
else
|
|
echo " Voir 'make install_mise', ou installez pyenv."
|
|
fi
|
|
exit 1
|
|
fi
|
|
echo "Interpreteur retenu : ${PYTHON_EXEC}"
|
|
|
|
# L'interpréteur est obtenu AVANT toute destruction : un provisionnement en
|
|
# échec laisse le venv en place.
|
|
if [[ -d ${VENV_PATH} ]]; then
|
|
REASON="$(el_venv_a_rebatir "${VENV_PATH}")"
|
|
CONSERVE="$(el_venv_version_autre "${VENV_PATH}")"
|
|
if [[ -z "${REASON}" ]] && [[ -n "${CONSERVE}" ]]; then
|
|
echo "Virtual environment ${VENV_PATH} conserve : ${CONSERVE}."
|
|
echo " Le rebatir refait toute son installation. Si vous le voulez :"
|
|
echo " rm -rf ${VENV_PATH} puis relancez."
|
|
fi
|
|
# rmdir n'écarte qu'un répertoire vide, ce que laisse une création
|
|
# interrompue ; seul un pyvenv.cfg autorise le « rm -rf ».
|
|
if [[ -n "${REASON}" ]] && ! rmdir "${VENV_PATH}" 2> /dev/null; then
|
|
if [[ ! -f "${VENV_PATH}/pyvenv.cfg" ]]; then
|
|
echo "Refus de detruire ${VENV_PATH} : ce n'est pas un venv (${REASON})."
|
|
echo " Ecartez-le vous-meme, puis relancez."
|
|
exit 1
|
|
fi
|
|
if el_venv_est_distant "${VENV_PATH}"; then
|
|
echo "Refus de detruire ${VENV_PATH} : il est sur un systeme de"
|
|
echo " fichiers monte a distance, donc il appartient a une autre"
|
|
echo " machine (${REASON} vu d'ici)."
|
|
echo " Installez SUR cette machine-la, pas au travers du montage."
|
|
exit 1
|
|
fi
|
|
echo "DESTRUCTION de ${VENV_PATH} : ${REASON}."
|
|
echo " Ce qui y a ete pose a la main part avec lui ; il est rebati."
|
|
if ! rm -rf "${VENV_PATH}"; then
|
|
echo "Destruction de ${VENV_PATH} en echec, probablement faute de droits :"
|
|
echo " le venv est peut-etre partiellement detruit. Rien n'est rebati."
|
|
echo " Corrigez les droits, puis : rm -rf ${VENV_PATH} et relancez."
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [[ ! -d ${VENV_PATH} ]]; then
|
|
echo -e "\n---- Create Virtual environment Python ----"
|
|
if ! "${PYTHON_EXEC}" -m venv "${VENV_PATH}"; then
|
|
echo "Virtual environment, error when creating ${VENV_PATH}"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Contrôle final : l'appelant enchaîne sur ce venv, un 0 doit le garantir.
|
|
# Hors service seulement : un venv d'une autre version qu'on vient de conserver
|
|
# sciemment reste utilisable.
|
|
REASON="$(el_venv_hors_service "${VENV_PATH}")"
|
|
if [[ ! -d ${VENV_PATH} ]] || [[ -n "${REASON}" ]]; then
|
|
echo "Virtual environment ${VENV_PATH} inutilisable : ${REASON:-absent}."
|
|
exit 1
|
|
fi
|
|
echo "Virtual environment ${VENV_PATH} pret."
|