gestion_table_tournante_libre/scripts/verifier_systemes.sh
Mathieu Benoit b9090508ff [ADD] run: make and ./run.sh, Electron start check, container matrix
make with no target does what ./run.sh does: Electron on a graphical
session, Vite's server without one or where Electron is not published
(s390x, ppc64le). Every npm, npx and node recipe goes through the
project's Node. make essai_demarrage starts the real Electron through
Playwright and reads its window title, on Chromium's headless Ozone
platform when there is no display: no X server is needed.
scripts/verifier_systemes.sh replays install and tests in podman over
the QEMU catalogue of TODO, and stops only its own containers.

Checked: 17 Linux images and Nix pass all six steps; pwsh parses.

--- FR ---

[ADD] lancement : make et ./run.sh, essai d'Electron, matrice

make sans cible fait ce que fait ./run.sh : Electron sur une session
graphique, le serveur de Vite sans elle ou là où Electron n'est pas
publié (s390x, ppc64le). Chaque recette npm, npx ou node passe par le
Node du projet. make essai_demarrage lance la vraie coquille Electron
par Playwright et lit le titre de sa fenêtre, sur la plateforme Ozone
headless de Chromium sans écran : aucun serveur X n'est requis.
scripts/verifier_systemes.sh rejoue installation et épreuves sous
podman sur le catalogue QEMU de TODO, et n'arrête que ses conteneurs.

Vérifié : 17 images Linux et Nix passent les six étapes ; pwsh analyse.

Assisted-by: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01EUXSGcwCLSC69FWEdCtWSb
2026-10-06 05:52:17 -04:00

244 lines
9.3 KiB
Bash
Executable file

#!/usr/bin/env bash
# © 2026 TechnoLibre (http://www.technolibre.ca)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
# Installe et éprouve le projet sur chaque système du catalogue de machines
# virtuelles de TODO (ERPLibre), chacun dans un conteneur podman : sous un
# compte ordinaire qui passe par sudo, ./install_dev.sh, puis make test,
# make test_long, make test_navigateur, l'essai de démarrage d'Electron, et
# le serveur de Vite. Les scripts PowerShell s'éprouvent sous pwsh.
#
# scripts/verifier_systemes.sh tout le catalogue
# scripts/verifier_systemes.sh debian-13 arch ces systèmes
# scripts/verifier_systemes.sh --liste les systèmes connus
#
# Ce qu'un conteneur n'éprouve pas : le bac à sable d'Electron (pas d'espaces
# de noms d'utilisateur, Electron s'y lance sans), une autre architecture
# que celle de l'hôte, NixOS lui-même (l'image nix éprouve shell.nix, sur
# une base qui n'est pas NixOS), une vraie session graphique.
#
# GTT_PARALLELES (4 par défaut) borne les conteneurs simultanés ; les
# journaux vont dans GTT_JOURNAUX, un dossier temporaire par défaut. Les
# téléchargements — npm, Electron, Chromium, Node — se partagent entre
# conteneurs par des volumes nommés gttl-cache-*.
set -euo pipefail
racine="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
# Système, image : le catalogue de script/qemu/deploy_qemu.py d'ERPLibre.
# Proxmox VE 9 est Debian 13 sous ses paquets : debian-13 le représente.
CATALOGUE='
ubuntu-24.04 docker.io/library/ubuntu:24.04
ubuntu-25.10 docker.io/library/ubuntu:25.10
ubuntu-26.04 docker.io/library/ubuntu:26.04
debian-12 docker.io/library/debian:12
debian-13 docker.io/library/debian:13
fedora-41 docker.io/library/fedora:41
fedora-42 docker.io/library/fedora:42
fedora-43 docker.io/library/fedora:43
fedora-44 docker.io/library/fedora:44
almalinux-9 docker.io/library/almalinux:9
almalinux-10 docker.io/library/almalinux:10
rocky-9 docker.io/rockylinux/rockylinux:9
rocky-10 docker.io/rockylinux/rockylinux:10
opensuse-leap-16.0 registry.opensuse.org/opensuse/leap:16.0
opensuse-tumbleweed registry.opensuse.org/opensuse/tumbleweed:latest
arch docker.io/library/archlinux:latest
nix docker.io/nixos/nix:latest
pwsh mcr.microsoft.com/powershell:latest
'
usage() {
sed -n '9,12p' "$0" | sed 's/^# \{0,1\}//'
}
image_de() {
printf '%s\n' "$CATALOGUE" | awk -v s="$1" '$1 == s { print $2 }'
}
systemes=()
for argument in "$@"; do
case "$argument" in
--liste)
printf '%s\n' "$CATALOGUE" | awk 'NF { print $1 }'
exit 0
;;
-h | --help)
usage
exit 0
;;
-*)
usage >&2
exit 2
;;
*)
[ -n "$(image_de "$argument")" ] || { echo "système inconnu : $argument (--liste)" >&2; exit 2; }
systemes+=("$argument")
;;
esac
done
if [ ${#systemes[@]} -eq 0 ]; then
while read -r s _; do
[ -n "$s" ] && systemes+=("$s")
done <<< "$CATALOGUE"
fi
command -v podman > /dev/null || { echo "podman introuvable." >&2; exit 1; }
journaux="${GTT_JOURNAUX:-$(mktemp -d "${TMPDIR:-/tmp}/verifier_systemes.XXXXXX")}"
mkdir -p "$journaux"
# Étiquette des conteneurs de cette vérification : une interruption arrête
# ceux-là, et aucun autre conteneur de la machine.
ETIQUETTE="gttl-verification=$$"
arreter() {
podman ps -q --filter "label=$ETIQUETTE" | xargs -r podman stop -t 2 > /dev/null 2>&1 || true
}
trap 'arreter; exit 130' INT
trap 'arreter; exit 143' TERM
# Copie de l'arbre de travail tel qu'il est — fichiers suivis et nouveaux
# non ignorés —, sans node_modules : chaque conteneur part de zéro.
source_copie="$journaux/source"
rm -rf "$source_copie"
mkdir -p "$source_copie"
(cd "$racine" && git ls-files -co --exclude-standard -z | tar --null -cf - -T - | tar -xf - -C "$source_copie")
# Préparation sous root, par famille : sudo et un compte ordinaire « dev »
# qui l'emploie sans mot de passe, comme un poste de développement. Son uid
# est le même dans chaque conteneur — 1500, libre aussi sous Ubuntu, dont
# l'image donne 1000 à son propre compte — : les caches partagés ne
# changent jamais de propriétaire.
preparation() {
case "$1" in
ubuntu-* | debian-*) echo 'apt-get update -q && DEBIAN_FRONTEND=noninteractive apt-get install -y -q sudo' ;;
fedora-* | almalinux-* | rocky-*) echo 'dnf install -y sudo shadow-utils' ;;
opensuse-*) echo 'zypper --non-interactive install sudo shadow' ;;
arch) echo 'pacman -Syu --noconfirm sudo' ;;
esac
}
# Étapes sous le compte dev, chacune annoncée par une ligne « === étape
# statut » que le bilan relit. L'essai et le serveur de Vite ne se jouent
# que sur une installation réussie.
ETAPES_DEV='
etape() { local nom="$1"; shift; if "$@"; then echo "=== $nom ok"; else echo "=== $nom ÉCHEC"; return 1; fi; }
cd "$HOME/projet"
etape install_dev ./install_dev.sh || exit 1
etape test make test
etape test_long make test_long
etape test_navigateur make test_navigateur
etape essai_demarrage env GTT_SANS_BAC_A_SABLE=1 make essai_demarrage
web() {
./run.sh --web > "$HOME/web.log" 2>&1 &
scripts/installation/avec_node.sh node -e "
const fin = Date.now() + 60000;
(async () => {
while (Date.now() < fin) {
try {
const page = await (await fetch(\"http://localhost:5173/\")).text();
if (page.includes(\"/src/main.js\")) process.exit(0);
} catch {}
await new Promise((r) => setTimeout(r, 500));
}
process.exit(1);
})();"
}
etape web web
'
verifier_linux() {
local systeme="$1" image="$2"
podman run --rm --env-host=false --label "$ETIQUETTE" \
-v "$source_copie:/source:ro" \
-v gttl-cache-npm:/home/dev/.npm \
-v gttl-cache-outils:/home/dev/.cache \
"$image" bash -c "
set -e
$(preparation "$systeme")
useradd -m -u 1500 -s /bin/bash dev 2> /dev/null || true
echo 'dev ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/dev
cp -a /source /home/dev/projet
chown -R dev: /home/dev/projet
chown dev: /home/dev /home/dev/.npm /home/dev/.cache
sudo -u dev -H bash -c '$ETAPES_DEV'
"
}
# L'image nix tourne sous root, sans sudo ni useradd : elle éprouve
# shell.nix, que GTT_FAMILLE désigne, sur une base qui n'est pas NixOS.
# ./install.sh y entre de lui-même ; make n'existe que dans shell.nix, où
# les étapes suivantes s'exécutent, comme sous NixOS.
verifier_nix() {
podman run --rm --env-host=false --label "$ETIQUETTE" -e GTT_FAMILLE=nixos \
-v "$source_copie:/source:ro" \
"$2" sh -c "
cp -a /source /root/projet
export HOME=/root
cd /root/projet
if nix-shell -p bash --run ./install.sh; then echo '=== entree_shell_nix ok'; else echo '=== entree_shell_nix ÉCHEC'; exit 1; fi
nix-shell scripts/installation/shell.nix --run 'bash -c '\''$ETAPES_DEV'\'''
"
}
# Les scripts PowerShell sous pwsh : l'analyse syntaxique de chacun, puis la
# lecture de .node-version, le choix de l'archive dans SHASUMS256.txt, et le
# téléchargement, la vérification et l'extraction de Node pour win-x64 —
# node.exe ne s'exécute pas ici, son extraction se constate.
verifier_pwsh() {
podman run --rm --env-host=false --label "$ETIQUETTE" -v "$source_copie:/source:ro" "$2" pwsh -NoProfile -Command '
$ErrorActionPreference = "Stop"
$erreurs = 0
foreach ($f in Get-ChildItem /source/scripts/windows/*.ps1) {
$jetons = $null; $fautes = $null
[void][System.Management.Automation.Language.Parser]::ParseFile($f.FullName, [ref]$jetons, [ref]$fautes)
if ($fautes.Count -gt 0) { $erreurs++; Write-Host "$($f.Name) : $($fautes[0].Message)" }
}
if ($erreurs -eq 0) { Write-Host "=== analyse ok" } else { Write-Host "=== analyse ÉCHEC"; exit 1 }
Copy-Item -Recurse /source /tmp/projet
$env:LOCALAPPDATA = "/tmp/donnees"
$env:PROCESSOR_ARCHITECTURE = "AMD64"
try { . /tmp/projet/scripts/windows/commun.ps1 } catch { Write-Host "=== chargement ÉCHEC $_"; exit 1 }
Write-Host "=== chargement ok"
$choix = Find-GttArchiveNode @("a1 node-v26.10.0-win-x64.7z", "b2 node-v26.10.0-win-x64.zip", "c3 node-v26.10.0-win-arm64.zip") "x64"
if ("$choix" -eq "b2 node-v26.10.0-win-x64.zip" -and (Get-GttMajeure) -match "^[0-9]+$") { Write-Host "=== choix ok" } else { Write-Host "=== choix ÉCHEC $choix"; exit 1 }
try { Install-GttNode } catch { }
if (Test-Path (Join-Path (Get-GttDossierNode) "node.exe")) { Write-Host "=== node_windows ok" } else { Write-Host "=== node_windows ÉCHEC"; exit 1 }
'
}
verifier() {
local systeme="$1" image journal
image="$(image_de "$systeme")"
journal="$journaux/$systeme.log"
{
echo "### $systeme ($image)"
case "$systeme" in
nix) verifier_nix "$systeme" "$image" ;;
pwsh) verifier_pwsh "$systeme" "$image" ;;
*) verifier_linux "$systeme" "$image" ;;
esac
} > "$journal" 2>&1 || true
echo "$systeme : $(grep -c '^=== .* ok$' "$journal") ok, $(grep -c '^=== .* ÉCHEC' "$journal") échec(s)"
}
paralleles="${GTT_PARALLELES:-4}"
echo "Journaux : $journaux"
for systeme in "${systemes[@]}"; do
while [ "$(jobs -rp | wc -l)" -ge "$paralleles" ]; do
sleep 2
done
verifier "$systeme" &
done
wait
echo
echo "Bilan :"
statut=0
for systeme in "${systemes[@]}"; do
ligne="$(grep '^=== ' "$journaux/$systeme.log" | sed 's/^=== //' | tr '\n' ' ')"
case "$ligne" in
'' | *ÉCHEC*) statut=1 ;;
esac
printf ' %-22s %s\n' "$systeme" "${ligne:-aucune étape (voir $journaux/$systeme.log)}"
done
exit "$statut"