4 Commits

Author SHA1 Message Date
nocode 0de970239f feat(build): refactor build script with interactive version and variant selection
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.
2026-06-23 11:02:41 +02:00
nocode 7d6bba42b2 feat(anaconda): add hostname field to user spoke and fix keyboard layout by territory
Replace keyboard correction logic in kickstart with anaconda package patches:

- Add "Nom de machine" (hostname) field to the User spoke in anaconda GUI
- user.py writes the hostname value to /tmp/fws-hostname for the kickstart %post
- Simplify kickstart to read from /tmp/fws-hostname instead of live hostname
- Fix keyboard layout selection to use full locale (e.g. fr_CH) instead of just language (fr)
  to correctly derive territory-specific keymaps (ch(fr) for Switzerland, not fr for France)
- Remove outdated fix_keyboard() function from kickstart

Also add --network=host flag to podman run in setup-aur.sh to ensure DNS and internet
connectivity through the host stack instead of the bridge (fixes timeout issues on
certain networks with firewalld/NAT).

Bump anaconda pkgrel from 2 to 4.
2026-06-23 10:48:32 +02:00
nocode 1184ba17d9 fix(releng): correct hostname and keyboard mapping in anaconda post-installation
Fix two bugs in the anaconda post-installation script:

1. Hostname handling: Anaconda writes an empty /etc/hostname to the target system. Now we preserve the hostname set during installation from the live environment, falling back to 'fws' if using default values.

2. Keyboard mapping: Anaconda derives keyboard layout from language only, ignoring territory. For locales with territory variants (e.g., fr_CH for Switzerland), we now apply territory-specific keyboard maps to both console (vconsole.conf) and X11 (xorg.conf.d) using langtable for proper mapping.
2026-06-23 08:40:42 +02:00
nocode d25ab9b4da fix(build): add --network=host to podman run commands for dns connectivity
Add --network=host flag to podman run commands in both build.sh and build-offi.sh to fix DNS resolution issues.

The podman bridge network was unable to route to external hosts on certain wifi networks due to firewalld/NAT misconfiguration after network changes, resulting in "core.db: Resolving timed out" errors. By sharing the host's network stack, the container inherits the same network connectivity including DNS resolution via 127.0.0.53/systemd-resolved that is available on the host.
2026-06-23 08:06:53 +02:00
12 changed files with 192 additions and 266 deletions
+1 -1
View File
@@ -1 +1 @@
0.5.3
0.5.4
+45 -20
View File
@@ -138,7 +138,12 @@ if [ -z "$FWS_IN_CONTAINER" ] && ! host_is_arch; then
"${SUDO[@]}" podman pull "$IMAGE"
echo "==> Relance dans le conteneur ($SELF)..."
"${SUDO[@]}" podman run --rm "${TTY[@]}" --privileged \
# --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 \
@@ -188,29 +193,49 @@ WORK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo "==> Dossier de travail : $WORK_DIR"
# ============================================================
# Lecture et validation de la version (fichier VERSION)
# 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"
[ -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
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
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"
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
echo "==> Version officielle : ${MAJOR}.${MINOR}.${BUILD}"
echo "==> Dossier de sortie : $OUT_DIR"
echo "==> ISO finale : FWS-${ISO_VERSION}-x86_64.iso"
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,
@@ -319,4 +344,4 @@ 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"
echo -e "\e[32mScript de build officiel (fws-${VERSION}-${ISO_TAG}) terminé avec succès.\e[0m"
+6 -1
View File
@@ -133,7 +133,12 @@ if [ -z "$FWS_IN_CONTAINER" ] && ! host_is_arch; then
"${SUDO[@]}" podman pull "$IMAGE"
echo "==> Relance dans le conteneur ($SELF)..."
"${SUDO[@]}" podman run --rm "${TTY[@]}" --privileged \
# --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 \
-23
View File
@@ -20,26 +20,6 @@ _OB_PID=$!
# boucle (symptôme « fond bleu qui clignote/reboote »). On NE rend jamais la main
# à startx : on reste sur Openbox pour lire les logs / rebooter proprement.
if command -v liveinst >/dev/null 2>&1; then
# Chantier D : RÉCAPITULATIF matériel AVANT de lancer l'installateur.
# fws-hw-detect est la MÊME source de vérité que le %post du kickstart
# (mode --env) → ce que cet écran annonce = ce que l'install appliquera
# (drivers GPU, guest tools de l'hyperviseur, effacement des disques…).
# « Éteindre » est le seul moyen propre d'annuler : on ne rend jamais la
# main à startx (cf. plus bas), et liveinst n'a pas encore touché au disque.
# Tout est best-effort : sans script ou sans zenity, on installe comme avant.
if command -v fws-hw-detect >/dev/null 2>&1; then
fws-hw-detect --text >/tmp/fws-hw-summary.txt 2>/dev/null || true
if command -v zenity >/dev/null 2>&1 && [ -s /tmp/fws-hw-summary.txt ]; then
if ! zenity --text-info --title="FWS — Récapitulatif avant installation" \
--filename=/tmp/fws-hw-summary.txt \
--ok-label="Lancer l'installateur" --cancel-label="Éteindre" \
--width=800 --height=700 2>/dev/null; then
systemctl poweroff
exit 0
fi
fi
fi
LIVEINST_LOG=/tmp/fws-liveinst.log
liveinst >"$LIVEINST_LOG" 2>&1
rc=$?
@@ -86,9 +66,6 @@ if command -v liveinst >/dev/null 2>&1; then
echo
echo "########## %post --nochroot (/tmp/fws-post-nochroot.log) ##########"
cat /tmp/fws-post-nochroot.log 2>/dev/null || echo "(absent)"
echo
echo "########## Récapitulatif matériel montré avant l'install ##########"
cat /tmp/fws-hw-summary.txt 2>/dev/null || echo "(absent)"
for f in /tmp/anaconda.log /tmp/syslog /tmp/program.log \
/tmp/storage.log /tmp/dbus.log /tmp/packaging.log /tmp/X.log; do
echo
@@ -1,173 +0,0 @@
#!/bin/bash
# ============================================================================
# fws-hw-detect — détection matériel FWS (hyperviseur + GPU).
#
# SOURCE UNIQUE de vérité, consommée par DEUX endroits :
# • l'écran « Récapitulatif avant installation » du live (--text, affiché
# par /root/.xinitrc via zenity juste avant de lancer liveinst) ;
# • le %post chrooté du kickstart Anaconda (--env), qui APPLIQUE :
# activation des guest tools du bon hyperviseur, purge des autres,
# installation des drivers GPU.
# → ce que l'écran ANNONCE = ce que l'install FERA (aucune divergence
# possible, la détection vit ici et nulle part ailleurs).
#
# Fonctionne dans le LIVE comme dans le CHROOT d'Anaconda : celui-ci
# bind-monte /sys et /proc du live → même matériel visible. Le script est
# livré par l'airootfs (/usr/local/bin) → recopié dans la cible par le
# payload liveimg → présent dans le chroot du %post. Aucune dépendance
# dure : lspci (pciutils) et ip (iproute2) ne servent qu'aux libellés
# humains de --text, avec repli si absents.
#
# Usage : fws-hw-detect --env lignes FWS_*='…' à eval par le kickstart
# fws-hw-detect --text récapitulatif humain en français (zenity)
# ============================================================================
set -u
MODE="${1:---text}"
# --- Hyperviseur --------------------------------------------------------------
# systemd-detect-virt lit CPUID/DMI → OK en chroot, sans systemd actif.
# ATTENTION : hors VM il AFFICHE « none » ET sort en code ≠ 0 → surtout pas de
# « || echo none » DANS le $() (on récolterait « none » en double).
VIRT="$(systemd-detect-virt 2>/dev/null | head -n1)"
[ -n "$VIRT" ] || VIRT=none
# Les guest tools des 3 hyperviseurs sont DÉJÀ dans l'image live
# (packages.x86_64 : open-vm-tools, virtualbox-guest-utils-nox,
# qemu-guest-agent) → activer un service marche HORS LIGNE ; on retire ceux
# des autres hyperviseurs (inutiles sur cette machine).
VIRT_SVC="" VIRT_RM="" VIRT_LABEL=""
case "$VIRT" in
vmware)
VIRT_LABEL="VMware"
VIRT_SVC="vmtoolsd.service vmware-vmblock-fuse.service"
VIRT_RM="virtualbox-guest-utils-nox qemu-guest-agent" ;;
oracle) # = VirtualBox (nom renvoyé par systemd-detect-virt)
VIRT_LABEL="VirtualBox"
VIRT_SVC="vboxservice.service"
VIRT_RM="open-vm-tools qemu-guest-agent" ;;
kvm|qemu)
VIRT_LABEL="QEMU/KVM"
VIRT_SVC="qemu-guest-agent.service"
VIRT_RM="open-vm-tools virtualbox-guest-utils-nox" ;;
none)
VIRT_LABEL="aucune (machine physique)"
VIRT_RM="open-vm-tools virtualbox-guest-utils-nox qemu-guest-agent" ;;
*) # Hyperviseur non géré (hyper-v…) : aucun de nos guest tools ne sert.
VIRT_LABEL="$VIRT (intégration non gérée)"
VIRT_RM="open-vm-tools virtualbox-guest-utils-nox qemu-guest-agent" ;;
esac
# --- GPU ----------------------------------------------------------------------
# Classe PCI 0x03xxxx = contrôleur d'affichage ; lecture DIRECTE de /sys, pas
# besoin de lspci. Vendors : 0x10de NVIDIA, 0x1002 AMD, 0x8086 Intel,
# 0x15ad VMware (le VMSVGA de VirtualBox porte AUSSI 0x15ad → couvert).
# QEMU virtio-gpu/QXL et VBoxVGA : modesetting + mesa (déjà tirés par
# xorg-server dans l'image) suffisent → rien à installer.
DRV_PKGS="" GPU_TEXT=""
for _dev in /sys/bus/pci/devices/*; do
case "$(cat "$_dev/class" 2>/dev/null)" in 0x03*) ;; *) continue ;; esac
_vendor="$(cat "$_dev/vendor" 2>/dev/null)"
_pkgs=""
case "$_vendor" in
# NVIDIA : le module des dépôts est bâti pour le NOYAU des dépôts →
# « linux » DOIT partir dans la même transaction pacman (le noyau
# installé est celui du live, plus vieux), sinon module ≠ noyau au
# 1er boot. Les chemins /boot/* sont stables → grub.cfg reste bon.
0x10de) _pkgs="linux nvidia nvidia-utils" ;;
0x1002) _pkgs="mesa vulkan-radeon xf86-video-amdgpu" ;;
0x8086) _pkgs="mesa vulkan-intel" ;;
0x15ad) _pkgs="mesa xf86-video-vmware" ;;
esac
# Libellé humain : lspci si dispo, sinon adresse PCI + vendor brut.
_name=""
if command -v lspci >/dev/null 2>&1; then
_name="$(lspci -s "${_dev##*/}" 2>/dev/null | head -n1 \
| cut -d: -f3- | sed 's/^ //')"
fi
[ -n "$_name" ] || _name="GPU PCI ${_dev##*/} (vendor $_vendor)"
if [ -n "$_pkgs" ]; then
GPU_TEXT="${GPU_TEXT} • ${_name}\n → paquets : ${_pkgs}\n"
DRV_PKGS="$DRV_PKGS $_pkgs"
else
GPU_TEXT="${GPU_TEXT} • ${_name}\n → rien à installer (modesetting + mesa, déjà dans l'image)\n"
fi
done
# Dédoublonnage (machine multi-GPU : « mesa » listé 2× ferait échouer pacman
# sur « duplicate target »).
if [ -n "$DRV_PKGS" ]; then
DRV_PKGS="$(printf '%s\n' $DRV_PKGS | sort -u | tr '\n' ' ')"
DRV_PKGS="${DRV_PKGS% }"
fi
# --- Mode machine : sortie shell pour le kickstart ----------------------------
if [ "$MODE" = "--env" ]; then
printf "FWS_VIRT='%s'\n" "$VIRT"
printf "FWS_VIRT_SVC='%s'\n" "$VIRT_SVC"
printf "FWS_VIRT_RM='%s'\n" "$VIRT_RM"
printf "FWS_DRV_PKGS='%s'\n" "$DRV_PKGS"
exit 0
fi
# --- Mode humain : récapitulatif --text (zenity, avant liveinst) ---------------
CPU="$(awk -F': +' '/^model name/{print $2; exit}' /proc/cpuinfo)"
[ -n "$CPU" ] || CPU="inconnu"
case "$(awk -F': +' '/^vendor_id/{print $2; exit}' /proc/cpuinfo)" in
GenuineIntel) UCODE="intel-ucode" ;;
AuthenticAMD) UCODE="amd-ucode" ;;
*) UCODE="" ;;
esac
RAM="$(awk '/^MemTotal/{printf "%.1f Gio", $2/1048576}' /proc/meminfo)"
if [ -d /sys/firmware/efi ]; then
BOOT="UEFI — GRUB x86_64-efi + entrée de secours EFI/BOOT/BOOTX64.EFI"
else
BOOT="BIOS hérité — GRUB i386-pc, table de partitions MBR forcée"
fi
if command -v ip >/dev/null 2>&1 && ip route get 1.1.1.1 >/dev/null 2>&1; then
NET="disponible ✔"
else
NET="INDISPONIBLE ✖ — drivers GPU et bureau ne s'installeront PAS (rattrapable au 1er boot)"
fi
# Type « disk » uniquement (exclut lecteur ISO sr0/loop). La clé USB du live,
# elle, EST un disque → il est juste qu'elle apparaisse sous l'avertissement
# d'effacement (clearpart --all du kickstart efface bien TOUS les disques).
DISKS="$(lsblk -dno NAME,SIZE,MODEL,TYPE 2>/dev/null \
| awk '$NF=="disk"{NF--; print " • " $0}')"
[ -n "$DISKS" ] || DISKS=" (aucun disque détecté)"
[ -n "$GPU_TEXT" ] || GPU_TEXT=" (aucune carte graphique détectée)\n"
printf '%b' \
"══════════════════════════════════════════════════════════
FWS — RÉCAPITULATIF AVANT INSTALLATION
══════════════════════════════════════════════════════════
MACHINE
• Démarrage : ${BOOT}
• Virtualisation : ${VIRT_LABEL}
• Processeur : ${CPU}"
[ -n "$UCODE" ] && printf '%b' "
• Microcode : ${UCODE} — déjà intégré à l'image, rien à faire"
printf '%b' "
• Mémoire : ${RAM}
• Réseau : ${NET}
DISQUES DÉTECTÉS
⚠ Par défaut, TOUS les disques ci-dessous seront ENTIÈREMENT
EFFACÉS (partitionnement automatique). Le partitionnement
manuel reste possible dans l'installateur.
${DISKS}
CARTES GRAPHIQUES → drivers installés AUTOMATIQUEMENT en fin d'install
${GPU_TEXT}
INTÉGRATION HYPERVISEUR (automatique, fonctionne hors ligne)
• Services activés : ${VIRT_SVC:-aucun}
• Guest tools retirés (inutiles) : ${VIRT_RM:-aucun}
DÉROULEMENT DE L'INSTALLATION
1. Réglages dans Anaconda : langue, clavier, fuseau, disque, utilisateur
2. Copie du système live FWS sur le disque (payload liveimg)
3. Noyau + initramfs régénérés (mkinitcpio), GRUB installé
4. Drivers GPU + intégration hyperviseur appliqués (voir ci-dessus)
5. Bureau choisi installé (réseau requis)
« Lancer l'installateur » pour continuer — « Éteindre » pour annuler.
"
-1
View File
@@ -24,7 +24,6 @@ file_permissions=(
["/root/.automated_script.sh"]="0:0:755"
["/root/.gnupg"]="0:0:700"
["/usr/local/bin/choose-mirror"]="0:0:755"
["/usr/local/bin/fws-hw-detect"]="0:0:755"
["/usr/local/bin/Installation_guide"]="0:0:755"
["/usr/local/bin/livecd-sound"]="0:0:755"
)
+1 -1
View File
@@ -1 +1 @@
archiso
fws
@@ -5,5 +5,14 @@
# On utilise donc un autre nom.
_fastfetch_rc=$?
if [ "${_fastfetch_rc}" -eq 0 ]; then
fastfetch
# Logo FWS maison (4 carrés + Tux) au lieu du logo Arch détecté par défaut.
fastfetch \
--logo-type file \
--logo /usr/local/share/fws/logo.txt \
--logo-color-1 '38;2;30;160;100' \
--logo-color-2 '38;2;45;125;210' \
--logo-color-3 '38;2;240;180;40' \
--logo-color-4 '38;2;25;85;145' \
--logo-color-5 '38;2;28;28;34' \
--logo-color-6 '38;2;245;165;35'
fi
@@ -0,0 +1,9 @@
$1████████ $2██$5████$2██
$1████████ $2█$5██$2██$5██$2█
$1████████ $2█$5██████$2█
$1████████ $2██$6█$2██$6█$2██
$3████████ $4████████
$3████████ $4████████
$3████████ $4████████
$3████████ $4████████
@@ -89,6 +89,17 @@ SYSROOT=/mnt/sysroot
# DNS pour que « pacman -S <bureau> » fonctionne dans le chroot.
cp -f /etc/resolv.conf "$SYSROOT/etc/resolv.conf" 2>/dev/null || true
# --- Hostname : valeur saisie dans le champ « Nom de machine » du spoke User --
# Anaconda ne capte PAS le hostname du spoke Réseau (→ /etc/hostname vide). On a
# donc ajouté un champ Hostname au spoke Utilisateur (cf. patch du paquet
# anaconda) : user.py écrit la valeur dans /tmp/fws-hostname (live). On la
# nettoie (caractères de hostname valides) et on l'écrit dans la cible ; défaut
# « fws » si vide/absent → plus jamais de hostname vide ni « archiso ».
HN=""
[ -f /tmp/fws-hostname ] && HN="$(tr -cd 'a-zA-Z0-9._-' < /tmp/fws-hostname)"
[ -n "$HN" ] || HN="fws"
echo "$HN" > "$SYSROOT/etc/hostname"
# Choix du bureau (écrit par l'addon « Choix du bureau », à venir ; valeur lue
# par le %post chrooté ci-dessous). « cli » par défaut si absent.
if [ -f /tmp/fws-desktop ]; then
@@ -194,47 +205,7 @@ else
echo "[FWS] AVERTISSEMENT : grub-install a échoué — bootloader à refaire à la main"
fi
# --- 4) Drivers matériels : détection + activation/installation AUTO ----------
# Toute la DÉTECTION vit dans /usr/local/bin/fws-hw-detect : livré par
# l'airootfs → recopié dans la cible par le payload liveimg → présent dans ce
# chroot. C'est la MÊME source de vérité que l'écran « Récapitulatif avant
# installation » du live (.xinitrc, mode --text) : ce qui a été ANNONCÉ à
# l'utilisateur = ce qu'on APPLIQUE ici. La détection marche en chroot car
# Anaconda bind-monte le /sys et le /proc du LIVE (le code plus haut s'appuie
# déjà dessus : /sys/firmware/efi, findmnt) → on voit le VRAI matériel.
# Variables produites par --env :
# FWS_VIRT hyperviseur (vmware/oracle/kvm/qemu/none…)
# FWS_VIRT_SVC services invité à activer (paquets DÉJÀ dans l'image → OK
# hors ligne ; c'était le chaînon manquant, rien n'activait
# vmtoolsd & co sur le système installé)
# FWS_VIRT_RM guest tools des AUTRES hyperviseurs, à purger
# FWS_DRV_PKGS paquets GPU à installer, dédoublonnés. NVIDIA embarque
# « linux » dans la même transaction : le module des dépôts
# est bâti pour le noyau des dépôts, pas celui du live ; les
# chemins /boot/* étant stables, le grub.cfg de l'étape 3
# reste valable (le hook pacman de nvidia relance mkinitcpio).
# NB : microcode CPU (amd-ucode/intel-ucode) et linux-firmware sont DÉJÀ dans
# l'image → recopiés, et grub-mkconfig (étape 3) a généré les initrd qui vont
# bien. Rien à faire pour eux.
if [ -x /usr/local/bin/fws-hw-detect ]; then
eval "$(/usr/local/bin/fws-hw-detect --env)"
# (a) Hyperviseur : activer le bon service invité, purger les autres.
[ -n "$FWS_VIRT_SVC" ] && { systemctl enable $FWS_VIRT_SVC || true; }
[ -n "$FWS_VIRT_RM" ] && { pacman -Rns --noconfirm $FWS_VIRT_RM || true; }
# (b) GPU : install réseau, NON bloquante (même philosophie que le
# bureau). --needed : ne réinstalle pas ce que l'image a déjà (mesa…).
if [ -n "$FWS_DRV_PKGS" ]; then
pacman-key --init &>/dev/null || true
pacman-key --populate archlinux &>/dev/null || true
if ! pacman -Sy --noconfirm --needed $FWS_DRV_PKGS; then
echo "[FWS] Drivers non installés ($FWS_DRV_PKGS) — réseau ? À refaire au 1er boot."
fi
fi
else
echo "[FWS] fws-hw-detect introuvable — drivers/guest tools NON configurés."
fi
# --- 5) Bureau choisi : pacman -S du DE (non bloquant si pas de réseau) -------
# --- 4) Bureau choisi : pacman -S du DE (non bloquant si pas de réseau) -------
DESK="cli"
[ -f /tmp/fws-desktop ] && DESK="$(tr -d '[:space:]' < /tmp/fws-desktop)"
DM=""
@@ -256,14 +227,14 @@ if [ -n "$PKGS" ]; then
fi
fi
# --- 6) Sécurité : verrouiller root s'il est resté SANS mot de passe ----------
# --- 5) Sécurité : verrouiller root s'il est resté SANS mot de passe ----------
# L'airootfs live a souvent un root sans mot de passe ; si l'utilisateur n'en a
# pas défini dans le GUI, on verrouille plutôt que de laisser le compte ouvert.
if passwd -S root 2>/dev/null | grep -qE '\bNP\b'; then
passwd -l root || true
fi
# --- 7) Le resolv.conf du live ne doit pas rester figé -----------------------
# --- 6) Le resolv.conf du live ne doit pas rester figé -----------------------
# NetworkManager (activé sur le système installé) régénère /etc/resolv.conf.
rm -f /tmp/fws-desktop /etc/resolv.conf 2>/dev/null || true
%end
+102 -1
View File
@@ -25,7 +25,7 @@
# ============================================================================
pkgname=anaconda
pkgver=45.8
pkgrel=2
pkgrel=4
pkgdesc="The Anaconda installer (porté sur Arch pour FWS, payload liveimg)"
arch=('x86_64')
url="https://github.com/rhinstaller/anaconda"
@@ -57,6 +57,107 @@ source=("anaconda-$pkgver.tar.gz::https://github.com/rhinstaller/anaconda/archiv
sha256sums=('5ef1464bff7f28a4a09a821cbb0121f09ef504ec169288d742373f86807ec4ed')
_srcdir="anaconda-anaconda-$pkgver"
prepare() {
cd "$srcdir/$_srcdir"
# ── FWS : clavier par défaut selon le TERRITOIRE de la locale ──────────────
# set_layouts() amont fait « locale = get_language_id(self.language) » →
# get_language_id JETTE le territoire (fr_CH.UTF-8 → 'fr') → list_keyboards('fr')
# = 'fr(oss)' (France) au lieu de 'ch(fr)' (Suisse). On passe la LOCALE COMPLÈTE
# (self.language) : langtable.list_keyboards('fr_CH.UTF-8') = 'ch(fr)'. La
# validation l'accepte (is_valid_langcode → parse_locale().language non vide).
# → le clavier du GUI ET du système installé suivent enfin la locale choisie.
sed -i \
's/^\(\s*\)locale = get_language_id(self\.language)/\1locale = self.language # FWS: garder le territoire (fr_CH -> ch(fr))/' \
pyanaconda/modules/localization/localization.py
# Garde-fou : casse le build si le motif amont a changé (le patch silencieux).
grep -q 'locale = self.language # FWS' \
pyanaconda/modules/localization/localization.py
# ── FWS : champ « Nom de machine » dans le spoke Utilisateur ───────────────
# Anaconda ne propage PAS le hostname (le champ du spoke Réseau est perdu chez
# nous → /etc/hostname vide). On ajoute donc un champ Hostname à l'onglet de
# création de compte (ligne 2 de la grille, libre) ; user.py écrit la valeur
# dans /tmp/fws-hostname, que le %post du kickstart applique à /etc/hostname.
python3 - <<'PYEOF'
import glob
# 1) user.glade : insérer label + entry "Host name" APRÈS le bloc username_entry.
glades = [p for p in glob.glob("pyanaconda/**/user.glade", recursive=True)
if 'username_entry' in open(p, encoding='utf-8').read()]
assert glades, "FWS: user.glade introuvable"
g = glades[0]
s = open(g, encoding='utf-8').read()
assert 'id="hostname_entry"' not in s, "FWS: glade déjà patché"
i = s.index('id="username_entry"')
k = s.index('</packing>', i) # fin du packing de username_entry
j = s.index('</child>', k) + len('</child>') # fin du <child> EXTERNE (pas l'accessible)
block = '''
<child>
<object class="GtkLabel" id="hostname_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="xpad">10</property>
<property name="label" translatable="yes" context="GUI|User">_Host name</property>
<property name="use-underline">True</property>
<property name="mnemonic-widget">hostname_entry</property>
<property name="xalign">1</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="hostname_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="width-chars">50</property>
<child internal-child="accessible">
<object class="AtkObject" id="hostname_entry-atkobject">
<property name="AtkObject::accessible-name" translatable="yes">Host Name</property>
</object>
</child>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</packing>
</child>'''
open(g, 'w', encoding='utf-8').write(s[:j] + block + s[j:])
# 2) user.py (GUI) : récupérer le widget + écrire /tmp/fws-hostname dans apply().
pys = glob.glob("pyanaconda/ui/gui/spokes/user.py")
assert pys, "FWS: user.py introuvable"
p = pys[0]
s = open(p, encoding='utf-8').read()
anchor = 'self._username_entry = self.builder.get_object("username_entry")'
assert anchor in s, "FWS: ancre username_entry absente"
s = s.replace(anchor,
anchor + '\n self._hostname_entry = self.builder.get_object("hostname_entry")',
1)
ap = 'set_user_list(self._users_module, self._user_list, remove_unset=True)'
assert ap in s, "FWS: ancre apply() absente"
s = s.replace(ap, ap + '''
# FWS : mémorise le nom de machine saisi (cible pas encore montée) pour
# le %post du kickstart, qui l'écrira dans /etc/hostname.
try:
_hn = self._hostname_entry.get_text().strip()
except Exception:
_hn = ""
try:
with open("/tmp/fws-hostname", "w") as _f:
_f.write(_hn)
except OSError:
pass''', 1)
open(p, 'w', encoding='utf-8').write(s)
print("FWS: champ Hostname ajouté au spoke Utilisateur (glade + user.py)")
PYEOF
}
build() {
cd "$srcdir/$_srcdir"
# Glade désactivé (catalogue designer, inutile au runtime) → pas de dép glade.
+4 -1
View File
@@ -114,7 +114,10 @@ if [ -z "$FWS_IN_CONTAINER" ] && ! host_is_arch; then
"${SUDO[@]}" podman pull "$IMAGE"
info "Relance dans le conteneur (setup-aur.sh)…"
"${SUDO[@]}" podman run --rm "${TTY[@]}" --privileged \
# --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 \