[UPD] install : le venv d'outillage passe en Python 3.14.7
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
This commit is contained in:
parent
7cdcd8a07a
commit
42e10bcced
25 changed files with 739 additions and 78 deletions
|
|
@ -36,9 +36,31 @@ Un seul fichier décide : `script/install/lib_python_provider.sh`. mise n'est
|
|||
jamais installé automatiquement — `make install_mise` porte cette décision.
|
||||
Pas de binaire mise pour s390x à ce jour : cette architecture reste sur pyenv.
|
||||
|
||||
## Le Python de l'outillage
|
||||
|
||||
`conf/python-erplibre-version` (3.14.7) donne l'interpréteur de
|
||||
`.venv.erplibre`, le venv d'outillage, distinct du venv Odoo (3.12.10 pour
|
||||
Odoo 18.0). C'est la seule version que `script/` vise : là où une distribution
|
||||
ne la porte pas, pyenv la compile.
|
||||
|
||||
Le PATCH ne borne que le venv d'Odoo, dont le pyproject exige
|
||||
`>=3.12.10,<3.13`. Pour l'outillage, la majeure.mineure suffit : exiger le
|
||||
patch écarterait le Python d'une distribution d'un cran en retard — NixOS 25.11
|
||||
livre 3.14.2 — et ferait compiler CPython pour rien.
|
||||
|
||||
`install_erplibre.sh` passe par `install_venv.sh`, donc par
|
||||
`EL_PYTHON_PROVIDER`. Un venv dont `bin/python` n'est pas compatible (même
|
||||
majeure.mineure, patch au moins égal) est DÉTRUIT puis rebâti : ce qui y avait
|
||||
été posé à la main part avec lui. Le venv d'Odoo, lui, n'est rebâti que s'il
|
||||
est HORS SERVICE : une simple différence de version le laisse en place, parce
|
||||
que le rebâtir refait une installation Poetry entière. Un répertoire sans
|
||||
`pyvenv.cfg` n'est jamais effacé.
|
||||
|
||||
Le hook `pre-commit` relaie `script/analyse/check_python_version.py` : il
|
||||
signale le source qui ne parse pas sous cette version, sans bloquer, et dit
|
||||
quand aucun interpréteur de cette version n'était là pour vérifier.
|
||||
L'image Docker de production bâtit `.venv.erplibre` sur le Python d'Odoo de son
|
||||
image de base, et s'arrête si ce Python ne sait pas lire `script/`.
|
||||
|
||||
## Paquets Python
|
||||
|
||||
|
|
|
|||
|
|
@ -156,6 +156,10 @@ au [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|||
- A VM deployed with the cache upstream cut — QEMU form, Proxmox VE, or `deploy_qemu.py --offline` — has npm's security audit turned off (`NPM_CONFIG_AUDIT=false`): it queries a remote service no cache can replay, and failed on every offline install. An online VM keeps its audit
|
||||
- Verifying a downloaded image no longer needs `--verify`: it runs by default for every distribution that publishes a sum, and `--no-verify` is what skips it — to be kept for offline runs, where a substituted image would otherwise pass unremarked
|
||||
- `--bios` is refused on an image with no BIOS boot sector, and says why. Forced there, it gave a VM reported « running » with a silent console — the very failure that flag exists to avoid elsewhere
|
||||
- The tooling virtual environment `.venv.erplibre` runs Python 3.14.7, independently of the Odoo one (3.12.10 for Odoo 18.0). `install_erplibre.sh` builds it through `install_venv.sh` and `EL_PYTHON_PROVIDER` instead of the system `python3`
|
||||
- `.venv.erplibre` on an incompatible Python is DELETED and rebuilt; whatever was installed in it by hand goes with it. Odoo's venv is kept when it merely differs in version, and rebuilt only when it is unusable: rebuilding it redoes a whole Poetry install. A directory without `pyvenv.cfg` is never deleted
|
||||
- The production Docker image builds `.venv.erplibre` on Odoo's Python and stops when that Python cannot parse `script/`
|
||||
- The PATCH bounds only Odoo's venv, whose pyproject requires `>=3.12.10,<3.13`. For the tooling one, the major.minor is enough: requiring the patch turned away a distribution's Python one step behind — NixOS 25.11 ships 3.14.2 where conf asks 3.14.7 — and made pyenv COMPILE CPython for a difference nothing needs
|
||||
- `make format` picks the formatter from each file's context: an Odoo module keeps isort and black on `py37`, the series still supported going down that far, while this repository's own tooling goes through ruff, configured once in `.ruff.toml`. ruff follows CPython's versions, where black 24.8.0 stops at `py313`, and its import sorting replaces isort; it is also what the OCA standard uses since it left black
|
||||
- The repositories that Google Repo checks out under `script/` are excluded from that formatting, a named path included: reformatting them would write in someone else's history. `target-version` stays at `py310` there, because the git hooks carry `#!/usr/bin/env python3` and a distribution still ships 3.10 — from 3.14 on, ruff would write `except A, B:` without parentheses
|
||||
|
||||
|
|
@ -174,6 +178,10 @@ au [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|||
- Une VM déployée l'amont du cache coupé — formulaire QEMU, Proxmox VE, ou `deploy_qemu.py --offline` — a l'audit de sécurité de npm désactivé (`NPM_CONFIG_AUDIT=false`) : il interroge un service qu'aucun cache ne rejoue, et échouait à chaque installation hors ligne. Une VM en ligne garde son audit
|
||||
- Vérifier une image téléchargée ne demande plus `--verify` : c'est le défaut pour toute distribution qui publie une somme, et `--no-verify` est ce qui la saute — à réserver aux essais hors ligne, où une image substituée passerait autrement sans un mot
|
||||
- `--bios` est refusé sur une image sans secteur d'amorçage BIOS, et dit pourquoi. Forcé là, il donnait une VM « running » à console muette — la panne même que ce drapeau évite ailleurs
|
||||
- L'environnement virtuel d'outillage `.venv.erplibre` tourne en Python 3.14.7, indépendamment de celui d'Odoo (3.12.10 pour Odoo 18.0). `install_erplibre.sh` le bâtit par `install_venv.sh` et `EL_PYTHON_PROVIDER` plutôt qu'avec le `python3` du système
|
||||
- `.venv.erplibre` sur un Python incompatible est SUPPRIMÉ puis rebâti ; ce qu'on y avait posé à la main part avec lui. Le venv d'Odoo est conservé quand seule sa version diffère, et rebâti seulement s'il est hors service : le rebâtir refait une installation Poetry entière. Un répertoire sans `pyvenv.cfg` n'est jamais effacé
|
||||
- L'image Docker de production bâtit `.venv.erplibre` sur le Python d'Odoo et s'arrête quand ce Python ne sait pas lire `script/`
|
||||
- Le PATCH ne borne que le venv d'Odoo, dont le pyproject exige `>=3.12.10,<3.13`. Pour celui de l'outillage, la majeure.mineure suffit : exiger le patch écartait le Python d'une distribution d'un cran en retard — NixOS 25.11 livre 3.14.2 quand conf demande 3.14.7 — et faisait COMPILER CPython à pyenv pour une différence que rien ne réclame
|
||||
- `make format` choisit le formateur d'après le contexte de chaque fichier : un module Odoo garde isort et black en `py37`, la série la plus ancienne encore supportée, quand l'outillage de ce dépôt passe par ruff, réglé une fois dans `.ruff.toml`. ruff suit les versions de CPython, là où black 24.8.0 s'arrête à `py313`, et son tri d'imports remplace isort ; c'est aussi ce qu'emploie la norme OCA depuis qu'elle a quitté black
|
||||
- Les dépôts que Google Repo rapatrie sous `script/` sont écartés de ce formatage, chemin nommé compris : les reformater écrirait dans l'historique d'autrui. `target-version` y reste à `py310`, parce que les hooks git portent `#!/usr/bin/env python3` et qu'une distribution livre encore 3.10 — à partir de 3.14, ruff écrirait `except A, B:` sans parenthèses
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,10 @@ au [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|||
- Une VM déployée l'amont du cache coupé — formulaire QEMU, Proxmox VE, ou `deploy_qemu.py --offline` — a l'audit de sécurité de npm désactivé (`NPM_CONFIG_AUDIT=false`) : il interroge un service qu'aucun cache ne rejoue, et échouait à chaque installation hors ligne. Une VM en ligne garde son audit
|
||||
- Vérifier une image téléchargée ne demande plus `--verify` : c'est le défaut pour toute distribution qui publie une somme, et `--no-verify` est ce qui la saute — à réserver aux essais hors ligne, où une image substituée passerait autrement sans un mot
|
||||
- `--bios` est refusé sur une image sans secteur d'amorçage BIOS, et dit pourquoi. Forcé là, il donnait une VM « running » à console muette — la panne même que ce drapeau évite ailleurs
|
||||
- L'environnement virtuel d'outillage `.venv.erplibre` tourne en Python 3.14.7, indépendamment de celui d'Odoo (3.12.10 pour Odoo 18.0). `install_erplibre.sh` le bâtit par `install_venv.sh` et `EL_PYTHON_PROVIDER` plutôt qu'avec le `python3` du système
|
||||
- `.venv.erplibre` sur un Python incompatible est SUPPRIMÉ puis rebâti ; ce qu'on y avait posé à la main part avec lui. Le venv d'Odoo est conservé quand seule sa version diffère, et rebâti seulement s'il est hors service : le rebâtir refait une installation Poetry entière. Un répertoire sans `pyvenv.cfg` n'est jamais effacé
|
||||
- L'image Docker de production bâtit `.venv.erplibre` sur le Python d'Odoo et s'arrête quand ce Python ne sait pas lire `script/`
|
||||
- Le PATCH ne borne que le venv d'Odoo, dont le pyproject exige `>=3.12.10,<3.13`. Pour celui de l'outillage, la majeure.mineure suffit : exiger le patch écartait le Python d'une distribution d'un cran en retard — NixOS 25.11 livre 3.14.2 quand conf demande 3.14.7 — et faisait COMPILER CPython à pyenv pour une différence que rien ne réclame
|
||||
- `make format` choisit le formateur d'après le contexte de chaque fichier : un module Odoo garde isort et black en `py37`, la série la plus ancienne encore supportée, quand l'outillage de ce dépôt passe par ruff, réglé une fois dans `.ruff.toml`. ruff suit les versions de CPython, là où black 24.8.0 s'arrête à `py313`, et son tri d'imports remplace isort ; c'est aussi ce qu'emploie la norme OCA depuis qu'elle a quitté black
|
||||
- Les dépôts que Google Repo rapatrie sous `script/` sont écartés de ce formatage, chemin nommé compris : les reformater écrirait dans l'historique d'autrui. `target-version` y reste à `py310`, parce que les hooks git portent `#!/usr/bin/env python3` et qu'une distribution livre encore 3.10 — à partir de 3.14, ruff écrirait `except A, B:` sans parenthèses
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|||
- A VM deployed with the cache upstream cut — QEMU form, Proxmox VE, or `deploy_qemu.py --offline` — has npm's security audit turned off (`NPM_CONFIG_AUDIT=false`): it queries a remote service no cache can replay, and failed on every offline install. An online VM keeps its audit
|
||||
- Verifying a downloaded image no longer needs `--verify`: it runs by default for every distribution that publishes a sum, and `--no-verify` is what skips it — to be kept for offline runs, where a substituted image would otherwise pass unremarked
|
||||
- `--bios` is refused on an image with no BIOS boot sector, and says why. Forced there, it gave a VM reported « running » with a silent console — the very failure that flag exists to avoid elsewhere
|
||||
- The tooling virtual environment `.venv.erplibre` runs Python 3.14.7, independently of the Odoo one (3.12.10 for Odoo 18.0). `install_erplibre.sh` builds it through `install_venv.sh` and `EL_PYTHON_PROVIDER` instead of the system `python3`
|
||||
- `.venv.erplibre` on an incompatible Python is DELETED and rebuilt; whatever was installed in it by hand goes with it. Odoo's venv is kept when it merely differs in version, and rebuilt only when it is unusable: rebuilding it redoes a whole Poetry install. A directory without `pyvenv.cfg` is never deleted
|
||||
- The production Docker image builds `.venv.erplibre` on Odoo's Python and stops when that Python cannot parse `script/`
|
||||
- The PATCH bounds only Odoo's venv, whose pyproject requires `>=3.12.10,<3.13`. For the tooling one, the major.minor is enough: requiring the patch turned away a distribution's Python one step behind — NixOS 25.11 ships 3.14.2 where conf asks 3.14.7 — and made pyenv COMPILE CPython for a difference nothing needs
|
||||
- `make format` picks the formatter from each file's context: an Odoo module keeps isort and black on `py37`, the series still supported going down that far, while this repository's own tooling goes through ruff, configured once in `.ruff.toml`. ruff follows CPython's versions, where black 24.8.0 stops at `py313`, and its import sorting replaces isort; it is also what the OCA standard uses since it left black
|
||||
- The repositories that Google Repo checks out under `script/` are excluded from that formatting, a named path included: reformatting them would write in someone else's history. `target-version` stays at `py310` there, because the git hooks carry `#!/usr/bin/env python3` and a distribution still ships 3.10 — from 3.14 on, ruff would write `except A, B:` without parentheses
|
||||
|
||||
|
|
|
|||
16
Makefile
16
Makefile
|
|
@ -129,6 +129,8 @@ install_uv:
|
|||
echo "Ajoutez ce repertoire au PATH, ou installez uv globalement."; \
|
||||
fi
|
||||
|
||||
# Telecharge puis execute : dans « curl | sh », le statut est celui de sh,
|
||||
# qui rend 0 sur une entree vide et masque un telechargement rate.
|
||||
.PHONY: install_mise
|
||||
install_mise:
|
||||
@if command -v mise >/dev/null 2>&1; then \
|
||||
|
|
@ -139,7 +141,19 @@ install_mise:
|
|||
echo "mise ne publie pas de binaire s390x : on reste sur pyenv."; \
|
||||
else \
|
||||
echo "Installation de mise depuis https://mise.run"; \
|
||||
curl -fsSL https://mise.run | sh; \
|
||||
installateur="$$(mktemp)" || exit 1; \
|
||||
if ! curl -fsSL -o "$$installateur" https://mise.run; then \
|
||||
rm -f "$$installateur"; \
|
||||
echo "Telechargement de l installateur mise impossible" \
|
||||
"(reseau ou cache) : mise n est pas pose." >&2; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
if ! sh "$$installateur"; then \
|
||||
rm -f "$$installateur"; \
|
||||
echo "L installateur de mise a echoue (voir ci-dessus)." >&2; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
rm -f "$$installateur"; \
|
||||
echo "Ajoutez ~/.local/bin a votre PATH, puis relancez l installation."; \
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -86,10 +86,21 @@ Suivez-nous sur Mastodon : https://fosstodon.org/@erplibre
|
|||
|
||||
Switch between versions with `make switch_odoo_18`, `make switch_odoo_16`, etc.
|
||||
|
||||
The Python in that table is the one of the Odoo virtual environment. The
|
||||
tooling virtual environment `.venv.erplibre` (TODO, `repo`, formatters) runs
|
||||
its own interpreter, **3.14.7**, set by `conf/python-erplibre-version`. Where a
|
||||
distribution does not carry it, pyenv compiles it.
|
||||
|
||||
<!-- [fr] -->
|
||||
|
||||
Changez de version avec `make switch_odoo_18`, `make switch_odoo_16`, etc.
|
||||
|
||||
Le Python de ce tableau est celui de l'environnement virtuel Odoo.
|
||||
L'environnement virtuel d'outillage `.venv.erplibre` (TODO, `repo`, formateurs)
|
||||
tourne sur son propre interpréteur, **3.14.7**, fixé par
|
||||
`conf/python-erplibre-version`. Là où une distribution ne le porte pas, pyenv
|
||||
le compile.
|
||||
|
||||
<!-- [en] -->
|
||||
|
||||
# Supported platforms
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@ Suivez-nous sur Mastodon : https://fosstodon.org/@erplibre
|
|||
|
||||
Changez de version avec `make switch_odoo_18`, `make switch_odoo_16`, etc.
|
||||
|
||||
Le Python de ce tableau est celui de l'environnement virtuel Odoo.
|
||||
L'environnement virtuel d'outillage `.venv.erplibre` (TODO, `repo`, formateurs)
|
||||
tourne sur son propre interpréteur, **3.14.7**, fixé par
|
||||
`conf/python-erplibre-version`. Là où une distribution ne le porte pas, pyenv
|
||||
le compile.
|
||||
|
||||
|
||||
# Plateformes supportées
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,11 @@ Follow us on Mastodon : https://fosstodon.org/@erplibre
|
|||
|
||||
Switch between versions with `make switch_odoo_18`, `make switch_odoo_16`, etc.
|
||||
|
||||
The Python in that table is the one of the Odoo virtual environment. The
|
||||
tooling virtual environment `.venv.erplibre` (TODO, `repo`, formatters) runs
|
||||
its own interpreter, **3.14.7**, set by `conf/python-erplibre-version`. Where a
|
||||
distribution does not carry it, pyenv compiles it.
|
||||
|
||||
|
||||
# Supported platforms
|
||||
|
||||
|
|
|
|||
|
|
@ -83,17 +83,26 @@
|
|||
};
|
||||
|
||||
# ── Les outils ───────────────────────────────────────────────────────────
|
||||
# python3.12 : la version qu'attend ERPLibre (.python-odoo-version). envfs
|
||||
# la rend visible en /usr/bin/python3.12, où lib_python_provider.sh la
|
||||
# cherche — ni mise ni pyenv n'ont alors à télécharger quoi que ce soit.
|
||||
# Les DEUX Python du dépôt, substitués depuis ses fichiers de version :
|
||||
# celui d'Odoo (.python-odoo-version) et celui de l'outillage
|
||||
# (conf/python-erplibre-version), qui ne sont plus la même version. envfs
|
||||
# les rend visibles en /usr/bin/python3.X, où lib_python_provider.sh les
|
||||
# cherche — ni mise ni pyenv n'ont alors rien à compiler. Déclarer le seul
|
||||
# Python d'Odoo laissait pyenv bâtir l'autre, et la compilation de CPython
|
||||
# s'arrête ici sur « Modules/_cursesmodule.o ».
|
||||
#
|
||||
# Le second marqueur est VIDE quand les deux versions coïncident : nommer
|
||||
# deux fois le même paquet ferait entrer en collision deux chemins
|
||||
# identiques dans le profil.
|
||||
#
|
||||
# Les sorties « .dev » portent les en-têtes : sans elles, une roue absente
|
||||
# du dépôt amont devrait se compiler et ne trouverait ni libpq-fe.h ni
|
||||
# openssl/ssl.h. Elles ne servent qu'à ce cas, et ne coûtent que du disque.
|
||||
environment.systemPackages = with pkgs; [
|
||||
python312
|
||||
python312Packages.pip
|
||||
python312Packages.virtualenv
|
||||
@EL_PY_ODOO_PKG@
|
||||
@EL_PY_ODOO_PKG@Packages.pip
|
||||
@EL_PY_ODOO_PKG@Packages.virtualenv
|
||||
@EL_PY_TOOLS_PKG@
|
||||
uv
|
||||
nodejs_22
|
||||
postgresql
|
||||
|
|
@ -336,7 +345,7 @@
|
|||
# venv, donc avec le python du système. Son échec est silencieux
|
||||
# (« 2>/dev/null ») : sans elle, la première page ouverte attendrait le
|
||||
# chargement du registre sans que rien ne le dise.
|
||||
path = with pkgs; [ bash python312 ];
|
||||
path = with pkgs; [ bash @EL_PY_ODOO_PKG@ ];
|
||||
# L'unité est déclarée par le module, donc démarrée par la
|
||||
# reconstruction — qui a lieu PENDANT « make install_os », alors que la
|
||||
# source d'Odoo n'arrive qu'à « make install_odoo_18 ». Sans condition,
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
3.12.10
|
||||
3.14.7
|
||||
|
|
@ -439,6 +439,10 @@ If these last steps to set up your development environment were unsuccessful, fo
|
|||
|
||||
## Manual Installation
|
||||
|
||||
This system interpreter only needs to reach `make` (Python 3.10 or later).
|
||||
`.venv.erplibre` is built on its own version, `conf/python-erplibre-version`,
|
||||
through `EL_PYTHON_PROVIDER` (mise or pyenv).
|
||||
|
||||
### Install Python 3.10.14
|
||||
You can delete the files that are left over in your home directory regarding the python installation when the steps have been completed succesfully.
|
||||
|
||||
|
|
@ -447,6 +451,10 @@ Si ces dernières étapes pour configurer votre environnement de développement
|
|||
|
||||
## Installation manuelle
|
||||
|
||||
Cet interpréteur système ne sert qu'à atteindre `make` (Python 3.10 ou plus).
|
||||
`.venv.erplibre` est bâti sur sa propre version, `conf/python-erplibre-version`,
|
||||
par `EL_PYTHON_PROVIDER` (mise ou pyenv).
|
||||
|
||||
### Installer Python 3.10.14
|
||||
Vous pouvez supprimer les fichiers restants dans votre répertoire personnel concernant l'installation de Python une fois les étapes complétées avec succès.
|
||||
|
||||
|
|
|
|||
|
|
@ -236,6 +236,10 @@ Si ces dernières étapes pour configurer votre environnement de développement
|
|||
|
||||
## Installation manuelle
|
||||
|
||||
Cet interpréteur système ne sert qu'à atteindre `make` (Python 3.10 ou plus).
|
||||
`.venv.erplibre` est bâti sur sa propre version, `conf/python-erplibre-version`,
|
||||
par `EL_PYTHON_PROVIDER` (mise ou pyenv).
|
||||
|
||||
### Installer Python 3.10.14
|
||||
Vous pouvez supprimer les fichiers restants dans votre répertoire personnel concernant l'installation de Python une fois les étapes complétées avec succès.
|
||||
|
||||
|
|
|
|||
|
|
@ -236,6 +236,10 @@ If these last steps to set up your development environment were unsuccessful, fo
|
|||
|
||||
## Manual Installation
|
||||
|
||||
This system interpreter only needs to reach `make` (Python 3.10 or later).
|
||||
`.venv.erplibre` is built on its own version, `conf/python-erplibre-version`,
|
||||
through `EL_PYTHON_PROVIDER` (mise or pyenv).
|
||||
|
||||
### Install Python 3.10.14
|
||||
You can delete the files that are left over in your home directory regarding the python installation when the steps have been completed succesfully.
|
||||
|
||||
|
|
|
|||
|
|
@ -37,8 +37,12 @@ RUN cd $ODOO_PREFIX && \
|
|||
ls -lha /ERPLibre && \
|
||||
python -m venv .venv.$ERPLIBRE_VERSION
|
||||
|
||||
# Le venv des outils prend le python de l'image, celui d'Odoo : le RUN
|
||||
# s'arrete ici si ce python ne sait pas lire la syntaxe de script/.
|
||||
RUN cd $ODOO_PREFIX && \
|
||||
ls -lha /ERPLibre && \
|
||||
{ python -m compileall -q script/ || \
|
||||
{ echo "Le python de l'image ($(python -V 2>&1)) ne lit pas script/ : prendre une version Odoo plus recente." ; exit 1 ; } ; } && \
|
||||
python -m venv .venv.erplibre && \
|
||||
source ./.venv.erplibre/bin/activate && \
|
||||
pip3 install -r requirement/erplibre_require-ments.txt
|
||||
|
|
|
|||
|
|
@ -70,11 +70,21 @@ docker build -f Dockerfile.prod.pkg -t technolibre/erplibre:12.0-pkg .
|
|||
```
|
||||
|
||||
<!-- [en] -->
|
||||
|
||||
`.venv.erplibre` is built on the image's own Python, Odoo's, without mise or
|
||||
pyenv. The build stops when that Python cannot parse `script/`, which happens
|
||||
with a deprecated Odoo version.
|
||||
|
||||
### Running ERPLibre using Docker-Compose
|
||||
|
||||
Go at the root of this git project.
|
||||
|
||||
<!-- [fr] -->
|
||||
|
||||
`.venv.erplibre` est bâti sur le Python de l'image, celui d'Odoo, sans mise ni
|
||||
pyenv. La construction s'arrête quand ce Python ne sait pas lire `script/`, ce
|
||||
qui arrive avec une version d'Odoo dépréciée.
|
||||
|
||||
### Exécuter ERPLibre avec Docker-Compose
|
||||
|
||||
Allez à la racine de ce projet git.
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@ docker build -f Dockerfile.base -t technolibre/erplibre-base:12.0 .
|
|||
docker build -f Dockerfile.prod.pkg -t technolibre/erplibre:12.0-pkg .
|
||||
```
|
||||
|
||||
|
||||
`.venv.erplibre` est bâti sur le Python de l'image, celui d'Odoo, sans mise ni
|
||||
pyenv. La construction s'arrête quand ce Python ne sait pas lire `script/`, ce
|
||||
qui arrive avec une version d'Odoo dépréciée.
|
||||
|
||||
### Exécuter ERPLibre avec Docker-Compose
|
||||
|
||||
Allez à la racine de ce projet git.
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@ docker build -f Dockerfile.base -t technolibre/erplibre-base:12.0 .
|
|||
docker build -f Dockerfile.prod.pkg -t technolibre/erplibre:12.0-pkg .
|
||||
```
|
||||
|
||||
|
||||
`.venv.erplibre` is built on the image's own Python, Odoo's, without mise or
|
||||
pyenv. The build stops when that Python cannot parse `script/`, which happens
|
||||
with a deprecated Odoo version.
|
||||
|
||||
### Running ERPLibre using Docker-Compose
|
||||
|
||||
Go at the root of this git project.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,58 @@
|
|||
#!/usr/bin/env bash
|
||||
# TODO deprecated, this is moved into install_locally.sh to be sure venv is installed and force take specified supported version
|
||||
python3 -m venv .venv.erplibre
|
||||
source .venv.erplibre/bin/activate
|
||||
pip3 install -r requirement/erplibre_require-ments.txt
|
||||
npm install
|
||||
# © 2021-2026 TechnoLibre (http://www.technolibre.ca)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
||||
#
|
||||
# Pose le venv d'OUTILLAGE d'ERPLibre, sans qu'une version d'Odoo soit
|
||||
# choisie : chemin et version se lisent dans conf/, versionné, et non par
|
||||
# env_var.sh, qui exige .python-odoo-version. Se lance depuis la racine du
|
||||
# dépôt.
|
||||
|
||||
CONF_VENV="conf/python-erplibre-venv"
|
||||
CONF_PYTHON_VERSION="conf/python-erplibre-version"
|
||||
|
||||
for conf_file in "${CONF_VENV}" "${CONF_PYTHON_VERSION}"; do
|
||||
if [[ ! -f "${conf_file}" ]]; then
|
||||
echo "Configuration introuvable : ${conf_file}"
|
||||
echo " Ce script se lance depuis la racine du depot :"
|
||||
echo " cd <racine du depot> && ./script/install/install_erplibre.sh"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# « xargs » retire espaces et retour de ligne autour de la valeur.
|
||||
VENV_ERPLIBRE_PATH=$(xargs < "${CONF_VENV}")
|
||||
PYTHON_ERPLIBRE_VERSION=$(xargs < "${CONF_PYTHON_VERSION}")
|
||||
|
||||
echo -e "Install ${VENV_ERPLIBRE_PATH} with ${PYTHON_ERPLIBRE_VERSION}"
|
||||
if ! ./script/install/install_venv.sh \
|
||||
"ERPLibre" "${VENV_ERPLIBRE_PATH}" "${PYTHON_ERPLIBRE_VERSION}"; then
|
||||
echo "Echec de creation de ${VENV_ERPLIBRE_PATH}, arret."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Un venv rebâti n'a plus bin/repo ; install_git_repo.sh ne le pose que s'il
|
||||
# manque. TODO s'en passe : seules les synchronisations de dépôts l'exigent,
|
||||
# donc un échec (hors ligne) est signalé sans arrêter l'installation.
|
||||
if ! ./script/install/install_git_repo.sh; then
|
||||
echo "git-repo n'est pas pose dans ${VENV_ERPLIBRE_PATH} : 'repo sync' en a besoin."
|
||||
echo " Rejouez quand le reseau le permet : ./script/install/install_git_repo.sh"
|
||||
fi
|
||||
|
||||
# el_pip_install vise le venv par son chemin : aucune activation n'est requise.
|
||||
# shellcheck source=script/install/lib_pip_provider.sh
|
||||
. ./script/install/lib_pip_provider.sh
|
||||
if ! el_pip_install "${VENV_ERPLIBRE_PATH}" \
|
||||
-r requirement/erplibre_require-ments.txt; then
|
||||
echo "Echec d'installation des dependances Python dans ${VENV_ERPLIBRE_PATH}."
|
||||
echo " Relancez : ./script/install/install_erplibre.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Prettier ne sert qu'au formatage XML (« make format ») : son échec est
|
||||
# signalé sans faire échouer une installation Python complète.
|
||||
if ! npm install; then
|
||||
echo "npm install a echoue : prettier et son greffon XML ne sont pas poses."
|
||||
echo " ${VENV_ERPLIBRE_PATH} est utilisable ; seul 'make format' les reclame."
|
||||
echo " Rejouez quand le reseau le permet : npm install"
|
||||
fi
|
||||
exit 0
|
||||
|
|
|
|||
|
|
@ -1,14 +1,44 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
VENV_ERPLIBRE_PATH=$(cat "conf/python-erplibre-venv" | xargs)
|
||||
# Se lance depuis la racine du dépôt : ailleurs, le chemin de venv serait vide
|
||||
# et la cible deviendrait « /bin/repo ».
|
||||
CONF_VENV="conf/python-erplibre-venv"
|
||||
if [[ ! -f "${CONF_VENV}" ]]; then
|
||||
echo "Configuration introuvable : ${CONF_VENV}"
|
||||
echo " cd <racine du depot> && ./script/install/install_git_repo.sh"
|
||||
exit 1
|
||||
fi
|
||||
VENV_ERPLIBRE_PATH=$(xargs < "${CONF_VENV}")
|
||||
|
||||
VENV_REPO_PATH=${VENV_ERPLIBRE_PATH}/bin/repo
|
||||
# Install git-repo if missing
|
||||
if [[ ! -f ${VENV_REPO_PATH} ]]; then
|
||||
echo "\n---- Install git-repo from Google APIS ----"
|
||||
curl https://storage.googleapis.com/git-repo-downloads/repo > ${VENV_REPO_PATH}
|
||||
chmod +x ${VENV_REPO_PATH}
|
||||
sed -i 1d ${VENV_REPO_PATH}
|
||||
if [[ ! -d "${VENV_ERPLIBRE_PATH}/bin" ]]; then
|
||||
echo "Venv ${VENV_ERPLIBRE_PATH} absent : posez-le avant git-repo."
|
||||
echo " ./script/install/install_erplibre.sh"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\n---- Install git-repo from Google APIS ----"
|
||||
# Téléchargé à côté, contrôlé, puis déplacé : sans « -f », curl écrit la
|
||||
# page d'une erreur HTTP et rend 0 ; un corps vide passe le statut.
|
||||
REPO_TMP="$(mktemp)" || exit 1
|
||||
if ! curl -fsSL -o "${REPO_TMP}" \
|
||||
https://storage.googleapis.com/git-repo-downloads/repo \
|
||||
|| [[ ! -s "${REPO_TMP}" ]]; then
|
||||
echo "Telechargement de git-repo impossible ou vide (reseau ou cache) :"
|
||||
echo " ${VENV_REPO_PATH} n'est pas pose."
|
||||
rm -f "${REPO_TMP}"
|
||||
exit 1
|
||||
fi
|
||||
# Le hashbang du venv remplace celui du python3 du système.
|
||||
sed -i 1d "${REPO_TMP}"
|
||||
PYTHON_HASHBANG="#!./${VENV_ERPLIBRE_PATH}/bin/python"
|
||||
sed -i "1 i ${PYTHON_HASHBANG}" ${VENV_REPO_PATH}
|
||||
sed -i "1 i ${PYTHON_HASHBANG}" "${REPO_TMP}"
|
||||
if ! mv "${REPO_TMP}" "${VENV_REPO_PATH}"; then
|
||||
echo "Mise en place de ${VENV_REPO_PATH} impossible."
|
||||
rm -f "${REPO_TMP}"
|
||||
exit 1
|
||||
fi
|
||||
# mktemp crée en 0600.
|
||||
chmod 755 "${VENV_REPO_PATH}"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -37,6 +37,21 @@ EL_CA_BUNDLE=/var/lib/erplibre/ca-bundle.crt
|
|||
[ -r "${EL_CA_BUNDLE}" ] || EL_CA_BUNDLE=""
|
||||
EL_LOCALE=${EL_LOCALE:-$(lire_seed locale)}
|
||||
EL_TZ=${EL_TZ:-$(lire_seed timezone)}
|
||||
# « 3.12.10 » donne « python312 », le nom du paquet nixpkgs. Les deux versions
|
||||
# du dépôt sont déclarées : celle d'Odoo et celle de l'outillage. Le second est
|
||||
# VIDE quand elles coïncident, un même paquet nommé deux fois entrant en
|
||||
# collision dans le profil.
|
||||
el_nix_python_pkg() {
|
||||
local v
|
||||
v="$(xargs < "$1" 2> /dev/null)"
|
||||
[ -n "${v}" ] || return 0
|
||||
echo "python$(echo "${v}" | cut -d. -f1)$(echo "${v}" | cut -d. -f2)"
|
||||
}
|
||||
EL_PY_ODOO_PKG="$(el_nix_python_pkg .python-odoo-version)"
|
||||
EL_PY_ODOO_PKG="${EL_PY_ODOO_PKG:-python312}"
|
||||
EL_PY_TOOLS_PKG="$(el_nix_python_pkg conf/python-erplibre-version)"
|
||||
[ "${EL_PY_TOOLS_PKG}" = "${EL_PY_ODOO_PKG}" ] && EL_PY_TOOLS_PKG=""
|
||||
|
||||
MODULE_SRC="conf/nixos/erplibre.nix"
|
||||
MODULE_DST="/etc/nixos/erplibre.nix"
|
||||
CONFIG="/etc/nixos/configuration.nix"
|
||||
|
|
@ -57,9 +72,12 @@ echo -e "\n---- Module ERPLibre pour NixOS ----"
|
|||
sed -e "s/@EL_USER@/${EL_USER}/g" -e "s#@EL_DIR@#${EL_DIR}#g" \
|
||||
-e "s/@EL_LOCALE@/${EL_LOCALE}/g" -e "s#@EL_TZ@#${EL_TZ}#g" \
|
||||
-e "s#@EL_CA_BUNDLE@#${EL_CA_BUNDLE}#g" \
|
||||
-e "s/@EL_PY_ODOO_PKG@/${EL_PY_ODOO_PKG}/g" \
|
||||
-e "s/@EL_PY_TOOLS_PKG@/${EL_PY_TOOLS_PKG}/g" \
|
||||
"${MODULE_SRC}" | sudo tee "${MODULE_DST}" > /dev/null
|
||||
echo " posé : ${MODULE_DST} (compte ${EL_USER}, dépôt ${EL_DIR})"
|
||||
echo " autorité du cache : ${EL_CA_BUNDLE:-aucune}"
|
||||
echo " Python : ${EL_PY_ODOO_PKG} (Odoo)${EL_PY_TOOLS_PKG:+, ${EL_PY_TOOLS_PKG} (outillage)}"
|
||||
echo " régional : locale « ${EL_LOCALE:-non demandée} »," \
|
||||
"fuseau « ${EL_TZ:-non demandé} »"
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,13 @@ fi
|
|||
|
||||
# Assign arguments to variables
|
||||
CONTEXT="$1"
|
||||
VENV_PATH="$2"
|
||||
# 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"
|
||||
|
|
@ -18,20 +23,140 @@ 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. C'est ce qui permet d'en ajouter un
|
||||
# troisième sans toucher ici.
|
||||
# ne connaît qu'un chemin d'interpréteur.
|
||||
# shellcheck source=script/install/lib_python_provider.sh
|
||||
. ./script/install/lib_python_provider.sh
|
||||
|
||||
PYTHON_EXEC="$(el_python_exec "${PYTHON_VERSION}")"
|
||||
# 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}"
|
||||
echo " Voir 'make install_mise', ou installez pyenv."
|
||||
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
|
||||
|
|
@ -39,3 +164,13 @@ if [[ ! -d ${VENV_PATH} ]]; then
|
|||
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."
|
||||
|
|
|
|||
|
|
@ -55,22 +55,29 @@ el_python_is_version() {
|
|||
[ "${got}" = "${want}" ]
|
||||
}
|
||||
|
||||
# Vrai si l'exécutable CONVIENT : même majeure.mineure, et patch au moins
|
||||
# égal au demandé. C'est exactement ce qu'exige le pyproject — « >=3.12.10,
|
||||
# <3.13 » — et non l'égalité stricte que testait el_python_is_version.
|
||||
# Vrai si l'exécutable CONVIENT. Deux exigences, selon ce qui borne l'appelant.
|
||||
#
|
||||
# La distinction n'est pas théorique. Tumbleweed s390x livre python312 en
|
||||
# 3.12.13 : parfaitement utilisable, mais rejeté par l'égalité, ce qui forçait
|
||||
# pyenv à COMPILER CPython — et gcc 15.2 s'y arrête sur une erreur interne
|
||||
# dans Parser/parser.c, un fichier généré de quarante mille lignes.
|
||||
# patch même majeure.mineure, et patch au moins égal. C'est ce que le
|
||||
# pyproject d'Odoo demande — « >=3.12.10,<3.13 » —, et Poetry
|
||||
# refuserait un patch inférieur.
|
||||
# mineure même majeure.mineure, quel que soit le patch. RIEN n'épingle le
|
||||
# patch du venv d'OUTILLAGE : l'exiger écarte le Python des
|
||||
# distributions dès qu'il est d'un patch en retard — NixOS 25.11
|
||||
# livre 3.14.2 quand conf/ demande 3.14.7 — et force pyenv à
|
||||
# COMPILER CPython pour une différence qui ne gêne personne.
|
||||
#
|
||||
# L'égalité stricte, elle, rejetterait aussi un patch plus RÉCENT : c'est
|
||||
# el_python_is_version, et elle ne sert qu'aux fournisseurs qui posent une
|
||||
# version nommée.
|
||||
el_python_is_compatible() {
|
||||
local exe="$1" want="$2" got
|
||||
local exe="$1" want="$2" exigence="${3:-patch}" got
|
||||
[ -x "${exe}" ] || return 1
|
||||
got="$("${exe}" -c 'import platform;print(platform.python_version())' \
|
||||
2> /dev/null)"
|
||||
[ -n "${got}" ] || return 1
|
||||
# Même majeure.mineure : 3.13 ne convient pas à un pyproject borné à <3.13.
|
||||
[ "${got%.*}" = "${want%.*}" ] || return 1
|
||||
[ "${exigence}" = "mineure" ] && return 0
|
||||
# Patch au moins égal, comparé en version et non en chaîne (3.12.9 < 3.12.10).
|
||||
[ "$(printf '%s\n%s\n' "${want}" "${got}" | sort -V | head -1)" = "${want}" ]
|
||||
}
|
||||
|
|
@ -81,7 +88,7 @@ el_python_is_compatible() {
|
|||
# prend des dizaines de minutes quand il aboutit. Le nom suit la convention de
|
||||
# toutes les distributions, « python3.12 ».
|
||||
el_distro_python_exec() {
|
||||
local want="$1" exe
|
||||
local want="$1" exigence="${2:-patch}" exe
|
||||
# Des chemins SYSTEME, jamais « command -v » : dans un venv activé celui-ci
|
||||
# rend le python DU VENV, et l'on bâtirait un venv depuis un venv. Le PATH
|
||||
# d'une session interactive n'a rien à faire dans cette décision.
|
||||
|
|
@ -94,7 +101,7 @@ el_distro_python_exec() {
|
|||
# pas, et la boucle passe a la suite sans rien couter.
|
||||
for exe in "/run/current-system/sw/bin/python${want%.*}" \
|
||||
"/usr/bin/python${want%.*}" "/usr/local/bin/python${want%.*}"; do
|
||||
if el_python_is_compatible "${exe}" "${want}"; then
|
||||
if el_python_is_compatible "${exe}" "${want}" "${exigence}"; then
|
||||
echo "${exe}"
|
||||
return 0
|
||||
fi
|
||||
|
|
@ -175,10 +182,31 @@ el_pyenv_install() {
|
|||
echo "${exe}"
|
||||
}
|
||||
|
||||
# Annonce la compilation pyenv AVANT de la subir, et le geste qui l'évite :
|
||||
# poser mise, ou lire ce que mise reproche quand il est déjà là. Muet si pyenv
|
||||
# porte déjà la version, puisque rien ne sera compilé.
|
||||
el_warn_pyenv_fallback() {
|
||||
local version="$1"
|
||||
[ -d "$(el_pyenv_root)/versions/${version}" ] && return 0
|
||||
if command -v mise > /dev/null 2>&1; then
|
||||
echo "mise n'a pas pu fournir Python ${version} : repli sur pyenv," >&2
|
||||
echo " qui COMPILE CPython. Pour lire ce que mise reproche :" >&2
|
||||
echo " mise install python@${version} (reseau requis)" >&2
|
||||
else
|
||||
echo "mise est absent : pyenv va etre pose, puis COMPILER CPython" >&2
|
||||
echo " ${version} -- quelques minutes, bien plus sous emulation, et il" >&2
|
||||
echo " lui faut une douzaine de -dev (openssl, zlib, readline, sqlite," >&2
|
||||
echo " bzip2, xz, tk). Pour l'eviter : Ctrl+C, puis" >&2
|
||||
echo " make install_mise" >&2
|
||||
echo " qui pose un CPython precompile en quelques secondes, et relancez." >&2
|
||||
fi
|
||||
}
|
||||
|
||||
# API publique : imprime le chemin absolu d'un interpréteur de cette version,
|
||||
# ou rien (et rend non nul) si aucun fournisseur n'y parvient.
|
||||
el_python_exec() {
|
||||
local version="$1" provider="${EL_PYTHON_PROVIDER:-auto}" exe
|
||||
local version="$1" exigence="${2:-patch}"
|
||||
local provider="${EL_PYTHON_PROVIDER:-auto}" exe
|
||||
|
||||
# 1) Déjà présent ? On ne réinstalle rien et on ne touche pas au réseau.
|
||||
# C'est ce qui rend le changement sans effet pour une installation
|
||||
|
|
@ -205,7 +233,7 @@ el_python_exec() {
|
|||
# Uniquement en mode « auto » : demander mise ou pyenv explicitement doit
|
||||
# être respecté, sinon le réglage ne veut plus rien dire.
|
||||
if [ "${provider}" = "auto" ] \
|
||||
&& exe="$(el_distro_python_exec "${version}")"; then
|
||||
&& exe="$(el_distro_python_exec "${version}" "${exigence}")"; then
|
||||
echo "Python $("${exe}" -V 2>&1 | awk '{print $2}') de la distribution :" \
|
||||
"aucune compilation." >&2
|
||||
echo "${exe}"
|
||||
|
|
@ -220,8 +248,7 @@ el_python_exec() {
|
|||
return 0
|
||||
fi
|
||||
[ "${provider}" = "mise" ] && return 1
|
||||
command -v mise > /dev/null 2>&1 \
|
||||
&& echo "mise n'a pas pu fournir Python ${version} : repli sur pyenv." >&2
|
||||
el_warn_pyenv_fallback "${version}"
|
||||
fi
|
||||
el_pyenv_install "${version}"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +1,13 @@
|
|||
#!/bin/bash
|
||||
DIR_VENV_ERPLIBRE_EXIST=1
|
||||
DIR_VENV_ERPLIBRE=".venv.erplibre"
|
||||
# If not exist, create it and do installation
|
||||
# Can be in conflict with ./script/install_locally.sh
|
||||
#!/usr/bin/env bash
|
||||
# © 2021-2026 TechnoLibre (http://www.technolibre.ca)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
||||
#
|
||||
# Auto-installation de TODO : install_erplibre.sh pose ou rebâtit le venv
|
||||
# d'outillage, puis TODO repart sur l'interpréteur de ce venv.
|
||||
# Se lance depuis la racine du dépôt.
|
||||
|
||||
if [[ ! -d "$DIR_VENV_ERPLIBRE" ]]; then
|
||||
DIR_VENV_ERPLIBRE_EXIST=0
|
||||
echo "$DIR_VENV_ERPLIBRE does not exist."
|
||||
# Le test d'origine etait inoperant : le tilde entre guillemets n'est pas
|
||||
# etendu, et « -d » testait un FICHIER comme un repertoire. La condition
|
||||
# etait donc toujours vraie, la commande echouait en « No such file or
|
||||
# directory », et le repli « python -m venv » ne servait jamais.
|
||||
# shellcheck source=script/install/lib_python_provider.sh
|
||||
. ./script/install/lib_python_provider.sh
|
||||
EL_PY_WANT="$(< ./conf/python-erplibre-version)"
|
||||
# Ici on ne PROVISIONNE pas : ce script s'execute au demarrage de TODO, il
|
||||
# doit rester rapide et hors reseau. On prend ce qui est deja pose, sinon
|
||||
# le python du systeme.
|
||||
EL_PY_EXEC="$(el_pyenv_exec_path "${EL_PY_WANT}")"
|
||||
el_python_is_version "${EL_PY_EXEC}" "${EL_PY_WANT}" \
|
||||
|| EL_PY_EXEC="$(el_mise_exec_path "${EL_PY_WANT}" 2> /dev/null)"
|
||||
if [[ -n "${EL_PY_EXEC}" ]] && [[ -x "${EL_PY_EXEC}" ]]; then
|
||||
"${EL_PY_EXEC}" -m venv $DIR_VENV_ERPLIBRE
|
||||
else
|
||||
python3 -m venv $DIR_VENV_ERPLIBRE
|
||||
fi
|
||||
if ! ./script/install/install_erplibre.sh; then
|
||||
echo "Installation d'ERPLibre en echec : TODO ne demarre pas."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If exist, source it and start installation
|
||||
source ./.venv.erplibre/bin/activate
|
||||
if [[ $DIR_VENV_ERPLIBRE_EXIST -eq 0 ]]; then
|
||||
pip install -r requirement/erplibre_require-ments.txt
|
||||
fi
|
||||
|
||||
./script/todo/todo.py
|
||||
exec "./$(xargs < conf/python-erplibre-venv)/bin/python" ./script/todo/todo.py "$@"
|
||||
|
|
|
|||
|
|
@ -153,10 +153,31 @@ class LeModule(unittest.TestCase):
|
|||
with self.subTest(lib=lib):
|
||||
self.assertIn(lib, self.src)
|
||||
|
||||
def test_the_python_matches_what_the_repository_wants(self):
|
||||
voulu = (RACINE / ".python-odoo-version").read_text().strip()
|
||||
majeur, mineur = voulu.split(".")[:2]
|
||||
self.assertIn(f"python{majeur}{mineur}", self.src)
|
||||
def test_no_python_version_is_written_by_hand(self):
|
||||
"""Une version écrite ici dériverait des fichiers du dépôt au premier
|
||||
changement — et déclarer le seul Python d'Odoo laissait pyenv bâtir
|
||||
celui de l'outillage, dont la compilation s'arrête sur
|
||||
« Modules/_cursesmodule.o »."""
|
||||
self.assertNotRegex(self.src, r"python3\d\d")
|
||||
self.assertIn("@EL_PY_ODOO_PKG@", self.src)
|
||||
self.assertIn("@EL_PY_TOOLS_PKG@", self.src)
|
||||
|
||||
def test_both_pythons_of_the_repository_are_declared(self):
|
||||
"""Le module les reçoit du script, qui les lit dans les deux fichiers
|
||||
de version."""
|
||||
script = SCRIPT.read_text(encoding="utf-8")
|
||||
self.assertIn(".python-odoo-version", script)
|
||||
self.assertIn("conf/python-erplibre-version", script)
|
||||
|
||||
def test_the_second_package_is_empty_when_both_agree(self):
|
||||
"""Nommer deux fois le même paquet ferait entrer en collision deux
|
||||
chemins identiques dans le profil."""
|
||||
script = SCRIPT.read_text(encoding="utf-8")
|
||||
self.assertRegex(
|
||||
script,
|
||||
r'EL_PY_TOOLS_PKG\}"?\s*=\s*"?\$\{EL_PY_ODOO_PKG'
|
||||
r'|\[ "\$\{EL_PY_TOOLS_PKG\}" = "\$\{EL_PY_ODOO_PKG\}" \]',
|
||||
)
|
||||
|
||||
def test_the_database_role_is_substituted(self):
|
||||
"""Le nom du compte varie d'un déploiement à l'autre ; l'écrire en dur
|
||||
|
|
@ -335,7 +356,7 @@ class LeServiceEstDeclare(unittest.TestCase):
|
|||
"""Une unité ne reçoit pas le PATH d'une session. run.sh lance des
|
||||
scripts dont le shebang est « env bash » : env est dans le PATH par
|
||||
défaut, bash non, et run.sh s'arrête avant Odoo."""
|
||||
self.assertIn("path = with pkgs; [ bash python312 ];", self.src)
|
||||
self.assertIn("path = with pkgs; [ bash @EL_PY_ODOO_PKG@ ];", self.src)
|
||||
|
||||
def test_the_repository_is_not_guessed(self):
|
||||
"""Le service lance le dépôt QUI A POSÉ le module. Écrire
|
||||
|
|
|
|||
278
test/test_install_venv_rebuild.py
Normal file
278
test/test_install_venv_rebuild.py
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
#!/usr/bin/env python3
|
||||
# © 2026 TechnoLibre (http://www.technolibre.ca)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
||||
"""install_venv.sh détruit un venv : sous quelles conditions, exactement ?
|
||||
|
||||
C'est le seul endroit du dépôt qui efface le travail de quelqu'un. Un venv
|
||||
porte ce qu'on y a posé à la main — bin/repo, uv, des paquets — et le nom
|
||||
.venv.erplibre ne dit pas sa version : rien ne distingue de l'extérieur celui
|
||||
qu'il faut rebâtir de celui qu'il faut garder.
|
||||
|
||||
Ces tests pèsent donc les REFUS autant que les destructions :
|
||||
|
||||
- un répertoire sans pyvenv.cfg n'est pas un venv et garde son contenu ;
|
||||
- un venv sur un système de fichiers monté appartient à une autre machine, et
|
||||
l'effacer le ferait à travers le réseau ;
|
||||
- un venv utilisable est conservé, sans quoi chaque installation rebâtirait
|
||||
ce qui marche.
|
||||
|
||||
L'interpréteur est un bouchon annoncé par PYENV_ROOT : les tests restent hors
|
||||
réseau, et rien ne dépend de ce que cette machine a installé.
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
RACINE = Path(__file__).resolve().parents[1]
|
||||
SCRIPT = RACINE / "script/install/install_venv.sh"
|
||||
|
||||
VOULUE = "9.99.0"
|
||||
AUTRE = "9.98.0"
|
||||
|
||||
# Un python qui suffit à ce que le script lui demande : sa version, la création
|
||||
# d'un venv, et la présence de pip.
|
||||
BOUCHON = """#!/bin/sh
|
||||
VERSION=__VERSION__
|
||||
case "$1" in
|
||||
-V|--version) echo "Python ${VERSION}" ;;
|
||||
-c) echo "${VERSION}" ;;
|
||||
-m)
|
||||
case "$2" in
|
||||
venv)
|
||||
mkdir -p "$3/bin" || exit 1
|
||||
printf 'version = %s\\n' "${VERSION}" > "$3/pyvenv.cfg"
|
||||
sed "s/^VERSION=.*/VERSION=${VERSION}/" "$0" > "$3/bin/python"
|
||||
chmod +x "$3/bin/python"
|
||||
: > "$3/bin/activate"
|
||||
;;
|
||||
pip) echo "pip 99.0 from nowhere" ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
exit 0
|
||||
"""
|
||||
|
||||
|
||||
def pose_bouchon(chemin, version):
|
||||
chemin.parent.mkdir(parents=True, exist_ok=True)
|
||||
chemin.write_text(
|
||||
BOUCHON.replace("__VERSION__", version), encoding="utf-8"
|
||||
)
|
||||
chemin.chmod(0o755)
|
||||
|
||||
|
||||
class BancInstallVenv(unittest.TestCase):
|
||||
"""Un PYENV_ROOT bouchonné, et un répertoire de travail jetable."""
|
||||
|
||||
def setUp(self):
|
||||
self.coin = Path(tempfile.mkdtemp())
|
||||
self.addCleanup(shutil.rmtree, self.coin, ignore_errors=True)
|
||||
pose_bouchon(
|
||||
self.coin / "pyenv" / "versions" / VOULUE / "bin" / "python",
|
||||
VOULUE,
|
||||
)
|
||||
self.bin = self.coin / "bin"
|
||||
self.bin.mkdir()
|
||||
|
||||
def env(self):
|
||||
return dict(
|
||||
os.environ,
|
||||
PYENV_ROOT=str(self.coin / "pyenv"),
|
||||
PATH=f"{self.bin}:{os.environ['PATH']}",
|
||||
EL_PYTHON_PROVIDER="pyenv",
|
||||
)
|
||||
|
||||
def lance(self, chemin_venv, contexte="ERPLibre"):
|
||||
return subprocess.run(
|
||||
[str(SCRIPT), contexte, str(chemin_venv), VOULUE],
|
||||
cwd=RACINE,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=self.env(),
|
||||
)
|
||||
|
||||
def venv_factice(self, nom, version):
|
||||
"""Un venv complet, comme « python -m venv » le laisse."""
|
||||
chemin = self.coin / nom
|
||||
(chemin / "bin").mkdir(parents=True)
|
||||
(chemin / "pyvenv.cfg").write_text(f"version = {version}\n")
|
||||
pose_bouchon(chemin / "bin" / "python", version)
|
||||
(chemin / "bin" / "activate").touch()
|
||||
(chemin / "TEMOIN").write_text("pose a la main\n")
|
||||
return chemin
|
||||
|
||||
|
||||
class TestCeQuIlConserve(BancInstallVenv):
|
||||
def test_un_venv_a_la_bonne_version_est_garde(self):
|
||||
venv = self.venv_factice("bon", VOULUE)
|
||||
fin = self.lance(venv)
|
||||
self.assertEqual(0, fin.returncode, fin.stdout + fin.stderr)
|
||||
self.assertTrue(
|
||||
(venv / "TEMOIN").exists(), "il a été rebâti pour rien"
|
||||
)
|
||||
|
||||
def test_un_chemin_neuf_est_simplement_cree(self):
|
||||
venv = self.coin / "neuf"
|
||||
fin = self.lance(venv)
|
||||
self.assertEqual(0, fin.returncode, fin.stdout + fin.stderr)
|
||||
self.assertTrue((venv / "pyvenv.cfg").exists())
|
||||
|
||||
|
||||
class TestCeQuIlDetruit(BancInstallVenv):
|
||||
def test_un_venv_d_une_autre_version_est_rebati(self):
|
||||
venv = self.venv_factice("perime", AUTRE)
|
||||
fin = self.lance(venv)
|
||||
self.assertEqual(0, fin.returncode, fin.stdout + fin.stderr)
|
||||
self.assertIn("DESTRUCTION", fin.stdout)
|
||||
self.assertFalse((venv / "TEMOIN").exists())
|
||||
self.assertIn(VOULUE, (venv / "pyvenv.cfg").read_text())
|
||||
|
||||
def test_la_destruction_est_annoncee_avant_d_avoir_lieu(self):
|
||||
"""Dans un journal de milliers de lignes, l'avis doit précéder."""
|
||||
venv = self.venv_factice("perime", AUTRE)
|
||||
fin = self.lance(venv)
|
||||
self.assertLess(
|
||||
fin.stdout.index("DESTRUCTION"),
|
||||
fin.stdout.index("Create Virtual environment"),
|
||||
)
|
||||
|
||||
def test_un_venv_sans_pip_est_rebati(self):
|
||||
"""Ce que laisse « python -m venv » quand ensurepip manque."""
|
||||
venv = self.venv_factice("sans_pip", VOULUE)
|
||||
(venv / "bin" / "activate").unlink()
|
||||
fin = self.lance(venv)
|
||||
self.assertEqual(0, fin.returncode, fin.stdout + fin.stderr)
|
||||
self.assertFalse((venv / "TEMOIN").exists())
|
||||
|
||||
|
||||
class TestLExigenceDePatch(BancInstallVenv):
|
||||
"""Le patch ne borne que le venv d'Odoo, contraint par son pyproject.
|
||||
|
||||
Sur le venv d'outillage, l'exiger écarterait le Python des distributions
|
||||
dès qu'il est d'un cran en retard — et ferait compiler CPython pour une
|
||||
différence que rien ne réclame."""
|
||||
|
||||
PATCH_PLUS_BAS = "9.99.0"
|
||||
DEMANDE = "9.99.4"
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
pose_bouchon(
|
||||
self.coin / "pyenv" / "versions" / self.DEMANDE / "bin" / "python",
|
||||
self.DEMANDE,
|
||||
)
|
||||
|
||||
def joue(self, contexte, venv):
|
||||
return subprocess.run(
|
||||
[str(SCRIPT), contexte, str(venv), self.DEMANDE],
|
||||
cwd=RACINE,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=self.env(),
|
||||
)
|
||||
|
||||
def test_l_outillage_garde_un_patch_plus_ancien(self):
|
||||
venv = self.venv_factice("outils", self.PATCH_PLUS_BAS)
|
||||
fin = self.joue("ERPLibre", venv)
|
||||
self.assertEqual(0, fin.returncode, fin.stdout + fin.stderr)
|
||||
self.assertTrue((venv / "TEMOIN").exists(), fin.stdout)
|
||||
|
||||
def test_odoo_refuse_un_patch_plus_ancien(self):
|
||||
"""Poetry refuserait un patch inférieur à ce que borne le pyproject."""
|
||||
venv = self.venv_factice("odoo", self.PATCH_PLUS_BAS)
|
||||
fin = self.joue("Odoo", venv)
|
||||
self.assertIn("conserve", fin.stdout + fin.stderr)
|
||||
|
||||
def test_une_autre_mineure_ne_passe_jamais(self):
|
||||
venv = self.venv_factice("mineure", "9.98.0")
|
||||
fin = self.joue("ERPLibre", venv)
|
||||
self.assertIn("DESTRUCTION", fin.stdout)
|
||||
|
||||
|
||||
class TestCeQueLeContexteDecide(BancInstallVenv):
|
||||
"""Rebâtir le venv d'outillage coûte une installation pip ; rebâtir celui
|
||||
d'Odoo en refait une de Poetry entière. L'écart de version ne vaut donc
|
||||
destruction que pour le premier."""
|
||||
|
||||
def test_le_venv_odoo_d_une_autre_version_est_conserve(self):
|
||||
venv = self.venv_factice("odoo", AUTRE)
|
||||
fin = self.lance(venv, contexte="Odoo")
|
||||
self.assertEqual(0, fin.returncode, fin.stdout + fin.stderr)
|
||||
self.assertIn("conserve", fin.stdout)
|
||||
self.assertTrue((venv / "TEMOIN").exists())
|
||||
|
||||
def test_le_venv_odoo_hors_service_est_rebati_quand_meme(self):
|
||||
"""Une autre version se tolère ; un interpréteur mort, non."""
|
||||
venv = self.venv_factice("odoo_casse", VOULUE)
|
||||
(venv / "bin" / "python").write_text("#!/bin/sh\nexit 1\n")
|
||||
fin = self.lance(venv, contexte="Odoo")
|
||||
self.assertEqual(0, fin.returncode, fin.stdout + fin.stderr)
|
||||
self.assertIn("DESTRUCTION", fin.stdout)
|
||||
self.assertFalse((venv / "TEMOIN").exists())
|
||||
|
||||
|
||||
class TestCeQuIlRefuse(BancInstallVenv):
|
||||
def test_un_repertoire_sans_pyvenv_cfg_garde_son_contenu(self):
|
||||
pas_un_venv = self.coin / "donnees"
|
||||
(pas_un_venv / "sous").mkdir(parents=True)
|
||||
(pas_un_venv / "sous" / "PRECIEUX").write_text("ne pas effacer\n")
|
||||
fin = self.lance(pas_un_venv)
|
||||
self.assertEqual(1, fin.returncode)
|
||||
self.assertIn("Refus de detruire", fin.stdout)
|
||||
self.assertTrue((pas_un_venv / "sous" / "PRECIEUX").exists())
|
||||
|
||||
def test_un_venv_monte_a_distance_est_epargne(self):
|
||||
"""Il appartient à une autre machine : l'effacer traverse le réseau."""
|
||||
faux_findmnt = self.bin / "findmnt"
|
||||
faux_findmnt.write_text("#!/bin/sh\necho fuse.sshfs\n")
|
||||
faux_findmnt.chmod(0o755)
|
||||
venv = self.venv_factice("monte", AUTRE)
|
||||
fin = self.lance(venv)
|
||||
self.assertEqual(1, fin.returncode)
|
||||
self.assertIn("monte a distance", fin.stdout)
|
||||
self.assertTrue((venv / "TEMOIN").exists())
|
||||
|
||||
def test_un_repertoire_vide_ne_demande_pas_d_intervention(self):
|
||||
"""Rien à perdre : rmdir suffit, et l'installation continue."""
|
||||
vide = self.coin / "vide"
|
||||
vide.mkdir()
|
||||
fin = self.lance(vide)
|
||||
self.assertEqual(0, fin.returncode, fin.stdout + fin.stderr)
|
||||
self.assertNotIn("Refus", fin.stdout)
|
||||
|
||||
def test_la_racine_est_refusee(self):
|
||||
fin = subprocess.run(
|
||||
[str(SCRIPT), "ERPLibre", "/", VOULUE],
|
||||
cwd=RACINE,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=self.env(),
|
||||
)
|
||||
self.assertEqual(1, fin.returncode)
|
||||
self.assertNotIn("DESTRUCTION", fin.stdout)
|
||||
|
||||
|
||||
class TestSansInterpreteur(BancInstallVenv):
|
||||
def test_aucune_destruction_quand_l_interpreteur_manque(self):
|
||||
"""L'interpréteur est obtenu AVANT : sinon on reste sans venv."""
|
||||
venv = self.venv_factice("perime", AUTRE)
|
||||
env = dict(self.env(), PYENV_ROOT=str(self.coin / "nulle_part"))
|
||||
fin = subprocess.run(
|
||||
[str(SCRIPT), "ERPLibre", str(venv), VOULUE],
|
||||
cwd=RACINE,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=env,
|
||||
)
|
||||
self.assertEqual(1, fin.returncode)
|
||||
self.assertTrue((venv / "TEMOIN").exists())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Reference in a new issue