Files
nocode 7730ac7b00 feat(build): add preflight package resolution and fws-dnd package
Add preflight package resolution step in build-offi.sh to validate all profile
packages against pacman repositories before mkarchiso execution. This prevents
'target not found' errors during ISO creation by catching missing packages early
with helpful error messages and recovery instructions.

Introduce fws-dnd package (D&D 5e manager for FWS with GTK4 interface) to the
local package build process in setup-aur.sh. Include PKGBUILD definition and
source tarball.

When package resolution fails, the build now exits with clear feedback pointing
users to run setup-aur.sh to build missing dependencies like fws-dnd.
2026-07-07 21:39:29 +02:00

349 lines
17 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ============================================================
# FWS — Build des paquets AUR (winboat-bin) + PKGBUILD locaux (deps Anaconda,
# fws-dnd) et création du repo pacman local fws-local/.
#
# Rejoue-le si tu changes la liste AUR_PACKAGES ou pour
# rafraîchir le repo local.
# ============================================================
set -e
trap 'rc=$?; echo -e "\033[0;31m[ERR] Échec (setup-aur.sh) ligne $LINENO, code $rc.\033[0m" >&2; exit $rc' ERR
# Paquets AUR à construire, DANS L'ORDRE (les deps avant les dépendants ; la
# boucle plus bas installe chaque paquet après build pour résoudre les chaînes).
# - libxmlrpc, satyr : deps de libreport (deps officielles uniquement)
# - libreport : tiré par python-meh ; chaîne AUR→AUR → APRÈS satyr+libxmlrpc
# - winboat-bin : app FWS
# - python-* : deps Anaconda présentes dans l'AUR (deps officielles only)
# python-blivet est packagé en LOCAL (pkgbuilds/, patché sans libselinux).
# gnome-kiosk (WM de la session GUI) est différé au chantier C.
# NB : python-iso639 RETIRÉ de l'AUR (mauvais projet homonyme, API sans find()) →
# packagé en LOCAL (pkgbuilds/python-iso639, projet PyPI « iso639 » 0.1.4).
# NB : python-langtable RETIRÉ de l'AUR (figé 0.0.51, sans list_common_languages) →
# packagé en LOCAL (pkgbuilds/python-langtable, 0.0.71).
AUR_PACKAGES=(libxmlrpc satyr libreport winboat-bin python-pid python-xkbregistry python-requests-ftp)
DISTRO_NAME="${ARCH_WSL_DISTRO:-Arch}"
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
BLUE='\033[0;34m'; CYAN='\033[0;36m'; NC='\033[0m'
info() { echo -e "${BLUE}==>${NC} $1"; }
success() { echo -e "${GREEN}[OK]${NC} $1"; }
warn() { echo -e "${YELLOW}[!!]${NC} $1"; }
error() { echo -e "${RED}[ERR]${NC} $1"; exit 1; }
step() { echo -e "\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${CYAN} $1${NC}"
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"; }
# ============================================================
# Bascule Git Bash → WSL si besoin
# ============================================================
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || -n "$WINDIR" ]]; then
info "Git Bash détecté — bascule dans WSL ($DISTRO_NAME)..."
export MSYS_NO_PATHCONV=1
export MSYS2_ARG_CONV_EXCL="*"
# WSL doit être présent.
command -v wsl.exe >/dev/null 2>&1 \
|| error "WSL introuvable — PowerShell admin : 'wsl --install', puis installe une distro Arch et relance."
# Choix de la distro Arch : override $ARCH_WSL_DISTRO, sinon nom exact,
# sinon 1re distro « arch » réellement joignable (énum via `wsl -l -q`,
# sortie UTF-16LE → on retire NUL/CR ; on garde la sonde « echo ok »).
pick_arch_distro() {
wsl.exe -d "$DISTRO_NAME" -u root -- echo ok >/dev/null 2>&1 && return 0
local d distros=()
mapfile -t distros < <(wsl.exe -l -q 2>/dev/null | tr -d '\0\r' | sed 's/[[:space:]]*$//;/^$/d')
for d in "${distros[@]}"; do
[[ "$d" == "$DISTRO_NAME" ]] || continue
wsl.exe -d "$d" -u root -- echo ok >/dev/null 2>&1 && { DISTRO_NAME="$d"; return 0; }
done
for d in "${distros[@]}"; do
[[ "$d" =~ [Aa][Rr][Cc][Hh] ]] || continue
wsl.exe -d "$d" -u root -- echo ok >/dev/null 2>&1 && { DISTRO_NAME="$d"; return 0; }
done
return 1
}
if ! pick_arch_distro; then
warn "Distros WSL installées :"
wsl.exe -l -v 2>/dev/null | tr -d '\0' >&2 || true
error "Aucune distro WSL Arch joignable. Installe ArchWSL (nom 'Arch') ou 'wsl --install -d archlinux', ou exporte ARCH_WSL_DISTRO=<nom>."
fi
info "Distro WSL : $DISTRO_NAME"
SCRIPT_DIR_WIN="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -W)"
SCRIPT_PATH_WSL=$(MSYS_NO_PATHCONV=1 wsl.exe -d "$DISTRO_NAME" -u root -- \
wslpath "$(echo "$SCRIPT_DIR_WIN" | sed 's|/|\\\\|g')/setup-aur.sh" \
2>/dev/null | tr -d '\r\n')
[ -n "$SCRIPT_PATH_WSL" ] \
|| error "Traduction du chemin vers WSL échouée (wslpath). Vérifie ARCH_WSL_DISTRO ($DISTRO_NAME)."
wsl.exe -d "$DISTRO_NAME" -u root -- test -f "$SCRIPT_PATH_WSL" \
|| error "Script introuvable dans WSL : $SCRIPT_PATH_WSL"
# Relance en root depuis le vrai chemin ($0 → SCRIPT_DIR correct).
# Fins de ligne garanties LF par .gitattributes (*.sh text eol=lf).
MSYS_NO_PATHCONV=1 wsl.exe -d "$DISTRO_NAME" -u root -- bash "$SCRIPT_PATH_WSL"
exit 0
fi
# ============================================================
# Bascule conteneur : hôte non-Arch (Fedora, Ubuntu, …) →
# setup dans un conteneur Arch via podman (rootful, --privileged).
# Voir build.sh pour le détail du design ; même image, même volume de
# cache pacman, dépôt monté au MÊME chemin absolu (→ local-repo/ revient
# sur l'hôte). makepkg refuse root mais on est dans le conteneur en root :
# setup-aur.sh recrée son propre utilisateur fwsbuild, c'est transparent.
# ============================================================
host_is_arch() {
# Fedora empaquette aussi « pacman » → sa seule présence ne suffit pas.
command -v pacman >/dev/null 2>&1 \
&& grep -qiE '^ID(_LIKE)?=.*arch' /etc/os-release 2>/dev/null
}
if [ -z "$FWS_IN_CONTAINER" ] && ! host_is_arch; then
info "Hôte non-Arch détecté — setup dans un conteneur Arch (podman)..."
command -v podman >/dev/null 2>&1 \
|| error "podman introuvable. Fedora : 'sudo dnf install -y podman' ; Debian/Ubuntu : 'sudo apt install -y podman'."
SUDO=(); [ "$EUID" -eq 0 ] || SUDO=(sudo)
TTY=(); [ -t 0 ] && TTY=(-it)
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
IMAGE="docker.io/library/archlinux:latest"
# pull explicite : « run » ne re-résout pas « latest » une fois en cache.
info "Pull de l'image $IMAGE"
"${SUDO[@]}" podman pull "$IMAGE"
info "Relance dans le conteneur (setup-aur.sh)…"
# --network=host : le bridge podman ne route plus vers l'extérieur sur
# certains réseaux (firewalld/NAT, → « Resolving timed out »). On partage la
# pile réseau de l'hôte (internet + DNS OK) pour les pacman/makepkg/AUR.
"${SUDO[@]}" podman run --rm "${TTY[@]}" --network=host --privileged \
-e FWS_IN_CONTAINER=1 \
-v "$REPO_DIR":"$REPO_DIR" \
-v fws-pacman-cache:/var/cache/pacman/pkg \
-w "$REPO_DIR" \
"$IMAGE" \
bash "$REPO_DIR/setup-aur.sh"
# podman rootful → local-repo/ appartient à root : on le rend à l'hôte.
OWNER="$(stat -c '%u:%g' "$REPO_DIR" 2>/dev/null || true)"
if [ -n "$OWNER" ] && [ -e "$REPO_DIR/local-repo" ]; then
"${SUDO[@]}" chown -R "$OWNER" "$REPO_DIR/local-repo" 2>/dev/null || true
fi
exit 0
fi
# ============================================================
# Vérifications
# ============================================================
command -v pacman >/dev/null || error "pacman introuvable (lance depuis Arch / WSL)"
# Élévation root : sudo de préférence, sinon su. $0 cité (chemins à espaces).
if [ "$EUID" -ne 0 ]; then
if command -v sudo >/dev/null 2>&1; then
exec sudo bash "$0" "$@"
else
exec su -c "bash \"$0\"" root
fi
fi
success "Arch Linux (root) ✓"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOCAL_REPO="$SCRIPT_DIR/local-repo"
BUILD_DIR="/tmp/fws-aur-build"
BUILD_USER="fwsbuild"
# ============================================================
step "0/4 — Préparation pacman (sandbox WSL + keyring)"
# ============================================================
# pacman ≥ 7 utilise landlock pour sandboxer les ops fs. Ni le kernel WSL
# ni (selon le noyau) le conteneur ne le supportent → désactivation explicite.
if grep -qi 'microsoft\|wsl' /proc/version 2>/dev/null || [ -n "$FWS_IN_CONTAINER" ]; then
if ! grep -qE '^[[:space:]]*DisableSandbox' /etc/pacman.conf; then
sed -i '/^\[options\]/a DisableSandbox' /etc/pacman.conf
warn "WSL/conteneur détecté → DisableSandbox ajouté à /etc/pacman.conf"
fi
fi
# Keyring : sur une WSL Arch ancienne, archlinux-keyring est périmé et
# bloque tout install ("unknown trust"). On bypass SigLevel uniquement
# pour mettre à jour le paquet keyring, puis on rétablit.
info "Refresh du trousseau pacman…"
pacman-key --init 2>/dev/null || true
if [ -f /etc/pacman.conf ] && ! grep -qE '^[[:space:]]*SigLevel[[:space:]]*=[[:space:]]*Never' /etc/pacman.conf; then
cp -f /etc/pacman.conf /etc/pacman.conf.fws.bak
sed -i 's/^SigLevel.*/SigLevel = Never/' /etc/pacman.conf
pacman -Sy --noconfirm --needed archlinux-keyring \
|| warn "Maj archlinux-keyring échouée (sigs bypass) — on continue"
mv -f /etc/pacman.conf.fws.bak /etc/pacman.conf
fi
pacman-key --populate archlinux 2>/dev/null || true
# Maj système complète : indispensable pour gérer les "package splits"
# (ex. gcc-libs → libgcc + libstdc++) sinon makepkg plantera sur
# "conflicting files" lors de l'install des dépendances.
info "Mise à jour complète du système (peut être long la première fois)…"
pacman -Syu --noconfirm \
|| warn "pacman -Syu a partiellement échoué — on continue"
# ============================================================
step "1/4 — Outils de build"
# ============================================================
pacman -Sy --needed --noconfirm base-devel git
# ============================================================
step "2/4 — Préparation utilisateur de build (non-root pour makepkg)"
# ============================================================
rm -rf "$BUILD_DIR"
mkdir -p "$BUILD_DIR"
if ! id "$BUILD_USER" &>/dev/null; then
useradd -m "$BUILD_USER"
echo "$BUILD_USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/fwsbuild
chmod 440 /etc/sudoers.d/fwsbuild
success "Utilisateur $BUILD_USER créé"
fi
chown -R "$BUILD_USER:$BUILD_USER" "$BUILD_DIR"
# ============================================================
# Helpers — build INCRÉMENTAL (saute un paquet déjà présent dans local-repo
# à la même version pkgver-pkgrel). Gros gain quand on n'itère que sur 1 paquet.
# ============================================================
mkdir -p "$LOCAL_REPO"
# Version « [epoch:]pkgver-pkgrel » lue dans un PKGBUILD (sourcing en sous-shell).
# Vide si illisible → on (re)construit par sécurité. Nos paquets n'ont pas de
# pkgver() VCS, donc le pkgver littéral est exact.
pkgbuild_fullver() {
( cd "$1" 2>/dev/null && source ./PKGBUILD >/dev/null 2>&1 \
&& printf '%s%s-%s' "${epoch:+$epoch:}" "$pkgver" "$pkgrel" ) 2>/dev/null || true
}
# Le paquet <name> en version <fullver> est-il déjà dans local-repo ? Le motif
# « -$ver- » borne la version (évite qu'« anaconda » matche « anaconda-widgets »).
repo_has() {
[ -n "$2" ] || return 1
local f
for f in "$LOCAL_REPO/$1-$2-"*.pkg.tar.*; do [ -e "$f" ] && return 0; done
return 1
}
# Publie les .pkg d'un build vers local-repo en purgeant d'abord les anciennes
# versions de CE paquet (+ son sous-paquet -debug). Le « -[0-9] » empêche
# « anaconda » d'attraper « anaconda-widgets » / « anaconda-debug ».
# Prend la LISTE EXPLICITE des fichiers à publier (pas un glob sur le dossier :
# un .pkg d'un build précédent peut traîner dans $BUILD_DIR/<name> et serait
# republié par-dessus la purge).
publish_to_repo() {
local name="$1"; shift
rm -f "$LOCAL_REPO/$name"-[0-9]*.pkg.tar.* \
"$LOCAL_REPO/$name"-debug-[0-9]*.pkg.tar.* 2>/dev/null || true
cp -f "$@" "$LOCAL_REPO/" || error "Copie de $name vers local-repo échouée"
}
# Construit OU saute <name> (source déjà déposée dans $BUILD_DIR/<name>).
# Installe TOUJOURS le résultat (depuis local-repo si sauté) pour que les
# paquets dépendants suivants résolvent leurs deps (chaînes AUR→AUR, anaconda…).
build_or_skip() {
# NB : référencer "$1" et PAS "$name" ici — dans un `local a=… b=…` à une
# seule ligne, bash développe la 2ᵉ valeur AVANT que `name` ne soit affecté,
# donc "$name" y serait vide → d="/tmp/fws-aur-build/" (PKGBUILD introuvable).
local name="$1" d="$BUILD_DIR/$1" ver
[ -f "$d/PKGBUILD" ] || error "PKGBUILD introuvable pour $name ($d)"
ver="$(pkgbuild_fullver "$d")"
if repo_has "$name" "$ver"; then
success "$name $ver déjà construit → saut (install depuis local-repo)"
pacman -U --noconfirm --needed "$LOCAL_REPO/$name-$ver-"*.pkg.tar.* \
|| error "Install (repo) de $name échouée"
return 0
fi
info "Build $name ${ver:+($ver) }(peut prendre plusieurs minutes)…"
chown -R "$BUILD_USER:$BUILD_USER" "$d"
su - "$BUILD_USER" -c "cd '$d' && makepkg -sf --noconfirm" \
|| error "Build $name échoué"
# N'installer/publier QUE les paquets produits par CE PKGBUILD dans SA
# version courante (makepkg --packagelist), jamais un glob "$d/"* : après
# un bump de pkgrel, l'ancien .pkg traîne encore dans $d (BUILD_DIR n'est
# pas nettoyé entre les runs) → pacman -U recevait 2× le même nom de
# paquet (« erreur : cible répétée ») et la vieille version repartait
# dans local-repo. Le grep filtre tout bruit éventuel de su - (PAM…).
# NB : --packagelist liste aussi un -debug qui n'est PAS toujours produit
# (paquet pur python : rien à stripper) → ne garder que les fichiers
# réellement présents sur disque.
local -a pkgfiles=() existing=()
local f
mapfile -t pkgfiles < <(su - "$BUILD_USER" -c "cd '$d' && makepkg --packagelist" \
| grep -E '\.pkg\.tar\.')
for f in "${pkgfiles[@]}"; do [ -e "$f" ] && existing+=("$f"); done
[ "${#existing[@]}" -gt 0 ] || error "Aucun paquet produit trouvé pour $name"
pacman -U --noconfirm "${existing[@]}" || error "Install de $name échouée"
publish_to_repo "$name" "${existing[@]}"
success "$name build + install OK"
}
# ============================================================
step "3/4 — Build des paquets (saut si déjà à jour dans local-repo)"
# ============================================================
# --- Paquets AUR (ordre : deps avant dépendants ; clone shallow puis build/saut) ---
for pkg in "${AUR_PACKAGES[@]}"; do
info "Clonage $pkg (AUR)…"
rm -rf "$BUILD_DIR/$pkg"
su - "$BUILD_USER" -c "git clone --depth=1 https://aur.archlinux.org/${pkg}.git $BUILD_DIR/$pkg" \
|| error "Clonage $pkg échoué"
build_or_skip "$pkg"
done
# --- PKGBUILD locaux FWS (ordre explicite, feuilles d'abord, anaconda dernier) ---
LOCAL_PKGBUILDS_DIR="$SCRIPT_DIR/pkgbuilds"
LOCAL_BUILD_ORDER=(
fws-dnd
pykickstart python-productmd python-requests-file python-simpleline
python-crypt_r python-iso639 python-langtable python-meh python-blivet
anaconda-widgets anaconda
)
BUILT_LOCAL=()
prepare_and_build_local() {
local name="$1" dir="$LOCAL_PKGBUILDS_DIR/$1"
[ -f "$dir/PKGBUILD" ] || return 1
rm -rf "$BUILD_DIR/$name"
cp -a "$dir" "$BUILD_DIR/$name"
build_or_skip "$name"
}
if [ -d "$LOCAL_PKGBUILDS_DIR" ]; then
# 1) Ordre explicite (deps avant dépendants).
for name in "${LOCAL_BUILD_ORDER[@]}"; do
if prepare_and_build_local "$name"; then BUILT_LOCAL+=("$name"); fi
done
# 2) Repli : tout PKGBUILD présent mais non listé (futur ajout oublié).
for dir in "$LOCAL_PKGBUILDS_DIR"/*/; do
[ -f "$dir/PKGBUILD" ] || continue
name="$(basename "$dir")"
printf '%s\n' "${BUILT_LOCAL[@]}" | grep -qx "$name" && continue
prepare_and_build_local "$name" || true
done
fi
# ============================================================
step "4/4 — (Re)génération de la base du repo local fws-local"
# ============================================================
# local-repo contient déjà TOUS les paquets (construits ce run + sautés des
# runs précédents). On régénère juste la base de données pacman du dépôt.
rm -f "$LOCAL_REPO"/fws-local.db* "$LOCAL_REPO"/fws-local.files* 2>/dev/null || true
repo-add "$LOCAL_REPO/fws-local.db.tar.gz" "$LOCAL_REPO"/*.pkg.tar.* \
|| error "repo-add a échoué"
success "Repo local prêt : $LOCAL_REPO"
# ============================================================
# Nettoyage utilisateur de build
# ============================================================
userdel -r "$BUILD_USER" 2>/dev/null || true
rm -f /etc/sudoers.d/fwsbuild
echo ""
echo -e "${GREEN}╔══════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ Setup terminé. Lance maintenant : ./build.sh ║${NC}"
echo -e "${GREEN}╚══════════════════════════════════════════════════╝${NC}"