diff --git a/.gitignore b/.gitignore index 3036c47..d52599c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,15 @@ out/ local-repo/ configs/baseline/airootfs/etc/systemd/system/multi-user.target.wants/ configs/releng/airootfs/etc/systemd/system/multi-user.target.wants/ -configs/baseline/airootfs/usr/lib/ +# Ignore le contenu généré de usr/lib (libs Calamares) MAIS conserve le module +# de choix de bureau FWS — sinon il est absent des clones et la sélection +# multi-desktop est cassée pour quiconque clone le dépôt. +configs/baseline/airootfs/usr/lib/* +!configs/baseline/airootfs/usr/lib/calamares/ +configs/baseline/airootfs/usr/lib/calamares/* +!configs/baseline/airootfs/usr/lib/calamares/modules/ +configs/baseline/airootfs/usr/lib/calamares/modules/* +!configs/baseline/airootfs/usr/lib/calamares/modules/fws-desktop-choice/ configs/baseline/airootfs/usr/bin/ configs/baseline/airootfs/usr/include/ configs/baseline/airootfs/usr/share/calamares/branding/default/ diff --git a/README.md b/README.md index 492b5b6..48a790b 100644 --- a/README.md +++ b/README.md @@ -212,7 +212,8 @@ L'ISO finale est générée dans `./out/FWS-YYYY.MM.DD-x86_64.iso`. | Symptôme | Cause / fix | |---|---| -| `setup-calamares.sh` : `wsl.exe -d Arch` introuvable | La distro WSL ne s'appelle pas `Arch`. Exporter `ARCH_WSL_DISTRO=NomDeMaDistro` ou renommer. | +| `Aucune distribution WSL Arch joignable` | Aucune distro Arch n'est installée/joignable. Les scripts auto-détectent désormais toute distro dont le nom contient « arch » (via `wsl -l -q`) ; installe ArchWSL (nom `Arch`) ou `wsl --install -d archlinux`, ou force `ARCH_WSL_DISTRO=NomDeMaDistro`. | +| `WSL introuvable` | WSL n'est pas installé. PowerShell admin : `wsl --install`, puis installe une distro Arch. | | `pacman: signature unknown trust` | Keyring périmé → `pacman -Sy --noconfirm archlinux-keyring` puis relancer. | | `makepkg: conflicting files` | `pacman -Syu` incomplet avant le build. Relancer `setup-calamares.sh`. | | `mkarchiso` plante sur `[fws-local]` | Le repo local n'a pas été généré. Relancer `setup-calamares.sh`. | diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..3eefcb9 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.0.0 diff --git a/build-offi.sh b/build-offi.sh new file mode 100755 index 0000000..afd77fc --- /dev/null +++ b/build-offi.sh @@ -0,0 +1,249 @@ +#!/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= (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 + +# ============================================================ +# Exécution native (Arch Linux bare-metal OU dans WSL) +# ============================================================ +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" + +# ============================================================ +# Lecture et validation de la version (fichier VERSION) +# ============================================================ +VERSION_FILE="$WORK_DIR/VERSION" +[ -f "$VERSION_FILE" ] \ + || { echo -e "\e[31mFichier VERSION introuvable : $VERSION_FILE\e[0m"; exit 1; } + +# Trim espaces / tabulations / CR / LF +VERSION="$(tr -d ' \t\r\n' < "$VERSION_FILE")" + +if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo -e "\e[31mVERSION invalide : '$VERSION' (attendu Major.Minor.Build, ex. 1.2.3)\e[0m" + exit 1 +fi + +IFS='.' read -r MAJOR MINOR BUILD <<< "$VERSION" +BUILD_DATE="$(date +%Y.%m.%d)" +ISO_VERSION="v${MAJOR}-${MINOR}-${BUILD}-${BUILD_DATE}" +OUT_DIR="$WORK_DIR/out/v${MAJOR}/v${MAJOR}.${MINOR}" +ISO_FILE="$OUT_DIR/FWS-${ISO_VERSION}-x86_64.iso" + +echo "==> Version officielle : ${MAJOR}.${MINOR}.${BUILD}" +echo "==> Dossier de sortie : $OUT_DIR" +echo "==> ISO finale : FWS-${ISO_VERSION}-x86_64.iso" + +# pacman ≥ 7 sandboxe les ops FS via landlock, non supporté par le +# kernel WSL → désactivation. Idempotent, sans effet sur Arch natif. +if [ "$IS_WSL" -eq 1 ] && ! grep -qE '^[[:space:]]*DisableSandbox' /etc/pacman.conf; then + sed -i '/^\[options\]/a DisableSandbox' /etc/pacman.conf + echo "==> WSL 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 +pacman -Sy --noconfirm archiso + +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 (calamares + winboat-bin) +if ls "$WORK_DIR/local-repo/"*.pkg.tar.zst &>/dev/null 2>&1; then + echo "==> Copie du repo local Calamares..." + 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 (v${MAJOR}.${MINOR}.${BUILD}) terminé avec succès.\e[0m" diff --git a/build.sh b/build.sh old mode 100644 new mode 100755 index 3da7f37..4027e39 --- a/build.sh +++ b/build.sh @@ -1,31 +1,128 @@ #!/bin/bash - -export MSYS_NO_PATHCONV=1 +# ============================================================ +# FWS — Build de l'ISO via mkarchiso (archiso) +# +# 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 'echo -e "\e[31mErreur lors de l execution (build.sh).\e[0m"; exit 1' ERR +trap 'rc=$?; echo -e "\e[31mÉchec (build.sh) ligne $LINENO, code $rc.\e[0m" >&2; exit $rc' ERR -DISTRO_NAME="Arch" +DISTRO_NAME="${ARCH_WSL_DISTRO:-Arch}" -if [ -n "$WSL_DISTRO_NAME" ]; then - echo -e "\e[36mBuild exécuté depuis WSL ($WSL_DISTRO_NAME) en tant que root...\e[0m" - IN_WSL=1 -else - echo -e "\e[36mLancement du processus de build dans WSL ($DISTRO_NAME) en tant que root...\e[0m" +# ============================================================ +# 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= (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.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 -if [ -z "$IN_WSL" ]; then - # ── Depuis Git Bash ────────────────────────────────────── - SCRIPT_DIR_WIN="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -W)" - WORK_DIR_WSL=$(MSYS_NO_PATHCONV=1 wsl.exe -d "$DISTRO_NAME" -u root -- \ - wslpath "$(echo "$SCRIPT_DIR_WIN" | sed 's|/|\\\\|g')" 2>/dev/null | tr -d '\r\n') +# ============================================================ +# Exécution native (Arch Linux bare-metal OU dans WSL) +# ============================================================ +command -v pacman >/dev/null \ + || { echo -e "\e[31mpacman introuvable — lance ce script depuis Arch / WSL.\e[0m"; exit 1; } - echo "==> Dossier de travail WSL : $WORK_DIR_WSL" +# 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 - MSYS_NO_PATHCONV=1 wsl.exe -d "$DISTRO_NAME" -u root -- bash << EOF -set -e -WORK_DIR="${WORK_DIR_WSL}" -echo "==> Dossier de travail : \$WORK_DIR" +if grep -qi 'microsoft\|wsl' /proc/version 2>/dev/null; then + echo -e "\e[36mBuild exécuté dans WSL ($DISTRO_NAME) en tant que root...\e[0m" + IS_WSL=1 +else + echo -e "\e[36mBuild exécuté 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" + +# pacman ≥ 7 sandboxe les ops FS via landlock, non supporté par le +# kernel WSL → désactivation. Idempotent, sans effet sur Arch natif. +if [ "$IS_WSL" -eq 1 ] && ! grep -qE '^[[:space:]]*DisableSandbox' /etc/pacman.conf; then + sed -i '/^\[options\]/a DisableSandbox' /etc/pacman.conf + echo "==> WSL détecté → DisableSandbox ajouté à /etc/pacman.conf" +fi echo "==> Mise à jour des miroirs et installation de archiso..." pacman -Sy --noconfirm reflector || true @@ -37,18 +134,18 @@ 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/ +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/ +if [ -d "$WORK_DIR/configs/baseline" ]; then + cp -ar "$WORK_DIR/configs/baseline/"* /tmp/fws-build/releng/ echo "==> configs/baseline/ fusionné (prioritaire)" fi -echo "==> Activation de NetworkManager.service sur le live (symlink réel WSL)..." +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 @@ -58,18 +155,18 @@ ls /tmp/fws-build/releng/airootfs/etc/systemd/system/ 2>/dev/null || echo " (au ls /tmp/fws-build/releng/airootfs/etc/systemd/system/multi-user.target.wants/ 2>/dev/null || echo " (aucun symlink)" # Copie le repo local (calamares + winboat-bin) -if ls "\$WORK_DIR/local-repo/"*.pkg.tar.zst &>/dev/null 2>&1; then +if ls "$WORK_DIR/local-repo/"*.pkg.tar.zst &>/dev/null 2>&1; then echo "==> Copie du repo local Calamares..." mkdir -p /tmp/fws-build/local-repo - cp -a "\$WORK_DIR/local-repo/"* /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) + 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 + > "$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 @@ -82,83 +179,31 @@ pacman -S --needed --noconfirm dos2unix find /tmp/fws-build/releng -type f -exec dos2unix {} + 2>/dev/null echo "==> Lancement de mkarchiso..." -mkdir -p "\$WORK_DIR/out" -chmod -f 777 "\$WORK_DIR/out/"FWS-*.iso 2>/dev/null || true -rm -f "\$WORK_DIR/out/"FWS-*.iso 2>/dev/null || true -mkarchiso -v -w /tmp/fws-build/work -o "\$WORK_DIR/out" /tmp/fws-build/releng +mkdir -p "$WORK_DIR/out" +# mkarchiso fait un « rm » interne de l'ISO cible avant de la (ré)écrire ; si +# une ISO du même nom est VERROUILLÉE par Windows (VM encore ouverte dessus, +# ISO montée, antivirus), ce rm échoue et tout le build casse à la toute fin. +# Parade : mkarchiso écrit dans un dossier de staging neuf, puis on déplace +# l'ISO. Si la cible est verrouillée, on bascule sur un nom horodaté → le +# build réussit quand même au lieu de tout perdre. +STAGE="$WORK_DIR/out/.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; } +DEST="$WORK_DIR/out/$(basename "$NEW_ISO")" +if { chmod -f 666 "$DEST" 2>/dev/null; rm -f "$DEST" 2>/dev/null; } && mv -f "$NEW_ISO" "$DEST" 2>/dev/null; then + FINAL="$DEST" +else + FINAL="$WORK_DIR/out/$(basename "${NEW_ISO%.iso}")-$(date +%H%M%S).iso" + echo -e "\e[33m[!] '$DEST' 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 terminé ! ISO dans \$WORK_DIR/out" -EOF - -else - # ── Déjà dans WSL ──────────────────────────────────────── - WORK_DIR="$PWD" - echo "==> Dossier de travail : $WORK_DIR" - - echo "==> Mise à jour et installation de archiso..." - pacman -Sy --noconfirm reflector || true - reflector --verbose --latest 10 --sort rate --save /etc/pacman.d/mirrorlist || true - pacman -Sy --noconfirm archiso - - echo "==> Préparation de l'environnement de build..." - rm -rf /tmp/fws-build - mkdir -p /tmp/fws-build/releng - - if [ -d "$WORK_DIR/configs/releng" ]; then - cp -ar "$WORK_DIR/configs/releng/"* /tmp/fws-build/releng/ - echo "==> configs/releng/ copié" - fi - - if [ -d "$WORK_DIR/configs/baseline" ]; then - cp -ar "$WORK_DIR/configs/baseline/"* /tmp/fws-build/releng/ - echo "==> configs/baseline/ fusionné (prioritaire)" - 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)" - - if ls "$WORK_DIR/local-repo/"*.pkg.tar.zst &>/dev/null 2>&1; then - echo "==> Copie du repo local Calamares..." - 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 "$WORK_DIR/out" - chmod -f 777 "$WORK_DIR/out/"FWS-*.iso 2>/dev/null || true - rm -f "$WORK_DIR/out/"FWS-*.iso 2>/dev/null || true - mkarchiso -v -w /tmp/fws-build/work -o "$WORK_DIR/out" /tmp/fws-build/releng - - echo "==> Nettoyage..." - rm -rf /tmp/fws-build/work - - echo "==> Build terminé ! L'ISO se trouve dans '$WORK_DIR/out'." -fi - -echo -e "\e[32mScript de build terminé avec succès.\e[0m" \ No newline at end of file +echo "==> Build terminé ! ISO : $FINAL" +echo -e "\e[32mScript de build terminé avec succès.\e[0m" diff --git a/configs/baseline/airootfs/etc/calamares/branding/fws/desktop.qml b/configs/baseline/airootfs/etc/calamares/branding/fws/desktop.qml deleted file mode 100644 index e1e59d9..0000000 --- a/configs/baseline/airootfs/etc/calamares/branding/fws/desktop.qml +++ /dev/null @@ -1,44 +0,0 @@ -import QtQuick 2.12 -import QtQuick.Controls 2.12 -import calamares 1.0 - -Page { - id: page - title: qsTr("Choix de l'environnement") - - Column { - anchors.fill: parent - anchors.margins: 20 - spacing: 12 - - Text { - text: qsTr("Choisissez l'environnement de bureau à installer :") - font.pixelSize: 20 - color: "#00d4ff" - } - - RadioButton { id: rb_xfce; text: "Xfce"; checked: true; onCheckedChanged: if (checked) saveChoice() } - RadioButton { id: rb_kde; text: "KDE"; onCheckedChanged: if (checked) saveChoice() } - RadioButton { id: rb_gnome; text: "GNOME"; onCheckedChanged: if (checked) saveChoice() } - RadioButton { id: rb_hypr; text: "Hyprland"; onCheckedChanged: if (checked) saveChoice() } - - Button { - text: qsTr("Enregistrer le choix") - onClicked: saveChoice() - } - - function saveChoice() { - var choice = rb_xfce.checked ? "xfce" : (rb_kde.checked ? "kde" : (rb_gnome.checked ? "gnome" : "hyprland")) - try { - calamares.globalStorage.insert("FWS_DESKTOP", choice) - } catch (e) { - // ignore if unavailable - } - try { - calamares.utils.runCommand("/bin/sh", ["-c", "printf '%s' \"" + choice + "\" > /run/fws-desktop"], true) - } catch (e) { - // best effort - } - } - } -} diff --git a/configs/baseline/airootfs/etc/calamares/modules/shellprocess.conf b/configs/baseline/airootfs/etc/calamares/modules/shellprocess.conf index d0b0eeb..9931c31 100644 --- a/configs/baseline/airootfs/etc/calamares/modules/shellprocess.conf +++ b/configs/baseline/airootfs/etc/calamares/modules/shellprocess.conf @@ -5,10 +5,39 @@ dontChroot: true +# Timeout par défaut (secondes) appliqué à chaque commande. +# La valeur par défaut de Calamares est 30 s — beaucoup trop courte +# pour l'installation d'un bureau complet (pacman télécharge des +# centaines de Mo). On relève le défaut et on accorde un délai +# spécifique très large à la commande d'init du bureau. +timeout: 300 + script: # Copie le kernel depuis l'ISO vers /boot du système cible - 'cp "$(find /run/archiso/bootmnt -name vmlinuz-linux 2>/dev/null | head -1)" "${ROOT}/boot/vmlinuz-linux"' - - 'chroot "${ROOT}" /bin/bash "/usr/local/bin/fws-desktop-init-$(cat /run/fws-desktop 2>/dev/null || printf xfce)"' + # Installation du bureau choisi : peut être long (réseau + gros DE + # comme KDE/GNOME) → 1 h de marge pour ne jamais expirer à tort. + # + # arch-chroot (et non « chroot » brut) : monte /proc /sys /dev /run et + # copie resolv.conf dans la cible. Indispensable, sinon les hooks + # post-transaction de pacman (systemd daemon-reload, udev, tmpfiles…) + # échouent faute de ces points de montage → pacman sort en code 1 + # alors même que les téléchargements ont réussi. + # Le nom du bureau est validé contre une allow-list (mêmes valeurs que + # les scripts fws-desktop-init-* présents) : toute valeur vide / inconnue + # / avec espace parasite retombe sur xfce → jamais d'abandon d'install sur + # un script d'init manquant. + - command: 'd="$(cat /run/fws-desktop 2>/dev/null)"; d="${d%%[[:space:]]*}"; case "$d" in xfce|kde|gnome|hyprland) ;; *) d=xfce ;; esac; arch-chroot "${ROOT}" /bin/bash "/usr/local/bin/fws-desktop-init-$d"' + timeout: 3600 + + # ── Nettoyage des artefacts « live-only » qui ne doivent PAS persister + # sur le système installé (le squashfs du live devient le root cible) ── + # 1) Autologin root SANS mot de passe sur tty1 (drop-in getty du live) : + # trou de sécurité + conflit avec le display manager sur vt1. + - 'rm -rf "${ROOT}/etc/systemd/system/getty@tty1.service.d"' + # 2) Provisionnement auto archiso (param noyau script=) : ne doit jamais + # tourner sur la machine installée. + - 'rm -f "${ROOT}/root/.zlogin" "${ROOT}/root/.automated_script.sh"' # Supprime le drop-in archiso (surcharge HOOKS avec des hooks inexistants post-install) - 'rm -f "${ROOT}/etc/mkinitcpio.conf.d/archiso.conf"' diff --git a/configs/baseline/airootfs/etc/calamares/settings.conf b/configs/baseline/airootfs/etc/calamares/settings.conf index 736723c..c40189b 100644 --- a/configs/baseline/airootfs/etc/calamares/settings.conf +++ b/configs/baseline/airootfs/etc/calamares/settings.conf @@ -6,13 +6,16 @@ modules-search: [ local, /usr/lib/calamares/modules ] sequence: + # NB : pas de module `packagechooser` ici — il n'est pas compilé dans le + # paquet calamares (AUR). Le choix du bureau se fait dans le live via + # /usr/local/bin/fws-pick-desktop (écrit /run/fws-desktop), validé ensuite + # par le job `fws-desktop-choice` ci-dessous. - show: - welcome - locale - keyboard - partition - users - - packagechooser - summary - exec: - partition diff --git a/configs/baseline/airootfs/root/.xinitrc b/configs/baseline/airootfs/root/.xinitrc index 53ca1df..c8f1257 100644 --- a/configs/baseline/airootfs/root/.xinitrc +++ b/configs/baseline/airootfs/root/.xinitrc @@ -7,4 +7,9 @@ fi xsetroot -solid "#1a1a2e" openbox & sleep 1 + +# Choix du bureau AVANT Calamares (le module packagechooser n'est pas compilé +# dans le paquet calamares AUR). Écrit /run/fws-desktop, lu pendant l'install. +/usr/local/bin/fws-pick-desktop || true + exec calamares diff --git a/configs/baseline/airootfs/root/.zlogin b/configs/baseline/airootfs/root/.zlogin new file mode 100644 index 0000000..e9f6fce --- /dev/null +++ b/configs/baseline/airootfs/root/.zlogin @@ -0,0 +1,11 @@ +# fix for screen readers +if grep -Fqa 'accessibility=' /proc/cmdline &> /dev/null; then + setopt SINGLE_LINE_ZLE +fi + +# Provisionnement automatique archiso (param noyau script=) : LIVE uniquement. +# Sur le système installé /run/archiso n'existe pas ; de plus shellprocess.conf +# retire ce fichier de la cible. Ceci est une seconde barrière de sécurité. +if [[ -d /run/archiso ]]; then + ~/.automated_script.sh +fi diff --git a/configs/baseline/airootfs/usr/lib/calamares/modules/fws-desktop-choice/main.py b/configs/baseline/airootfs/usr/lib/calamares/modules/fws-desktop-choice/main.py new file mode 100755 index 0000000..b914655 --- /dev/null +++ b/configs/baseline/airootfs/usr/lib/calamares/modules/fws-desktop-choice/main.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +import libcalamares + +# Chaque valeur doit avoir un /usr/local/bin/fws-desktop-init- +# correspondant (invariant 1:1). Toute valeur hors-set retombe sur FALLBACK. +VALID = {"xfce", "kde", "gnome", "hyprland"} +FALLBACK = "xfce" + + +def pretty_name(): + return "Sélection de l'environnement de bureau" + + +STATE = "/run/fws-desktop" + + +def run(): + # Le choix est fait dans le live par /usr/local/bin/fws-pick-desktop, qui + # écrit STATE (le module packagechooser n'est pas compilé dans le paquet + # calamares AUR, donc pas de sélection côté Calamares). Ici on valide et on + # normalise pour garantir une valeur sûre à shellprocess (repli xfce). + choice = FALLBACK + try: + with open(STATE) as fh: + raw = fh.read().strip() + if raw in VALID: + choice = raw + except OSError: + pass + + try: + with open(STATE, "w") as fh: + fh.write(choice) + except OSError as e: + libcalamares.utils.warning(f"fws-desktop-choice: impossible d'écrire {STATE}: {e}") + + libcalamares.utils.debug(f"fws-desktop-choice: bureau = {choice}") + return None diff --git a/configs/baseline/airootfs/usr/lib/calamares/modules/fws-desktop-choice/module.desc b/configs/baseline/airootfs/usr/lib/calamares/modules/fws-desktop-choice/module.desc new file mode 100644 index 0000000..b01a8f9 --- /dev/null +++ b/configs/baseline/airootfs/usr/lib/calamares/modules/fws-desktop-choice/module.desc @@ -0,0 +1,5 @@ +--- +type: "job" +name: "fws-desktop-choice" +interface: "python" +script: "main.py" diff --git a/configs/baseline/profiledef.sh b/configs/baseline/profiledef.sh index 68c1c64..40290a8 100644 --- a/configs/baseline/profiledef.sh +++ b/configs/baseline/profiledef.sh @@ -14,6 +14,23 @@ pacman_conf="pacman.conf" airootfs_image_type="squashfs" airootfs_image_tool_options=('-comp' 'xz' '-Xbcj' 'x86' '-b' '1M' '-Xdict-size' '1M') bootstrap_tarball_compression=(xz -9e) +# NB : ce profiledef.sh ÉCRASE celui de configs/releng/ lors de la fusion du +# build (baseline prioritaire). Il doit donc être un SUR-ENSEMBLE des +# permissions de releng, sinon les helpers live perdent leur bit exécutable +# (ils sont versionnés en 0644) et /root/.gnupg perd son 0700 (gpg refuse). file_permissions=( ["/etc/shadow"]="0:0:400" + ["/root"]="0:0:750" + ["/root/.automated_script.sh"]="0:0:755" + ["/root/.gnupg"]="0:0:700" + ["/usr/local/bin/choose-mirror"]="0:0:755" + ["/usr/local/bin/Installation_guide"]="0:0:755" + ["/usr/local/bin/livecd-sound"]="0:0:755" + ["/usr/local/bin/fws-pick-desktop"]="0:0:755" + ["/usr/bin/fws-installer"]="0:0:755" + ["/usr/local/bin/fws-desktop-init-common"]="0:0:755" + ["/usr/local/bin/fws-desktop-init-xfce"]="0:0:755" + ["/usr/local/bin/fws-desktop-init-kde"]="0:0:755" + ["/usr/local/bin/fws-desktop-init-gnome"]="0:0:755" + ["/usr/local/bin/fws-desktop-init-hyprland"]="0:0:755" ) diff --git a/configs/releng/airootfs/usr/bin/fws-installer b/configs/releng/airootfs/usr/bin/fws-installer old mode 100644 new mode 100755 diff --git a/configs/releng/airootfs/usr/local/bin/Installation_guide b/configs/releng/airootfs/usr/local/bin/Installation_guide old mode 100644 new mode 100755 diff --git a/configs/releng/airootfs/usr/local/bin/choose-mirror b/configs/releng/airootfs/usr/local/bin/choose-mirror old mode 100644 new mode 100755 diff --git a/configs/releng/airootfs/usr/local/bin/fws-desktop-init-common b/configs/releng/airootfs/usr/local/bin/fws-desktop-init-common old mode 100644 new mode 100755 index c52910b..f87956d --- a/configs/releng/airootfs/usr/local/bin/fws-desktop-init-common +++ b/configs/releng/airootfs/usr/local/bin/fws-desktop-init-common @@ -5,8 +5,50 @@ fws_first_user() { awk -F: '$3 >= 1000 && $1 != "nobody" { print $1; exit }' /etc/passwd } +FWS_LOG=/var/log/fws-desktop-init.log + +# Paquets communs à TOUS les bureaux graphiques. La cible de base n'installe +# rien de tout ça (packages.conf ne fait que des « remove »), donc chaque +# bureau doit les tirer explicitement : audio (PipeWire), applet réseau NM, +# accès volumes (gvfs), dossiers utilisateur, trousseau, polices (dont emoji). +# (Xfce a déjà sa propre liste complète et n'utilise pas ce tableau.) +FWS_BASE_PACKAGES=( + pipewire pipewire-alsa pipewire-pulse wireplumber pavucontrol + networkmanager network-manager-applet + gvfs gvfs-mtp gvfs-gphoto2 gvfs-smb + xdg-user-dirs xdg-user-dirs-gtk xdg-utils + gnome-keyring libsecret polkit + noto-fonts noto-fonts-emoji ttf-dejavu ttf-liberation +) + fws_install_packages() { - pacman -Sy --noconfirm --needed "$@" + # NE PAS faire « pacman -Sy » : rafraîchir les bases sans + # upgrader le système (partial upgrade) provoque des « conflicting + # files » / dépendances cassées → pacman sort en code 1. + # + # 1) Rafraîchit d'abord archlinux-keyring (seule exception admise au + # partial upgrade) : son hook relance pacman-key --populate et évite + # les erreurs de signature dans le chroot. + pacman -Sy --noconfirm --needed archlinux-keyring 2>&1 | tee -a "$FWS_LOG" || true + + # 2) -Syu COMPLET. On désactive CheckSpace à la volée via une conf + # temporaire (process substitution) : le calcul d'espace est non + # fiable pendant une install en chroot et peut faire échouer pacman. + # La conf du système installé (/etc/pacman.conf) reste intacte. + # --noconfirm sélectionne le provider par défaut (ex. + # qt6-multimedia-ffmpeg) sans bloquer sur une saisie. + if ! pacman --config <(sed 's/^[[:space:]]*CheckSpace/#CheckSpace/' /etc/pacman.conf) \ + -Syu --noconfirm --needed "$@" 2>&1 | tee -a "$FWS_LOG"; then + # Surface l'erreur réelle (sinon noyée/tronquée dans la boîte + # Calamares). Tout est aussi conservé dans $FWS_LOG sur la cible. + echo "" >&2 + echo "######## ÉCHEC pacman — log complet : $FWS_LOG (système installé) ########" >&2 + echo "######## Lignes d'erreur détectées : ########" >&2 + grep -iE "error|conflicting|exists in filesystem|no space|impossible|introuvable|failed" \ + "$FWS_LOG" | tail -n 25 >&2 + echo "#########################################################################" >&2 + return 1 + fi } fws_enable_services() { @@ -22,13 +64,11 @@ fws_disable_services() { done } -fws_write_dmrc() { - local user_name="$1" - local session_name="$2" - - if [ -n "$user_name" ] && [ -d "/home/$user_name" ]; then - printf '[Desktop]\nSession=%s\n' "$session_name" > "/home/$user_name/.dmrc" - fi +fws_set_graphical_default() { + # Système installé : démarrer en mode graphique (lance le display manager). + # Idempotent ; le défaut systemd est déjà graphical.target mais on le rend + # explicite pour ne dépendre d'aucun héritage du squashfs archiso. + systemctl set-default graphical.target >/dev/null 2>&1 || true } fws_write_lightdm_config() { diff --git a/configs/releng/airootfs/usr/local/bin/fws-desktop-init-gnome b/configs/releng/airootfs/usr/local/bin/fws-desktop-init-gnome old mode 100644 new mode 100755 index 4d3ed8b..15e9925 --- a/configs/releng/airootfs/usr/local/bin/fws-desktop-init-gnome +++ b/configs/releng/airootfs/usr/local/bin/fws-desktop-init-gnome @@ -5,8 +5,8 @@ set -euo pipefail first_user="$(fws_first_user)" -fws_install_packages gnome sddm +fws_install_packages "${FWS_BASE_PACKAGES[@]}" gnome sddm fws_disable_services lightdm.service gdm.service fws_enable_services sddm.service -fws_write_sddm_config "$first_user" gnome -fws_write_dmrc "$first_user" gnome \ No newline at end of file +fws_set_graphical_default +fws_write_sddm_config "$first_user" gnome \ No newline at end of file diff --git a/configs/releng/airootfs/usr/local/bin/fws-desktop-init-hyprland b/configs/releng/airootfs/usr/local/bin/fws-desktop-init-hyprland old mode 100644 new mode 100755 index 8370387..f6f0b5c --- a/configs/releng/airootfs/usr/local/bin/fws-desktop-init-hyprland +++ b/configs/releng/airootfs/usr/local/bin/fws-desktop-init-hyprland @@ -5,8 +5,46 @@ set -euo pipefail first_user="$(fws_first_user)" -fws_install_packages hyprland xdg-desktop-portal-hyprland xdg-desktop-portal-gtk waybar wofi kitty swaybg swayidle swaylock xorg-xwayland wl-clipboard grim slurp qt5-wayland qt6-wayland sddm +# Config Hyprland minimale + autostart (agent polkit, barre, applet réseau, +# notifications). Sans config ni agent polkit, la session est inutilisable +# pour un non-technicien (pas de raccourcis, pas d'élévation de privilèges GUI). +fws_write_hyprland_config() { + local user_name="$1" + [ -n "$user_name" ] && [ -d "/home/$user_name" ] || return 0 + local cfg_dir="/home/$user_name/.config/hypr" + install -d -m 755 "$cfg_dir" + if [ -f /usr/share/hypr/hyprland.conf ]; then + cp -f /usr/share/hypr/hyprland.conf "$cfg_dir/hyprland.conf" + else + cat > "$cfg_dir/hyprland.conf" <<'EOF' +$terminal = kitty +$menu = wofi --show drun +bind = SUPER, Q, exec, $terminal +bind = SUPER, R, exec, $menu +bind = SUPER, C, killactive +bind = SUPER, M, exit +EOF + fi + cat >> "$cfg_dir/hyprland.conf" <<'EOF' + +# ── FWS : démarrage automatique de la session ── +exec-once = systemctl --user start hyprpolkitagent +exec-once = waybar +exec-once = nm-applet --indicator +exec-once = mako +EOF + chown -R "$user_name:$user_name" "/home/$user_name/.config" +} + +# PipeWire/applet NM/polices viennent de FWS_BASE_PACKAGES ; hyprpolkitagent +# fournit l'agent d'authentification polkit pour Wayland/Hyprland. +fws_install_packages "${FWS_BASE_PACKAGES[@]}" \ + hyprland xdg-desktop-portal-hyprland xdg-desktop-portal-gtk \ + waybar wofi kitty mako swaybg swayidle swaylock \ + xorg-xwayland wl-clipboard grim slurp \ + qt5-wayland qt6-wayland hyprpolkitagent sddm fws_disable_services lightdm.service gdm.service fws_enable_services sddm.service +fws_set_graphical_default fws_write_sddm_config "$first_user" hyprland -fws_write_dmrc "$first_user" hyprland \ No newline at end of file +fws_write_hyprland_config "$first_user" \ No newline at end of file diff --git a/configs/releng/airootfs/usr/local/bin/fws-desktop-init-kde b/configs/releng/airootfs/usr/local/bin/fws-desktop-init-kde old mode 100644 new mode 100755 index 1a0d32e..ee89fd1 --- a/configs/releng/airootfs/usr/local/bin/fws-desktop-init-kde +++ b/configs/releng/airootfs/usr/local/bin/fws-desktop-init-kde @@ -5,8 +5,8 @@ set -euo pipefail first_user="$(fws_first_user)" -fws_install_packages plasma-meta konsole dolphin sddm +fws_install_packages "${FWS_BASE_PACKAGES[@]}" plasma-meta konsole dolphin sddm fws_disable_services lightdm.service gdm.service fws_enable_services sddm.service -fws_write_sddm_config "$first_user" plasma -fws_write_dmrc "$first_user" plasma \ No newline at end of file +fws_set_graphical_default +fws_write_sddm_config "$first_user" plasma \ No newline at end of file diff --git a/configs/releng/airootfs/usr/local/bin/fws-desktop-init-xfce b/configs/releng/airootfs/usr/local/bin/fws-desktop-init-xfce old mode 100644 new mode 100755 index 4886b15..8da2930 --- a/configs/releng/airootfs/usr/local/bin/fws-desktop-init-xfce +++ b/configs/releng/airootfs/usr/local/bin/fws-desktop-init-xfce @@ -22,5 +22,5 @@ fws_install_packages \ upower fws_disable_services sddm.service gdm.service fws_enable_services lightdm.service -fws_write_lightdm_config "$first_user" xfce -fws_write_dmrc "$first_user" xfce \ No newline at end of file +fws_set_graphical_default +fws_write_lightdm_config "$first_user" xfce \ No newline at end of file diff --git a/configs/releng/airootfs/usr/local/bin/fws-pick-desktop b/configs/releng/airootfs/usr/local/bin/fws-pick-desktop new file mode 100755 index 0000000..dfdde95 --- /dev/null +++ b/configs/releng/airootfs/usr/local/bin/fws-pick-desktop @@ -0,0 +1,41 @@ +#!/bin/bash +# ============================================================ +# FWS — Sélecteur d'environnement de bureau (LIVE uniquement) +# +# Le paquet calamares (AUR) ne compile PAS le module packagechooser : +# on choisit donc le bureau ICI, dans le live, AVANT de lancer Calamares. +# Le choix est écrit dans /run/fws-desktop, lu ensuite par : +# - le module Calamares fws-desktop-choice (validation), +# - shellprocess.conf → /usr/local/bin/fws-desktop-init-. +# ============================================================ +set -u + +STATE=/run/fws-desktop +DEFAULT=xfce +VALID_RE='^(xfce|kde|gnome|hyprland)$' + +choice="" + +# Dialogue graphique si zenity + X sont disponibles ; sinon repli silencieux. +if command -v zenity >/dev/null 2>&1 && [ -n "${DISPLAY:-}" ]; then + choice="$(zenity --list --radiolist \ + --title="FWS — Environnement de bureau" \ + --text="Choisissez le bureau à installer :" \ + --width=560 --height=360 \ + --column="Choix" --column="id" --column="Bureau" \ + --hide-column=2 --print-column=2 \ + TRUE xfce "Xfce — léger, stable et rapide (recommandé)" \ + FALSE kde "KDE Plasma — moderne et très personnalisable" \ + FALSE gnome "GNOME — épuré et intuitif" \ + FALSE hyprland "Hyprland — compositeur Wayland dynamique" \ + 2>/dev/null)" +fi + +# Normalisation : toute valeur vide / annulée / invalide → bureau par défaut. +choice="$(printf '%s' "$choice" | tr -d '[:space:]')" +if ! printf '%s' "$choice" | grep -Eq "$VALID_RE"; then + choice="$DEFAULT" +fi + +printf '%s' "$choice" > "$STATE" +exit 0 diff --git a/configs/releng/airootfs/usr/local/bin/livecd-sound b/configs/releng/airootfs/usr/local/bin/livecd-sound old mode 100644 new mode 100755 diff --git a/scripts/run_archiso.sh b/scripts/run_archiso.sh old mode 100644 new mode 100755 diff --git a/setup-calamares.sh b/setup-calamares.sh old mode 100644 new mode 100755 index 1429195..10409f2 --- a/setup-calamares.sh +++ b/setup-calamares.sh @@ -7,6 +7,7 @@ # rafraîchir le repo local. # ============================================================ set -e +trap 'rc=$?; echo -e "\033[0;31m[ERR] Échec (setup-calamares.sh) ligne $LINENO, code $rc.\033[0m" >&2; exit $rc' ERR AUR_PACKAGES=(calamares winboat-bin) DISTRO_NAME="${ARCH_WSL_DISTRO:-Arch}" @@ -29,19 +30,45 @@ if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || -n "$WINDIR" ]]; then export MSYS_NO_PATHCONV=1 export MSYS2_ARG_CONV_EXCL="*" - if ! wsl.exe -d "$DISTRO_NAME" -u root -- echo ok >/dev/null 2>&1; then - # Auto-détection - for name in "Arch" "ArchLinux" "archlinux" "arch" "ArchWSL"; do - if wsl.exe -d "$name" -u root -- echo ok >/dev/null 2>&1; then - DISTRO_NAME="$name"; break - fi + # 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=." 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-calamares.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 @@ -50,7 +77,14 @@ fi # Vérifications # ============================================================ command -v pacman >/dev/null || error "pacman introuvable (lance depuis Arch / WSL)" -[ "$EUID" -eq 0 ] || exec su -c "bash $0" root +# É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)"