erplibre/script/install/install_suse_dependency.sh
Mathieu Benoit a579cc9cf3 [FIX] install: the EL9, EL10 and Fedora build chain
"dnf install: error: unrecognized arguments" on AlmaLinux 10 and Rocky 10,
on every call: PostgreSQL, build dependencies, pyenv. The tools group got
away with its fallback, which made the trace misleading -- gcc installed,
nothing after it did.

"--skip-unavailable" is a dnf5 option, which the script's own comment
already said while assuming it everywhere. Fedora 41+ ships dnf5, but EL9
and EL10 stay on dnf4, whose equivalent is "--setopt=strict=0". We now ask
dnf what it understands instead of inferring it from the distribution.

Three neighbouring fixes: the "c-development" group does not exist on EL,
where it is called "development"; CRB is enabled through /usr/bin/crb; and
g++ plus the missing headers are installed explicitly. Rust is added only
where wheels are absent, and qpdf is built when the distribution ships one
older than pikepdf demands.

--- FR ---

« dnf install: error: unrecognized arguments » sur AlmaLinux 10 et
Rocky 10, à chaque appel : PostgreSQL, dépendances de compilation, pyenv.
Le groupe d'outils s'en tirait par son repli, ce qui rendait la trace
trompeuse — gcc installé, rien après lui.

« --skip-unavailable » est une option de dnf5, ce que le commentaire du
script disait déjà tout en la supposant partout. Fedora 41+ livre dnf5,
mais EL9 et EL10 restent sur dnf4, dont l'équivalent est
« --setopt=strict=0 ». On demande maintenant à dnf ce qu'il comprend
plutôt que de le déduire de la distribution.

Trois correctifs voisins : le groupe « c-development » n'existe pas sur
EL, où il s'appelle « development » ; CRB s'active par /usr/bin/crb ; et
g++ ainsi que les en-têtes manquants sont posés explicitement. Rust n'est
ajouté que là où les roues manquent, et qpdf est compilé quand la
distribution en livre un plus ancien que ce qu'exige pikepdf.

Assisted-by: Claude Opus 5
2026-08-16 23:33:49 -04:00

338 lines
15 KiB
Bash
Executable file

#!/usr/bin/env bash
# © 2021-2026 TechnoLibre (http://www.technolibre.ca)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
#
# Dépendances système ERPLibre pour la famille SUSE (zypper). Équivalent SUSE
# de install_debian_dependency.sh et install_fedora_dependency.sh.
#
# Visé : openSUSE Tumbleweed, la seule distribution du catalogue dont qpdf
# (12.3.2) dépasse déjà le seuil de pikepdf 10 — la compilation de qpdf, une
# demi-heure sous émulation s390x, ne s'y déclenche pas.
. ./env_var.sh
. ./script/install/lib_qpdf.sh
EL_USER=${USER}
# « --non-interactive » est une option GLOBALE de zypper, elle précède la
# sous-commande. Les deux autres appartiennent à « install » et doivent la
# SUIVRE : placées avant, zypper répond « The flag
# --auto-agree-with-licenses is not known » et s'arrête.
#
# On demande à zypper quelles options il accepte, plutôt que de le supposer :
# la famille SUSE n'est pas testée ici, et un drapeau inconnu fait échouer la
# commande entière au lieu du seul paquet visé.
# --auto-agree-with-licenses : sinon zypper attend l'acceptation d'une
# licence, réponse que personne ne donnera dans une installation détachée.
# --ignore-unknown : saute un nom de paquet absent au lieu de refuser tout
# le lot, l'équivalent de « --skip-unavailable » côté dnf.
ZYP="sudo zypper --non-interactive"
ZYP_HELP="$(zypper install --help 2>&1 || true)"
ZYP_LIC=""
ZYP_IGN=""
case "${ZYP_HELP}" in
*--auto-agree-with-licenses*) ZYP_LIC="--auto-agree-with-licenses" ;;
esac
case "${ZYP_HELP}" in
*--ignore-unknown*) ZYP_IGN="--ignore-unknown" ;;
esac
echo "zypper : options retenues = ${ZYP_LIC} ${ZYP_IGN}"
# Lot obligatoire : un paquet manquant doit se voir.
ZYP_IN="${ZYP} install ${ZYP_LIC}"
# Lot best-effort : un nom absent est sauté.
ZYP_SOFT="${ZYP_IN} ${ZYP_IGN}"
# openSUSE remplace des paquets par des variantes « compat » qui les FOURNISSENT
# sans en porter le nom : sur Tumbleweed, zlib-ng-compat-devel fournit
# zlib-devel et se trouve posé d'office. Demander « zlib-devel » par son nom
# force alors un échange, zypper soulève un conflit — et --non-interactive n'a
# aucune solution par défaut : il énumère les choix, puis ABANDONNE le lot
# entier. C'est ce qui a arrêté l'installation sur amd64, en emportant les huit
# autres dépendances de pyenv qui, elles, ne posaient aucun problème.
# « --ignore-unknown » ne couvre que les noms absents, jamais les conflits.
#
# On ne demande donc que ce que rien ne fournit déjà. rpm interroge les
# « Provides », pas seulement les noms : c'est la seule autorité sur la
# question. Effet de bord bienvenu, une relance ne redemande plus rien.
zyp_filter() {
local p
for p in "$@"; do
rpm -q --whatprovides "${p}" > /dev/null 2>&1 || printf '%s\n' "${p}"
done
}
# Un telechargement tronque par le miroir fait echouer le LOT ENTIER, et
# zypper ne reessaie pas. Vecu : « libLLVM22 ... OpenSSL SSL_read: unexpected
# eof while reading » a emporte « rust cargo », et l'absence de cargo n'est
# apparue qu'une heure plus tard, dans la compilation de bcrypt. Une seconde
# tentative suffit dans la quasi-totalite des cas.
zyp_retry() {
local cmd=("$@")
"${cmd[@]}" && return 0
echo " zypper a echoue (reseau ?), seconde tentative..." >&2
"${cmd[@]}"
}
zyp_in() {
local todo
mapfile -t todo < <(zyp_filter "$@")
if [ "${#todo[@]}" -eq 0 ]; then
echo " deja fourni : $*"
return 0
fi
zyp_retry ${ZYP_IN} "${todo[@]}"
}
zyp_soft() {
local todo
mapfile -t todo < <(zyp_filter "$@")
if [ "${#todo[@]}" -eq 0 ]; then
echo " deja fourni : $*"
return 0
fi
zyp_retry ${ZYP_SOFT} "${todo[@]}"
}
#--------------------------------------------------
# Miroir des dépôts
#--------------------------------------------------
# Le redirecteur officiel d'openSUSE n'est PAS géographique : mesuré depuis
# Montréal sur les métadonnées oss s390x (15 Mo), download.opensuse.org met
# 23,8 s — il sert depuis l'Europe — contre 2,7 s pour mirrors.rit.edu.
#
# Chaque miroir est SONDÉ sur le chemin de l'architecture courante : tous ne
# répliquent pas les architectures secondaires, et rit.edu sert justement
# zsystems mais pas x86_64. Aucun sondage concluant : on garde les dépôts de
# l'image, donc le comportement d'avant.
# Plusieurs miroirs, sondés dans l'ordre sur le chemin exact du produit et
# de l'architecture : aucun ne réplique tout. Relevé le 2026-08-12 —
# csclub sert Leap mais pas Tumbleweed, leaseweb sert Tumbleweed x86_64
# mais pas les ports zsystems, et rit.edu — seule entrée jusqu'ici — était
# injoignable ce jour-là, ce qui renvoyait tout le monde en Europe.
ZYP_MIRRORS="https://mirror.csclub.uwaterloo.ca/opensuse https://mirrors.rit.edu/opensuse https://mirror.us.leaseweb.net/opensuse"
# Leap et Tumbleweed sont deux PRODUITS, pas deux versions du même : arbres de
# dépôts différents, et surtout une mise à jour de nature différente (plus bas).
SUSE_ID="$([ -r /etc/os-release ] && . /etc/os-release && echo "${ID}")"
SUSE_VER="$([ -r /etc/os-release ] && . /etc/os-release && echo "${VERSION_ID}")"
case "${SUSE_ID}" in
*tumbleweed*) SUSE_ROLLING=1 ;;
*) SUSE_ROLLING=0 ;;
esac
if [ "${SUSE_ROLLING}" = 1 ]; then
# Tumbleweed isole les architectures secondaires sous /ports/.
zp=tumbleweed
[ "$(uname -m)" = s390x ] && zp=ports/zsystems/tumbleweed
else
# Leap 16 unifie tout : un seul arbre, avec s390x dedans. Les chemins
# /ports/ équivalents rendent 404 — relevé, pas déduit.
zp="distribution/leap/${SUSE_VER}"
fi
for zm in ${ZYP_MIRRORS}; do
if curl -fsS --max-time 20 -o /dev/null \
"${zm}/${zp}/repo/oss/repodata/repomd.xml"; then
sudo sed -i "s|https\?://download\.opensuse\.org|${zm}|g" \
/etc/zypp/repos.d/*.repo 2> /dev/null || true
echo "miroir openSUSE : ${zm}"
break
fi
done
echo -e "\n---- Rafraichissement des depots ----"
# Tumbleweed est ROLLING : installer sans rafraîchir mène à des paquets
# introuvables (l'index local pointe des versions déjà retirées du miroir).
sudo zypper --non-interactive refresh || true
# Mise à jour COMPLÈTE, obligatoire pour la même raison qu'Arch : une rolling
# release ne supporte PAS les mises à jour partielles. L'image cloud est un
# instantané figé dont les dépôts ont avancé — vécu sur s390x, git 2.54
# réclamait un perl-Git bâti contre un perl-base plus ancien que celui de
# l'image. zypper proposait alors trois solutions et ATTENDAIT un choix ;
# « --non-interactive » prend le défaut, « c » = annuler, et tout s'arrêtait.
echo -e "\n---- Mise a jour complete (dup) ----"
${ZYP} dup ${ZYP_LIC} --allow-vendor-change || true
#--------------------------------------------------
# Outils de compilation (build Python via pyenv, extensions Python)
#--------------------------------------------------
echo -e "\n---- Outils de developpement ----"
# Les compilateurs sont installés EXPLICITEMENT, jamais par le seul motif :
# un « pattern » absent ou incomplet laisserait le système sans g++, et
# l'échec n'apparaîtrait qu'à la compilation de numpy — la leçon d'EL, où le
# groupe « development-tools » n'existe pas et où le repli ne partait jamais.
# Les noms non versionnés existent bien dans Tumbleweed (relevé dans le
# primary.xml du dépôt oss) : « gcc » y est un méta-paquet qui tire gcc15.
zyp_in gcc gcc-c++ make automake patch
retVal=$?
if [[ ${retVal} -ne 0 ]]; then
echo "zypper install compilers error."
exit 1
fi
# Le motif ensuite, en complément et sans jamais bloquer.
${ZYP_IN} -t pattern devel_basis > /dev/null 2>&1 || true
# Python appelle son compilateur par le nom gravé dans sysconfig, souvent
# « cc ». Sur openSUSE ce lien n'est garanti par aucune déclaration de
# paquet — vécu sur amd64 : « cc -pthread … error: [Errno 2] No such file or
# directory » à la compilation de python-ldap, alors que gcc était installé.
if ! command -v cc > /dev/null 2>&1 && command -v gcc > /dev/null 2>&1; then
sudo ln -sf "$(command -v gcc)" /usr/local/bin/cc
echo "cc -> $(command -v gcc)"
fi
#--------------------------------------------------
# PostgreSQL
#--------------------------------------------------
echo -e "\n---- Install PostgreSQL Server ----"
zyp_in postgresql-server postgresql-contrib postgresql-server-devel
retVal=$?
if [[ ${retVal} -ne 0 ]]; then
echo "zypper install postgresql installation error."
exit 1
fi
# openSUSE n'initialise pas le cluster : le service le fait au 1er démarrage,
# mais seulement si le répertoire de données est vide.
sudo systemctl enable --now postgresql 2> /dev/null || true
# PostGIS : absent des dépôts Tumbleweed s390x. Optionnel, ne bloque pas.
zyp_soft postgis || echo "PostGIS non installe (optionnel)."
echo -e "\n---- Creating the ERPLibre PostgreSQL User ----"
sudo su - postgres -c "createuser -s ${EL_USER}" 2> /dev/null || true
#--------------------------------------------------
# Dépendances de build (extensions Python, Odoo)
#--------------------------------------------------
echo -e "\n--- Installing suse dependency --"
# git-daemon : comme sur Fedora, « git daemon » n'est pas dans le paquet git de
# base. ERPLibre sert son manifeste par git://127.0.0.1:9418/ pendant
# « repo sync » — sans lui, « Connection refused » et synchro impossible.
# Rust n'est nécessaire QUE là où les roues manquent : bcrypt et cryptography
# portent une extension Rust, et sur amd64 leurs roues masquent le besoin. Sur
# s390x tout compile, et bcrypt s'arrête sur « error: can't find Rust
# compiler ». Tumbleweed livre 1.94, bien au-dessus du 1.78 qu'exige le
# Cargo.lock v4 de cryptography. On évite ainsi ~200 Mo inutiles sur amd64.
if [ "$(uname -m)" = "s390x" ]; then
zyp_soft rust cargo
if ! command -v cargo > /dev/null 2>&1; then
# FATAL, et non plus un simple avertissement : sur s390x, bcrypt et
# cryptography n'ont aucune roue et portent une extension Rust. Sans
# cargo l'installation est perdue d'avance — mais elle ne le montrait
# qu'une heure plus tard, au fond d'une trace pip. Mieux vaut s'arreter
# ici, ou la cause est encore lisible.
echo "cargo introuvable apres deux tentatives." >&2
echo " bcrypt et cryptography ne peuvent pas se compiler sans lui." >&2
echo " Verifiez le miroir zypper, puis relancez." >&2
exit 1
fi
# Sans roue s390x, TOUT se compile contre les en-têtes de la distribution.
# Cette liste reprend donc celles d'apt et de dnf, aux noms d'openSUSE près
# — relevés dans l'index oss de zsystems, jamais devinés. La tenir alignée
# ici plutôt que d'attendre : trois fois de suite, le même manque a été
# découvert d'abord par Debian, puis retrouvé une distribution à la fois.
# tbb-devel manifold3d refuse de configurer sans lui, et le dit dans un
# message de CMake, pas de compilateur : « Parallel mode
# enabled, but tbb was not found ».
# clang-devel pymupdf charge libclang.so par ctypes (lien juste après).
# cmake, pkgconf-pkg-config : nécessaires à el_qpdf_ensure, et ils
# n'arrivent que plus bas dans le script.
#
# « pkgconf-pkg-config » et non « pkg-config » : aucun RPM ne porte ce
# dernier nom dans Tumbleweed, il n'existe plus que comme capacité fournie
# par le premier. La capacité résout aujourd'hui, le nom réel ne dépend
# de rien.
#
# GeographicLib est absent : openSUSE n'empaquette que le binding Python,
# pas la bibliothèque C++. Rien à poser, contrairement à apt et dnf.
zyp_soft qpdf-devel libjpeg8-devel cmake pkgconf-pkg-config \
tbb-devel geos-devel proj-devel krb5-devel ninja clang-devel llvm-devel
# Tumbleweed livre qpdf 12.3.2 : l'appel ne fait que le constater. Il est là
# pour que les trois familles suivent la même règle.
el_qpdf_ensure
# pymupdf charge « libclang.so » par son nom nu, via ctypes ; le paquet ne
# livre qu'un nom versionné. Il ne manque que le lien — même correctif que
# côté apt et dnf.
for d in /usr/lib64 /usr/lib; do
if [ -d "${d}" ] && [ ! -e "${d}/libclang.so" ]; then
so="$(ls -1 "${d}"/libclang.so.* 2> /dev/null | sort -V | tail -1)"
if [ -n "${so}" ]; then
sudo ln -s "${so}" "${d}/libclang.so" && sudo ldconfig
echo "libclang.so -> ${so}"
fi
fi
done
fi
zyp_soft \
git git-daemon wget libxslt-devel libzip-devel openldap2-devel \
cyrus-sasl-devel libffi-devel libbz2-devel gnu_parallel swig cmake \
portaudio-devel cups-devel xmlsec1 xmlsec1-openssl-devel \
libmariadb-devel freetds-devel
retVal=$?
if [[ ${retVal} -ne 0 ]]; then
echo "zypper suse tool installation error."
exit 1
fi
# Dépendances de build pour pyenv (compilation de CPython) — CRITIQUE.
echo -e "\n---- Dependances pyenv (compilation Python) ----"
zyp_in \
make gcc zlib-devel libbz2-devel readline-devel sqlite3-devel \
libopenssl-devel tk-devel libffi-devel xz-devel patch findutils
retVal=$?
if [[ ${retVal} -ne 0 ]]; then
echo "zypper pyenv dependencies installation error."
exit 1
fi
# Dépendances selenium / bindings.
zyp_soft \
cairo-devel python3-devel pkgconf-pkg-config gobject-introspection-devel \
libXt-devel || echo "Dependances selenium partielles (optionnel)."
#--------------------------------------------------
# Node.js + npm (rtlcss, less)
#--------------------------------------------------
echo -e "\n---- Installing nodeJS NPM and rtlcss ----"
# openSUSE versionne les paquets node (nodejs22, nodejs24…) et ne fournit pas
# toujours de méta-paquet « nodejs ». On prend le plus récent disponible.
NODE_OK=0
for pkg in nodejs24 nodejs22 nodejs20 nodejs; do
if ${ZYP_IN} "${pkg}" "${pkg/nodejs/npm}" 2> /dev/null; then
NODE_OK=1
echo "node fourni par ${pkg}"
break
fi
done
if [[ ${NODE_OK} -ne 1 ]] || ! command -v npm > /dev/null 2>&1; then
echo "zypper nodejs installation error."
exit 1
fi
sudo npm install -g rtlcss less || echo "npm rtlcss/less: erreur (optionnel)."
echo -e "\n---- Test tool ----"
npm install || echo "npm install (prettier/plugin-xml): erreur (optionnel)."
sudo ln -fs /usr/local/bin/lessc /usr/bin/lessc 2> /dev/null || true
#--------------------------------------------------
# nginx (optionnel)
#--------------------------------------------------
if [ "${EL_INSTALL_NGINX}" = "True" ]; then
echo -e "\n---- Installing nginx ----"
zyp_soft nginx || echo "nginx: erreur (optionnel)."
fi
#--------------------------------------------------
# wkhtmltopdf (optionnel)
#--------------------------------------------------
if [ "${EL_INSTALL_WKHTMLTOPDF}" = "True" ]; then
if ! command -v wkhtmltopdf > /dev/null 2>&1; then
echo -e "\n---- Installing wkhtml (best-effort) ----"
# wkhtmltopdf ne publie AUCUN paquet openSUSE. Le dépôt de la distribution
# fournit « wkhtmltopdf » quand il existe pour l'architecture ; sinon on
# renonce, Odoo sait imprimer sans lui (rendu dégradé des PDF).
zyp_soft wkhtmltopdf || echo "wkhtmltopdf non installe (optionnel)."
else
echo -e "\n---- Already installed wkhtml ----"
fi
fi
echo -e "\n---- SUSE dependency installation done ----"