0de970239f
Replace automatic version reading from VERSION file with interactive prompts for version (major.minor.build) and ISO variant name (e.g., cli, gnome, kde).
Changes:
- Remove automatic VERSION file reading; now serves as default with prompt
- Add interactive prompts for version and variant name with validation
- Simplify ISO naming from FWS-v{major}-{minor}-{build}-{date}-x86_64.iso to fws-{version}-{variant}.iso
- Update hostname from 'archiso' to 'fws'
- Add custom FWS logo for fastfetch with color configuration
- Improve error messages and user feedback
This enables flexible build variants and streamlines the build process.
348 lines
16 KiB
Bash
Executable File
348 lines
16 KiB
Bash
Executable File
#!/bin/bash
|
|
# ============================================================
|
|
# FWS — Build OFFICIEL versionné de l'ISO (archiso)
|
|
#
|
|
# Identique à build.sh dans sa structure, mais :
|
|
# - lit la version dans le fichier VERSION (format Major.Minor.Build)
|
|
# - nomme l'ISO FWS-vMAJOR-MINOR-BUILD-DATE-x86_64.iso
|
|
# - range l'ISO dans out/vMAJOR/vMAJOR.MINOR/
|
|
#
|
|
# Fonctionne sur :
|
|
# - Windows 10 / 11 (Git Bash → bascule auto dans WSL Arch)
|
|
# - Arch Linux natif (exécution directe)
|
|
# - WSL Arch lancé directement (exécution directe)
|
|
#
|
|
# Nom de la distro WSL : "Arch" par défaut, ou $ARCH_WSL_DISTRO,
|
|
# ou auto-détecté parmi les noms courants.
|
|
# ============================================================
|
|
|
|
set -e
|
|
trap 'rc=$?; echo -e "\e[31mÉchec (build-offi.sh) ligne $LINENO, code $rc.\e[0m" >&2; exit $rc' ERR
|
|
|
|
DISTRO_NAME="${ARCH_WSL_DISTRO:-Arch}"
|
|
|
|
# ============================================================
|
|
# Bascule Git Bash (Windows 10/11) → WSL si besoin
|
|
# ============================================================
|
|
if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || -n "$WINDIR" ]]; then
|
|
echo -e "\e[36mGit Bash détecté — bascule dans WSL ($DISTRO_NAME)...\e[0m"
|
|
export MSYS_NO_PATHCONV=1
|
|
export MSYS2_ARG_CONV_EXCL="*"
|
|
|
|
# WSL doit être présent (sinon message clair plutôt que command not found).
|
|
command -v wsl.exe >/dev/null 2>&1 || {
|
|
echo -e "\e[31mWSL introuvable. Installe WSL2 puis une distro Arch :\e[0m" >&2
|
|
echo " 1) PowerShell admin : wsl --install" >&2
|
|
echo " 2) Installe Arch (ArchWSL, ou 'wsl --install -d archlinux') puis relance." >&2
|
|
exit 1
|
|
}
|
|
|
|
# Choix de la distro Arch : override $ARCH_WSL_DISTRO, sinon nom exact,
|
|
# sinon 1re distro « arch » réellement joignable. On énumère via
|
|
# `wsl -l -q` (sortie UTF-16LE → on retire NUL/CR) au lieu d'une liste
|
|
# figée, mais on garde la sonde « echo ok » (une distro listée peut
|
|
# être en cours d'install / cassée).
|
|
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
|
|
echo -e "\e[31mAucune distribution WSL Arch joignable.\e[0m" >&2
|
|
echo "Distros WSL installées :" >&2
|
|
wsl.exe -l -v 2>/dev/null | tr -d '\0' >&2 || true
|
|
echo "" >&2
|
|
echo "Installe Arch dans WSL puis relance :" >&2
|
|
echo " - ArchWSL (yuk7) — s'enregistre sous 'Arch' : https://github.com/yuk7/ArchWSL/releases/latest" >&2
|
|
echo " - ou image officielle : wsl --install -d archlinux (nom 'archlinux')" >&2
|
|
echo "Distro sous un autre nom ? export ARCH_WSL_DISTRO=<nom> (cf. 'wsl -l -v' ci-dessus)." >&2
|
|
exit 1
|
|
fi
|
|
echo -e "\e[36m==> Distro WSL : $DISTRO_NAME\e[0m"
|
|
|
|
# Traduit le dossier du script en chemin WSL.
|
|
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')/build-offi.sh" \
|
|
2>/dev/null | tr -d '\r\n')
|
|
[ -n "$SCRIPT_PATH_WSL" ] || {
|
|
echo -e "\e[31mTraduction du chemin vers WSL échouée (wslpath). Vérifie ARCH_WSL_DISTRO ($DISTRO_NAME).\e[0m" >&2
|
|
exit 1
|
|
}
|
|
wsl.exe -d "$DISTRO_NAME" -u root -- test -f "$SCRIPT_PATH_WSL" || {
|
|
echo -e "\e[31mScript introuvable dans WSL : $SCRIPT_PATH_WSL\e[0m" >&2
|
|
exit 1
|
|
}
|
|
|
|
# Relance ce même script dans WSL, en root, depuis son vrai chemin
|
|
# (BASH_SOURCE → WORK_DIR correct). Les fins de ligne sont garanties LF
|
|
# par .gitattributes (*.sh text eol=lf) ; le profil copié est en plus
|
|
# passé à dos2unix plus loin.
|
|
echo "==> Script à exécuter dans WSL : $SCRIPT_PATH_WSL"
|
|
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, …) →
|
|
# build dans un conteneur Arch via podman.
|
|
#
|
|
# mkarchiso exige pacman + des mounts/chroot/loop privilégiés que
|
|
# seul un environnement Arch fournit. Sur un hôte non-Arch on relance
|
|
# CE script à l'identique dans docker.io/library/archlinux:latest, le
|
|
# dépôt monté au MÊME chemin absolu (→ WORK_DIR et out/ inchangés).
|
|
# podman ROOTFUL + --privileged obligatoire : rootless ne gère pas les
|
|
# mounts/chroot de mkarchiso (et --privileged relâche aussi SELinux,
|
|
# enforcing sur Fedora, sur le bind-mount sans avoir besoin de :Z).
|
|
# ============================================================
|
|
host_is_arch() {
|
|
# Fedora empaquette aussi « pacman » → sa seule présence ne suffit pas ;
|
|
# on exige en plus un ID/ID_LIKE « arch » dans /etc/os-release.
|
|
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
|
|
echo -e "\e[36mHôte non-Arch détecté — build officiel dans un conteneur Arch (podman)...\e[0m"
|
|
|
|
command -v podman >/dev/null 2>&1 || {
|
|
echo -e "\e[31mpodman introuvable.\e[0m" >&2
|
|
echo " Fedora : sudo dnf install -y podman" >&2
|
|
echo " Debian/Ubuntu : sudo apt install -y podman" >&2
|
|
exit 1
|
|
}
|
|
|
|
# Rootful : préfixe sudo si on n'est pas déjà root.
|
|
SUDO=(); [ "$EUID" -eq 0 ] || SUDO=(sudo)
|
|
# -it seulement si on est dans un terminal (sinon podman casse en CI).
|
|
TTY=(); [ -t 0 ] && TTY=(-it)
|
|
|
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
SELF="$(basename "${BASH_SOURCE[0]}")"
|
|
IMAGE="docker.io/library/archlinux:latest"
|
|
|
|
# pull explicite : « run » ne re-résout jamais le tag « latest » une fois
|
|
# l'image en cache → sans ça on build indéfiniment sur une image qui
|
|
# vieillit (puis partial upgrades pacman). Le -Syu côté conteneur (plus
|
|
# bas) complète la parade.
|
|
echo "==> Pull de l'image $IMAGE..."
|
|
"${SUDO[@]}" podman pull "$IMAGE"
|
|
|
|
echo "==> Relance dans le conteneur ($SELF)..."
|
|
# --network=host : le réseau bridge de podman ne route plus vers l'extérieur
|
|
# sur ce wifi (firewalld/NAT cassé après changement de réseau → « core.db :
|
|
# Resolving timed out », même avec --dns). En partageant la pile réseau de
|
|
# l'hôte (qui, lui, a internet + DNS via 127.0.0.53/systemd-resolved joignable
|
|
# dans son propre netns), le conteneur récupère une connectivité identique.
|
|
"${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/$SELF"
|
|
|
|
# podman rootful → les fichiers produits (out/) appartiennent à root.
|
|
# On les rend au propriétaire du dépôt pour confort côté hôte.
|
|
OWNER="$(stat -c '%u:%g' "$REPO_DIR" 2>/dev/null || true)"
|
|
if [ -n "$OWNER" ]; then
|
|
for d in out local-repo; do
|
|
[ -e "$REPO_DIR/$d" ] && "${SUDO[@]}" chown -R "$OWNER" "$REPO_DIR/$d" 2>/dev/null || true
|
|
done
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
# ============================================================
|
|
# Exécution native (Arch Linux bare-metal, WSL, OU conteneur Arch)
|
|
# ============================================================
|
|
command -v pacman >/dev/null \
|
|
|| { echo -e "\e[31mpacman introuvable — lance ce script depuis Arch / WSL.\e[0m"; exit 1; }
|
|
|
|
# mkarchiso exige root. Sur Arch natif on s'élève (sudo de préférence,
|
|
# sinon su) ; depuis la bascule Git Bash on est déjà root (-u root).
|
|
# $0 est cité pour gérer les chemins à espaces (ex. "1. FWS").
|
|
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
|
|
|
|
if grep -qi 'microsoft\|wsl' /proc/version 2>/dev/null; then
|
|
echo -e "\e[36mBuild officiel dans WSL ($DISTRO_NAME) en tant que root...\e[0m"
|
|
IS_WSL=1
|
|
else
|
|
echo -e "\e[36mBuild officiel sur Arch Linux natif en tant que root...\e[0m"
|
|
IS_WSL=0
|
|
fi
|
|
|
|
# Le dossier de travail = dossier qui contient ce script (gère les
|
|
# espaces du chemin, ex. "1. FWS").
|
|
WORK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
echo "==> Dossier de travail : $WORK_DIR"
|
|
|
|
# ============================================================
|
|
# Version (major.minor.build) + nom de la variante.
|
|
# La version est DEMANDÉE ; le fichier VERSION sert de DÉFAUT (taper Entrée =
|
|
# reprendre sa valeur). Produit fws-<major.minor.build>-<nom>.iso
|
|
# (ex. fws-1.5.0-cli.iso). Nécessite un terminal (read).
|
|
# ============================================================
|
|
# Défaut éventuel lu dans le fichier VERSION (doit être major.minor.build).
|
|
VERSION_FILE="$WORK_DIR/VERSION"
|
|
VERSION_DEFAULT=""
|
|
if [ -f "$VERSION_FILE" ]; then
|
|
VERSION_DEFAULT="$(tr -d ' \t\r\n' < "$VERSION_FILE")"
|
|
[[ "$VERSION_DEFAULT" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || VERSION_DEFAULT=""
|
|
fi
|
|
|
|
while :; do
|
|
if [ -n "$VERSION_DEFAULT" ]; then
|
|
read -rp "==> Version (major.minor.build) [Entrée = $VERSION_DEFAULT] : " VERSION \
|
|
|| { echo -e "\e[31mEntrée requise — lance le script en interactif.\e[0m" >&2; exit 1; }
|
|
[ -n "$VERSION" ] || VERSION="$VERSION_DEFAULT" # vide → on reprend le fichier VERSION
|
|
else
|
|
read -rp "==> Version (major.minor.build, ex. 1.5.0) : " VERSION \
|
|
|| { echo -e "\e[31mEntrée requise — lance le script en interactif.\e[0m" >&2; exit 1; }
|
|
fi
|
|
[[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && break
|
|
echo -e "\e[31m Format attendu : major.minor.build (ex. 1.5.0)\e[0m" >&2
|
|
done
|
|
while :; do
|
|
read -rp "==> Nom de la variante (ex. cli, gnome, kde) : " ISO_TAG \
|
|
|| { echo -e "\e[31mEntrée requise — lance le script en interactif.\e[0m" >&2; exit 1; }
|
|
# normalise : minuscules, lettres / chiffres / tirets uniquement
|
|
ISO_TAG="$(printf '%s' "$ISO_TAG" | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9-')"
|
|
[ -n "$ISO_TAG" ] && break
|
|
echo -e "\e[31m Nom requis (lettres, chiffres, tirets)\e[0m" >&2
|
|
done
|
|
|
|
IFS='.' read -r MAJOR MINOR BUILD <<< "$VERSION"
|
|
# iso_version interne (passé à mkarchiso) ; l'ISO finale est renommée plus bas.
|
|
ISO_VERSION="${VERSION}-${ISO_TAG}"
|
|
OUT_DIR="$WORK_DIR/out/v${MAJOR}/v${MAJOR}.${MINOR}"
|
|
ISO_FILE="$OUT_DIR/fws-${VERSION}-${ISO_TAG}.iso"
|
|
|
|
echo "==> Version : ${VERSION} · variante : ${ISO_TAG}"
|
|
echo "==> ISO finale : fws-${VERSION}-${ISO_TAG}.iso"
|
|
echo "==> Dossier : $OUT_DIR"
|
|
|
|
# pacman ≥ 7 sandboxe les ops FS via landlock, non supporté par le kernel
|
|
# WSL ni (selon le noyau) par le conteneur → désactivation. Idempotent,
|
|
# sans effet sur Arch natif.
|
|
if { [ "$IS_WSL" -eq 1 ] || [ -n "$FWS_IN_CONTAINER" ]; } \
|
|
&& ! grep -qE '^[[:space:]]*DisableSandbox' /etc/pacman.conf; then
|
|
sed -i '/^\[options\]/a DisableSandbox' /etc/pacman.conf
|
|
echo "==> WSL/conteneur détecté → DisableSandbox ajouté à /etc/pacman.conf"
|
|
fi
|
|
|
|
echo "==> Mise à jour des miroirs et installation de archiso..."
|
|
pacman -Sy --noconfirm reflector || true
|
|
reflector --verbose --latest 10 --sort rate --save /etc/pacman.d/mirrorlist || true
|
|
if [ -n "$FWS_IN_CONTAINER" ]; then
|
|
# Image de base qui vieillit → upgrade complet AVANT d'ajouter archiso,
|
|
# sinon partial upgrade (archiso tire des deps plus récentes que la base).
|
|
pacman -Syu --noconfirm archiso
|
|
else
|
|
pacman -Sy --noconfirm archiso
|
|
fi
|
|
|
|
echo "==> Préparation de l'environnement de build..."
|
|
rm -rf /tmp/fws-build
|
|
mkdir -p /tmp/fws-build/releng
|
|
|
|
# Copie configs/releng/ en base
|
|
if [ -d "$WORK_DIR/configs/releng" ]; then
|
|
cp -ar "$WORK_DIR/configs/releng/"* /tmp/fws-build/releng/
|
|
echo "==> configs/releng/ copié"
|
|
fi
|
|
|
|
# Fusionne configs/baseline/ par dessus (priorité aux fichiers baseline)
|
|
if [ -d "$WORK_DIR/configs/baseline" ]; then
|
|
cp -ar "$WORK_DIR/configs/baseline/"* /tmp/fws-build/releng/
|
|
echo "==> configs/baseline/ fusionné (prioritaire)"
|
|
fi
|
|
|
|
# ── Injection de la version dans profiledef.sh (copie temporaire) ──
|
|
# mkarchiso nomme l'ISO ${iso_name}-${iso_version}-${arch}.iso.
|
|
# On force iso_version pour obtenir vMAJOR-MINOR-BUILD-DATE.
|
|
if [ -f /tmp/fws-build/releng/profiledef.sh ]; then
|
|
sed -i "s|^iso_version=.*|iso_version=\"${ISO_VERSION}\"|" \
|
|
/tmp/fws-build/releng/profiledef.sh
|
|
echo "==> iso_version forcé à '${ISO_VERSION}' dans profiledef.sh"
|
|
else
|
|
echo -e "\e[31mprofiledef.sh introuvable dans le profil de build.\e[0m"
|
|
exit 1
|
|
fi
|
|
|
|
echo "==> Activation de NetworkManager.service sur le live (symlink réel)..."
|
|
mkdir -p /tmp/fws-build/releng/airootfs/etc/systemd/system/multi-user.target.wants
|
|
ln -sf /usr/lib/systemd/system/NetworkManager.service \
|
|
/tmp/fws-build/releng/airootfs/etc/systemd/system/multi-user.target.wants/NetworkManager.service
|
|
|
|
echo "==> Vérification des services systemd..."
|
|
ls /tmp/fws-build/releng/airootfs/etc/systemd/system/ 2>/dev/null || echo " (aucun service)"
|
|
ls /tmp/fws-build/releng/airootfs/etc/systemd/system/multi-user.target.wants/ 2>/dev/null || echo " (aucun symlink)"
|
|
|
|
# Copie le repo local (winboat-bin + deps Anaconda packagées)
|
|
if ls "$WORK_DIR/local-repo/"*.pkg.tar.zst &>/dev/null 2>&1; then
|
|
echo "==> Copie du repo local fws-local..."
|
|
mkdir -p /tmp/fws-build/local-repo
|
|
cp -a "$WORK_DIR/local-repo/"* /tmp/fws-build/local-repo/
|
|
|
|
echo "==> Injection [fws-local] dans pacman.conf..."
|
|
sed -i '/^\[fws-local\]/,/^$/d' /tmp/fws-build/releng/pacman.conf
|
|
PACMAN_TMP=$(mktemp)
|
|
printf '[fws-local]\nSigLevel = Optional TrustAll\nServer = file:///tmp/fws-build/local-repo\n\n' \
|
|
> "$PACMAN_TMP"
|
|
cat /tmp/fws-build/releng/pacman.conf >> "$PACMAN_TMP"
|
|
mv "$PACMAN_TMP" /tmp/fws-build/releng/pacman.conf
|
|
|
|
echo "==> Vérification pacman.conf :"
|
|
head -5 /tmp/fws-build/releng/pacman.conf
|
|
else
|
|
echo "==> Aucun repo local détecté."
|
|
fi
|
|
|
|
echo "==> Correction des retours à la ligne Windows (dos2unix)..."
|
|
pacman -S --needed --noconfirm dos2unix
|
|
find /tmp/fws-build/releng -type f -exec dos2unix {} + 2>/dev/null
|
|
|
|
echo "==> Lancement de mkarchiso..."
|
|
mkdir -p "$OUT_DIR"
|
|
# mkarchiso supprime l'ISO cible avant de la réécrire : si elle est VERROUILLÉE
|
|
# par Windows (VM ouverte dessus, ISO montée), ce rm casse tout le build à la
|
|
# fin. Parade : staging neuf puis déplacement ; si la cible (cette même
|
|
# version) est verrouillée, on bascule sur un nom horodaté. On ne touche
|
|
# jamais aux ISO des autres versions.
|
|
STAGE="$OUT_DIR/.staging-$$"
|
|
rm -rf "$STAGE"; mkdir -p "$STAGE"
|
|
mkarchiso -v -w /tmp/fws-build/work -o "$STAGE" /tmp/fws-build/releng
|
|
|
|
NEW_ISO="$(ls -1 "$STAGE/"*.iso 2>/dev/null | head -1)"
|
|
[ -n "$NEW_ISO" ] || { echo -e "\e[31mAucune ISO produite par mkarchiso.\e[0m" >&2; exit 1; }
|
|
if { chmod -f 666 "$ISO_FILE" 2>/dev/null; rm -f "$ISO_FILE" 2>/dev/null; } && mv -f "$NEW_ISO" "$ISO_FILE" 2>/dev/null; then
|
|
FINAL="$ISO_FILE"
|
|
else
|
|
FINAL="${ISO_FILE%.iso}-$(date +%H%M%S).iso"
|
|
echo -e "\e[33m[!] '$ISO_FILE' est verrouillée (une VM l'utilise ?). Écriture sous un nom unique.\e[0m" >&2
|
|
mv -f "$NEW_ISO" "$FINAL"
|
|
fi
|
|
rm -rf "$STAGE" 2>/dev/null || true
|
|
|
|
echo "==> Nettoyage..."
|
|
rm -rf /tmp/fws-build/work
|
|
|
|
echo "==> Build officiel terminé ! ISO : $FINAL"
|
|
echo -e "\e[32mScript de build officiel (fws-${VERSION}-${ISO_TAG}) terminé avec succès.\e[0m"
|