Compare commits
10 Commits
a63446a832
...
refactor/m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56dfe11039 | ||
|
|
88797bb1e9 | ||
|
|
2dc1881b69 | ||
|
|
21de42b6b1 | ||
|
|
6bb29fc081 | ||
|
|
cd8248f2f5 | ||
|
|
40f4efceed | ||
|
|
106fa940d7 | ||
|
|
49d94bd2ac | ||
|
|
6d65f28844 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -12,9 +12,7 @@ id_ovh*
|
|||||||
authorized_keys
|
authorized_keys
|
||||||
|
|
||||||
# ── Generated build staging (build-iso.sh populates this at build time) ─
|
# ── Generated build staging (build-iso.sh populates this at build time) ─
|
||||||
build/includes/
|
build/*
|
||||||
build/live-includes/
|
|
||||||
build/first-login.sh
|
|
||||||
|
|
||||||
# ── Build artifacts ────────────────────────────────────────────────────
|
# ── Build artifacts ────────────────────────────────────────────────────
|
||||||
out/
|
out/
|
||||||
|
|||||||
28
Makefile
28
Makefile
@@ -1,8 +1,12 @@
|
|||||||
# Void Installer — XPS 17 (xps9700)
|
# Void Installer — XPS 17 (xps9700)
|
||||||
#
|
#
|
||||||
|
# Profiles: stable-cinnamon | stable-niri | mainline-cinnamon | mainline-niri
|
||||||
|
# kernel: stable = Void's linux (k6), mainline = linux-mainline (k7)
|
||||||
|
# DE: cinnamon = Cinnamon/X11, niri = niri+noctalia-shell/Wayland
|
||||||
|
#
|
||||||
# Targets:
|
# Targets:
|
||||||
# make iso build the auto-installing ISO (uses docker)
|
# make iso build the auto-installing ISO (PROFILE=stable-cinnamon)
|
||||||
# make live build the full Cinnamon live desktop ISO
|
# make live build the full desktop live ISO (PROFILE=stable-cinnamon)
|
||||||
# make test-disk create a fresh QEMU test disk that mimics XPS 17 layout
|
# make test-disk create a fresh QEMU test disk that mimics XPS 17 layout
|
||||||
# make test full automated QEMU smoke test
|
# make test full automated QEMU smoke test
|
||||||
# make test-iso rebuild only the TEST ISO variant
|
# make test-iso rebuild only the TEST ISO variant
|
||||||
@@ -10,10 +14,16 @@
|
|||||||
# make shellcheck lint all installer/build shell scripts
|
# make shellcheck lint all installer/build shell scripts
|
||||||
# make clean remove build/, out/ (cache stays)
|
# make clean remove build/, out/ (cache stays)
|
||||||
# make distclean also remove cache/
|
# make distclean also remove cache/
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
# make live PROFILE=mainline-niri
|
||||||
|
# make iso PROFILE=stable-cinnamon
|
||||||
|
# make test PROFILE=mainline-cinnamon
|
||||||
|
|
||||||
PROJECT_DIR := $(CURDIR)
|
PROJECT_DIR := $(CURDIR)
|
||||||
OUT := $(PROJECT_DIR)/out
|
OUT := $(PROJECT_DIR)/out
|
||||||
SECRETS := $(PROJECT_DIR)/secrets.env
|
SECRETS := $(PROJECT_DIR)/secrets.env
|
||||||
|
PROFILE ?= stable-cinnamon
|
||||||
|
|
||||||
.PHONY: all iso live live-qemu test test-disk test-iso qemu shellcheck clean distclean check-secrets check-docker
|
.PHONY: all iso live live-qemu test test-disk test-iso qemu shellcheck clean distclean check-secrets check-docker
|
||||||
|
|
||||||
@@ -27,10 +37,10 @@ check-docker:
|
|||||||
@docker info >/dev/null 2>&1 || { echo "ERROR: docker daemon unreachable (in 'docker' group? systemctl start docker?)"; exit 1; }
|
@docker info >/dev/null 2>&1 || { echo "ERROR: docker daemon unreachable (in 'docker' group? systemctl start docker?)"; exit 1; }
|
||||||
|
|
||||||
iso: check-secrets check-docker
|
iso: check-secrets check-docker
|
||||||
$(PROJECT_DIR)/iso/build-iso.sh
|
$(PROJECT_DIR)/iso/build.sh --profile $(PROFILE) --type installer
|
||||||
|
|
||||||
live: check-secrets check-docker
|
live: check-secrets check-docker
|
||||||
$(PROJECT_DIR)/iso/build-live-iso.sh
|
$(PROJECT_DIR)/iso/build.sh --profile $(PROFILE) --type live
|
||||||
|
|
||||||
# Launch the live ISO in QEMU with 12 GB RAM so nix packages fit in the tmpfs.
|
# Launch the live ISO in QEMU with 12 GB RAM so nix packages fit in the tmpfs.
|
||||||
# The live session is a pure-RAM tmpfs overlay; Cinnamon + nix need ~7-8 GB total.
|
# The live session is a pure-RAM tmpfs overlay; Cinnamon + nix need ~7-8 GB total.
|
||||||
@@ -38,14 +48,14 @@ live-qemu:
|
|||||||
$(PROJECT_DIR)/tests/launch-live-qemu.sh
|
$(PROJECT_DIR)/tests/launch-live-qemu.sh
|
||||||
|
|
||||||
test-iso: check-secrets check-docker
|
test-iso: check-secrets check-docker
|
||||||
REBUILD_ISO=1 $(PROJECT_DIR)/tests/run-qemu-test.sh
|
REBUILD_ISO=1 PROFILE=$(PROFILE) $(PROJECT_DIR)/tests/run-qemu-test.sh
|
||||||
|
|
||||||
test-disk:
|
test-disk:
|
||||||
$(PROJECT_DIR)/tests/make-test-disk.sh $(OUT)/test-disk.img
|
$(PROJECT_DIR)/tests/make-test-disk.sh $(OUT)/test-disk.img
|
||||||
|
|
||||||
test: check-secrets check-docker
|
test: check-secrets check-docker
|
||||||
@mkdir -p $(OUT)
|
@mkdir -p $(OUT)
|
||||||
$(PROJECT_DIR)/tests/run-qemu-test.sh
|
PROFILE=$(PROFILE) $(PROJECT_DIR)/tests/run-qemu-test.sh
|
||||||
|
|
||||||
qemu:
|
qemu:
|
||||||
$(PROJECT_DIR)/tests/interactive-qemu.sh
|
$(PROJECT_DIR)/tests/interactive-qemu.sh
|
||||||
@@ -55,10 +65,8 @@ shellcheck:
|
|||||||
shellcheck -x \
|
shellcheck -x \
|
||||||
$(PROJECT_DIR)/installer/install.sh \
|
$(PROJECT_DIR)/installer/install.sh \
|
||||||
$(PROJECT_DIR)/installer/lib/*.sh \
|
$(PROJECT_DIR)/installer/lib/*.sh \
|
||||||
$(PROJECT_DIR)/iso/build-iso.sh \
|
$(PROJECT_DIR)/iso/build.sh \
|
||||||
$(PROJECT_DIR)/iso/_inner-build.sh \
|
$(PROJECT_DIR)/iso/_inner-build-unified.sh \
|
||||||
$(PROJECT_DIR)/iso/_inner-build-live.sh \
|
|
||||||
$(PROJECT_DIR)/iso/build-live-iso.sh \
|
|
||||||
$(PROJECT_DIR)/tests/*.sh \
|
$(PROJECT_DIR)/tests/*.sh \
|
||||||
$(PROJECT_DIR)/tests/lib/*.sh
|
$(PROJECT_DIR)/tests/lib/*.sh
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ HOSTNAME="xps9700"
|
|||||||
USERNAME="moze"
|
USERNAME="moze"
|
||||||
USER_FULLNAME="moze"
|
USER_FULLNAME="moze"
|
||||||
USER_UID="1000"
|
USER_UID="1000"
|
||||||
USER_GROUPS="wheel,docker,video,audio,input,plugdev,network,kvm,users"
|
USER_GROUPS="wheel,docker,video,audio,input,plugdev,network,kvm,users,bluetooth"
|
||||||
DEFAULT_SHELL="/bin/bash"
|
DEFAULT_SHELL="/bin/bash"
|
||||||
|
|
||||||
# ---------- Locale ----------
|
# ---------- Locale ----------
|
||||||
@@ -78,6 +78,7 @@ NIX_USER_PACKAGES=(
|
|||||||
"nixpkgs#google-chrome"
|
"nixpkgs#google-chrome"
|
||||||
"nixpkgs#mission-center"
|
"nixpkgs#mission-center"
|
||||||
"nixpkgs#vscode"
|
"nixpkgs#vscode"
|
||||||
|
"nixpkgs#fastfetch"
|
||||||
)
|
)
|
||||||
|
|
||||||
# ---------- Cinnamon customization ----------
|
# ---------- Cinnamon customization ----------
|
||||||
|
|||||||
171
config/profiles/mainline-cinnamon/packages.list
Normal file
171
config/profiles/mainline-cinnamon/packages.list
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
# Packages installed into the target system for the mainline-cinnamon profile.
|
||||||
|
# Identical to stable-cinnamon but uses Linux mainline kernel (kernel 7) for
|
||||||
|
# cutting-edge hardware support. Includes alsa-ucm-conf for SoundWire audio.
|
||||||
|
# Lines beginning with '#' or empty are skipped.
|
||||||
|
|
||||||
|
# --- base / boot ---
|
||||||
|
base-system
|
||||||
|
linux-mainline
|
||||||
|
linux-mainline-headers
|
||||||
|
linux-firmware
|
||||||
|
linux-firmware-network
|
||||||
|
intel-ucode
|
||||||
|
grub-x86_64-efi
|
||||||
|
efibootmgr
|
||||||
|
os-prober
|
||||||
|
dracut
|
||||||
|
gptfdisk
|
||||||
|
parted
|
||||||
|
btrfs-progs
|
||||||
|
dosfstools
|
||||||
|
|
||||||
|
# --- core userspace ---
|
||||||
|
sudo
|
||||||
|
bash
|
||||||
|
bash-completion
|
||||||
|
git
|
||||||
|
curl
|
||||||
|
wget
|
||||||
|
vim
|
||||||
|
nano
|
||||||
|
htop
|
||||||
|
tmux
|
||||||
|
unzip
|
||||||
|
zip
|
||||||
|
xz
|
||||||
|
rsync
|
||||||
|
pciutils
|
||||||
|
usbutils
|
||||||
|
lsof
|
||||||
|
strace
|
||||||
|
file
|
||||||
|
which
|
||||||
|
man-pages
|
||||||
|
mdocml
|
||||||
|
ca-certificates
|
||||||
|
xtools
|
||||||
|
|
||||||
|
# --- networking ---
|
||||||
|
NetworkManager
|
||||||
|
NetworkManager-openvpn
|
||||||
|
openssh
|
||||||
|
iwd
|
||||||
|
wpa_supplicant
|
||||||
|
nftables
|
||||||
|
chrony
|
||||||
|
wireless-regdb
|
||||||
|
|
||||||
|
# --- audio (pipewire stack + SoundWire / SOF support for mainline) ---
|
||||||
|
pipewire
|
||||||
|
wireplumber
|
||||||
|
alsa-pipewire
|
||||||
|
pavucontrol
|
||||||
|
alsa-utils
|
||||||
|
alsa-ucm-conf
|
||||||
|
sof-firmware
|
||||||
|
|
||||||
|
# --- graphics / xorg ---
|
||||||
|
xorg-minimal
|
||||||
|
xorg-fonts
|
||||||
|
xorg-input-drivers
|
||||||
|
xf86-input-libinput
|
||||||
|
xf86-video-intel
|
||||||
|
mesa-dri
|
||||||
|
mesa-vulkan-intel
|
||||||
|
intel-video-accel
|
||||||
|
vulkan-loader
|
||||||
|
|
||||||
|
# --- nvidia (PRIME offload) ---
|
||||||
|
nvidia
|
||||||
|
nvidia-libs-32bit
|
||||||
|
nvidia-vaapi-driver
|
||||||
|
|
||||||
|
# --- desktop ---
|
||||||
|
cinnamon
|
||||||
|
xdg-user-dirs
|
||||||
|
xdg-utils
|
||||||
|
xdg-desktop-portal
|
||||||
|
xdg-desktop-portal-gtk
|
||||||
|
gvfs
|
||||||
|
gvfs-mtp
|
||||||
|
gvfs-smb
|
||||||
|
file-roller
|
||||||
|
gnome-keyring
|
||||||
|
seahorse
|
||||||
|
network-manager-applet
|
||||||
|
blueman
|
||||||
|
bluez
|
||||||
|
|
||||||
|
# --- display manager ---
|
||||||
|
lightdm
|
||||||
|
lightdm-gtk3-greeter
|
||||||
|
|
||||||
|
# --- fonts ---
|
||||||
|
noto-fonts-ttf
|
||||||
|
noto-fonts-emoji
|
||||||
|
noto-fonts-cjk
|
||||||
|
liberation-fonts-ttf
|
||||||
|
dejavu-fonts-ttf
|
||||||
|
font-awesome6
|
||||||
|
|
||||||
|
# --- containers ---
|
||||||
|
docker
|
||||||
|
docker-compose
|
||||||
|
|
||||||
|
# --- terminal ---
|
||||||
|
alacritty
|
||||||
|
|
||||||
|
# --- gtk theming deps (for gruvbox theme) ---
|
||||||
|
sassc
|
||||||
|
gnome-themes-extra
|
||||||
|
gtk-engine-murrine
|
||||||
|
dconf
|
||||||
|
dconf-editor
|
||||||
|
|
||||||
|
# --- media / utilities ---
|
||||||
|
vlc
|
||||||
|
obs
|
||||||
|
flameshot
|
||||||
|
|
||||||
|
# --- nix package manager ---
|
||||||
|
nix
|
||||||
|
|
||||||
|
# --- zram / swap ---
|
||||||
|
zramen
|
||||||
|
|
||||||
|
# --- power / laptop ---
|
||||||
|
tlp
|
||||||
|
tlp-rdw
|
||||||
|
acpi
|
||||||
|
acpid
|
||||||
|
upower
|
||||||
|
brightnessctl
|
||||||
|
|
||||||
|
# --- printing ---
|
||||||
|
cups
|
||||||
|
cups-filters
|
||||||
|
cups-pk-helper
|
||||||
|
ghostscript
|
||||||
|
foomatic-db
|
||||||
|
gutenprint
|
||||||
|
hplip
|
||||||
|
system-config-printer
|
||||||
|
sane
|
||||||
|
simple-scan
|
||||||
|
|
||||||
|
# --- bluetooth ---
|
||||||
|
bluez-alsa
|
||||||
|
|
||||||
|
# --- backups / snapshots ---
|
||||||
|
timeshift
|
||||||
|
grub-btrfs
|
||||||
|
inotify-tools
|
||||||
|
|
||||||
|
# --- trackpad gestures ---
|
||||||
|
libinput-gestures
|
||||||
|
wmctrl
|
||||||
|
xdotool
|
||||||
|
python3-setproctitle
|
||||||
|
|
||||||
|
# --- screenshots ---
|
||||||
|
xclip
|
||||||
153
config/profiles/mainline-cinnamon/packages.live.list
Normal file
153
config/profiles/mainline-cinnamon/packages.live.list
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
# Packages included in the LIVE desktop ISO squashfs for the mainline-cinnamon profile.
|
||||||
|
# Boots into a Cinnamon session with the mainline kernel as primary.
|
||||||
|
# Includes linux (kernel 6) as a secondary fallback boot entry — same as mainline-niri.
|
||||||
|
# Lines beginning with '#' or empty are skipped.
|
||||||
|
|
||||||
|
# --- base / boot ---
|
||||||
|
base-system
|
||||||
|
# Mainline (kernel 7) — primary boot kernel
|
||||||
|
linux-mainline
|
||||||
|
linux-mainline-headers
|
||||||
|
# Kernel 6 (stable) — secondary fallback boot entry
|
||||||
|
linux
|
||||||
|
linux-headers
|
||||||
|
linux-firmware
|
||||||
|
linux-firmware-network
|
||||||
|
intel-ucode
|
||||||
|
dracut
|
||||||
|
|
||||||
|
# --- core userspace ---
|
||||||
|
sudo
|
||||||
|
bash
|
||||||
|
bash-completion
|
||||||
|
git
|
||||||
|
zenity
|
||||||
|
curl
|
||||||
|
wget
|
||||||
|
vim
|
||||||
|
nano
|
||||||
|
htop
|
||||||
|
tmux
|
||||||
|
unzip
|
||||||
|
zip
|
||||||
|
xz
|
||||||
|
rsync
|
||||||
|
pciutils
|
||||||
|
usbutils
|
||||||
|
lsof
|
||||||
|
file
|
||||||
|
which
|
||||||
|
man-pages
|
||||||
|
mdocml
|
||||||
|
ca-certificates
|
||||||
|
xtools
|
||||||
|
gptfdisk
|
||||||
|
parted
|
||||||
|
btrfs-progs
|
||||||
|
dosfstools
|
||||||
|
|
||||||
|
# --- networking ---
|
||||||
|
NetworkManager
|
||||||
|
NetworkManager-openvpn
|
||||||
|
openssh
|
||||||
|
iwd
|
||||||
|
wpa_supplicant
|
||||||
|
chrony
|
||||||
|
wireless-regdb
|
||||||
|
|
||||||
|
# --- audio (pipewire stack + SoundWire / SOF support) ---
|
||||||
|
pipewire
|
||||||
|
wireplumber
|
||||||
|
alsa-pipewire
|
||||||
|
pavucontrol
|
||||||
|
alsa-utils
|
||||||
|
alsa-ucm-conf
|
||||||
|
sof-firmware
|
||||||
|
|
||||||
|
# --- graphics / xorg ---
|
||||||
|
xorg-minimal
|
||||||
|
xorg-fonts
|
||||||
|
xorg-input-drivers
|
||||||
|
xf86-input-libinput
|
||||||
|
xf86-video-intel
|
||||||
|
xf86-video-fbdev
|
||||||
|
xf86-video-vesa
|
||||||
|
mesa-dri
|
||||||
|
mesa-vulkan-intel
|
||||||
|
intel-video-accel
|
||||||
|
vulkan-loader
|
||||||
|
|
||||||
|
# --- nvidia PRIME (from nonfree repo) ---
|
||||||
|
nvidia
|
||||||
|
nvidia-libs
|
||||||
|
nvidia-vaapi-driver
|
||||||
|
|
||||||
|
# --- desktop ---
|
||||||
|
cinnamon
|
||||||
|
xdg-user-dirs
|
||||||
|
xdg-utils
|
||||||
|
xdg-desktop-portal
|
||||||
|
xdg-desktop-portal-gtk
|
||||||
|
gvfs
|
||||||
|
gvfs-mtp
|
||||||
|
gvfs-smb
|
||||||
|
file-roller
|
||||||
|
gnome-keyring
|
||||||
|
seahorse
|
||||||
|
network-manager-applet
|
||||||
|
blueman
|
||||||
|
bluez
|
||||||
|
|
||||||
|
# --- display manager ---
|
||||||
|
lightdm
|
||||||
|
lightdm-gtk3-greeter
|
||||||
|
|
||||||
|
# --- fonts ---
|
||||||
|
noto-fonts-ttf
|
||||||
|
noto-fonts-emoji
|
||||||
|
noto-fonts-cjk
|
||||||
|
liberation-fonts-ttf
|
||||||
|
dejavu-fonts-ttf
|
||||||
|
font-awesome6
|
||||||
|
|
||||||
|
# --- terminal ---
|
||||||
|
alacritty
|
||||||
|
setxkbmap
|
||||||
|
|
||||||
|
# --- gtk theming deps ---
|
||||||
|
sassc
|
||||||
|
gnome-themes-extra
|
||||||
|
gtk-engine-murrine
|
||||||
|
dconf
|
||||||
|
dconf-editor
|
||||||
|
|
||||||
|
# --- code editors ---
|
||||||
|
vscode
|
||||||
|
|
||||||
|
# --- media / utilities ---
|
||||||
|
vlc
|
||||||
|
flameshot
|
||||||
|
|
||||||
|
# --- containers ---
|
||||||
|
docker
|
||||||
|
docker-compose
|
||||||
|
|
||||||
|
# --- nix package manager ---
|
||||||
|
nix
|
||||||
|
|
||||||
|
# --- zram / swap ---
|
||||||
|
zramen
|
||||||
|
|
||||||
|
# --- power / laptop ---
|
||||||
|
tlp
|
||||||
|
tlp-rdw
|
||||||
|
acpi
|
||||||
|
acpid
|
||||||
|
upower
|
||||||
|
brightnessctl
|
||||||
|
|
||||||
|
# --- printing ---
|
||||||
|
cups
|
||||||
|
cups-filters
|
||||||
|
cups-pk-helper
|
||||||
|
system-config-printer
|
||||||
22
config/profiles/mainline-cinnamon/profile.conf
Normal file
22
config/profiles/mainline-cinnamon/profile.conf
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Mainline-cinnamon profile.
|
||||||
|
# Linux mainline kernel (kernel 7) + Cinnamon DE + X11.
|
||||||
|
# Useful when you need cutting-edge hardware support (GPU, WiFi, SoundWire)
|
||||||
|
# with the familiar Cinnamon desktop.
|
||||||
|
PROFILE_NAME="mainline-cinnamon"
|
||||||
|
PROFILE_DESC="Linux mainline kernel + Cinnamon (X11)"
|
||||||
|
|
||||||
|
# Kernel — mainline for newest hardware and driver support.
|
||||||
|
KERNEL_PKG="linux-mainline"
|
||||||
|
|
||||||
|
# Display server / DE.
|
||||||
|
DISPLAY_SERVER="x11"
|
||||||
|
DESKTOP="cinnamon"
|
||||||
|
|
||||||
|
# Package list (relative to repo root).
|
||||||
|
PROFILE_PACKAGES_FILE="config/profiles/mainline-cinnamon/packages.list"
|
||||||
|
|
||||||
|
# Default GTK theme + icons (overrides install.conf if set there).
|
||||||
|
GTK_THEME="Gruvbox-Dark"
|
||||||
|
ICON_THEME="Gruvbox-Plus-Dark"
|
||||||
|
DEFAULT_TERMINAL="alacritty"
|
||||||
|
CURSOR_THEME="Bibata-Modern-Ice"
|
||||||
@@ -47,10 +47,9 @@ prefer-no-csd
|
|||||||
|
|
||||||
spawn-at-startup "swaybg" "-i" "/usr/share/backgrounds/void-installer/pxfuel.jpg"
|
spawn-at-startup "swaybg" "-i" "/usr/share/backgrounds/void-installer/pxfuel.jpg"
|
||||||
spawn-at-startup "mako"
|
spawn-at-startup "mako"
|
||||||
spawn-at-startup "nm-applet" "--indicator"
|
|
||||||
spawn-at-startup "blueman-applet"
|
|
||||||
spawn-at-startup "/usr/libexec/polkit-gnome-authentication-agent-1"
|
spawn-at-startup "/usr/libexec/polkit-gnome-authentication-agent-1"
|
||||||
spawn-at-startup "noctalia-shell"
|
spawn-at-startup "sh" "-c" "command -v gnome-keyring-daemon >/dev/null 2>&1 && gnome-keyring-daemon --start --components=secrets,pkcs11 >/dev/null 2>&1; true"
|
||||||
|
spawn-at-startup "sh" "-c" "i=0; while [ \$i -lt 30 ] && ! dbus-send --system --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:org.bluez >/dev/null 2>&1; do sleep 1; i=\$((i+1)); done; exec noctalia-shell"
|
||||||
|
|
||||||
cursor {
|
cursor {
|
||||||
xcursor-theme "Bibata-Modern-Ice"
|
xcursor-theme "Bibata-Modern-Ice"
|
||||||
@@ -59,7 +58,7 @@ cursor {
|
|||||||
|
|
||||||
binds {
|
binds {
|
||||||
Mod+T { spawn "alacritty"; }
|
Mod+T { spawn "alacritty"; }
|
||||||
Mod+D { spawn "fuzzel"; }
|
Mod+D { spawn "sh" "-c" "quickshell msg -c noctalia-shell launcher toggle"; }
|
||||||
Mod+Q { close-window; }
|
Mod+Q { close-window; }
|
||||||
Mod+Shift+E { quit; }
|
Mod+Shift+E { quit; }
|
||||||
Print { screenshot; }
|
Print { screenshot; }
|
||||||
@@ -99,9 +98,74 @@ export MOZ_ENABLE_WAYLAND=1
|
|||||||
export _JAVA_AWT_WM_NONREPARENTING=1
|
export _JAVA_AWT_WM_NONREPARENTING=1
|
||||||
export XDG_CURRENT_DESKTOP=niri
|
export XDG_CURRENT_DESKTOP=niri
|
||||||
export XDG_SESSION_TYPE=wayland
|
export XDG_SESSION_TYPE=wayland
|
||||||
|
export GTK_USE_PORTAL=1
|
||||||
|
export ELECTRON_OZONE_PLATFORM_HINT=auto
|
||||||
EOF
|
EOF
|
||||||
chmod 0644 "$TARGET/etc/profile.d/wayland.sh"
|
chmod 0644 "$TARGET/etc/profile.d/wayland.sh"
|
||||||
log "wayland environment installed at /etc/profile.d/wayland.sh"
|
log "wayland environment installed at /etc/profile.d/wayland.sh"
|
||||||
|
|
||||||
|
# Expose nix .desktop files and icons (installed via first-boot-nix)
|
||||||
|
cat > "$TARGET/etc/profile.d/nix-xdg.sh" <<'NIXEOF'
|
||||||
|
# Add nix profile share directory so launchers and icon themes pick up nix apps.
|
||||||
|
if [[ -d "${HOME:-}/.nix-profile/share" ]]; then
|
||||||
|
case ":${XDG_DATA_DIRS:-}:" in
|
||||||
|
*":$HOME/.nix-profile/share:"*) ;;
|
||||||
|
*) export XDG_DATA_DIRS="$HOME/.nix-profile/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
NIXEOF
|
||||||
|
chmod 0644 "$TARGET/etc/profile.d/nix-xdg.sh"
|
||||||
|
|
||||||
|
# /etc/environment: baseline XDG_DATA_DIRS loaded by pam_env for ALL session
|
||||||
|
# types (TTY login, greetd). The nix profile share path must be absolute here
|
||||||
|
# because pam_env does not expand $HOME when the key uses = (not DEFAULT=).
|
||||||
|
# The installed user's home is /home/$USERNAME, so we hardcode it.
|
||||||
|
cat > "$TARGET/etc/environment" <<ENVEOF
|
||||||
|
XDG_DATA_DIRS=/home/${USERNAME}/.nix-profile/share:/usr/local/share:/usr/share
|
||||||
|
QT_QPA_PLATFORM=wayland;xcb
|
||||||
|
GDK_BACKEND=wayland,x11
|
||||||
|
MOZ_ENABLE_WAYLAND=1
|
||||||
|
LIBSEAT_BACKEND=logind
|
||||||
|
GTK_USE_PORTAL=1
|
||||||
|
ELECTRON_OZONE_PLATFORM_HINT=auto
|
||||||
|
ENVEOF
|
||||||
|
log "/etc/environment written with XDG_DATA_DIRS for nix profile"
|
||||||
|
|
||||||
|
# dconf system keyfile: GTK dark theme reported to all apps via xdg-portal
|
||||||
|
install -d -m 0755 "$TARGET/etc/dconf/db/local.d"
|
||||||
|
install -d -m 0755 "$TARGET/etc/dconf/profile"
|
||||||
|
cat > "$TARGET/etc/dconf/db/local.d/01-dark-theme" <<'EOF'
|
||||||
|
[org/gnome/desktop/interface]
|
||||||
|
color-scheme='prefer-dark'
|
||||||
|
gtk-theme='Gruvbox-Dark'
|
||||||
|
icon-theme='Gruvbox-Plus-Dark'
|
||||||
|
cursor-theme='Bibata-Modern-Ice'
|
||||||
|
cursor-size=24
|
||||||
|
EOF
|
||||||
|
echo 'user-db:user
|
||||||
|
system-db:local' > "$TARGET/etc/dconf/profile/user"
|
||||||
|
run_chroot "dconf update 2>/dev/null || true"
|
||||||
|
log "dconf dark theme profile installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
_niri_write_session_wrapper() {
|
||||||
|
local TARGET="$1"
|
||||||
|
# Create /usr/local/bin/niri-session: sources /etc/profile before exec'ing
|
||||||
|
# niri --session so that all /etc/profile.d/* scripts (nix paths,
|
||||||
|
# XDG_DATA_DIRS with ~/.nix-profile/share, wayland env, etc.) are in effect
|
||||||
|
# for the compositor and every app it spawns.
|
||||||
|
install -d -m 0755 "$TARGET/usr/local/bin"
|
||||||
|
cat > "$TARGET/usr/local/bin/niri-session" <<'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
# niri-session — wrapper started by greetd/tuigreet.
|
||||||
|
# Sources /etc/profile so that all /etc/profile.d/* scripts run
|
||||||
|
# (nix paths, wayland env, XDG_DATA_DIRS with ~/.nix-profile/share, etc.)
|
||||||
|
# before handing off to the compositor.
|
||||||
|
[ -f /etc/profile ] && . /etc/profile
|
||||||
|
exec niri --session "$@"
|
||||||
|
EOF
|
||||||
|
chmod 0755 "$TARGET/usr/local/bin/niri-session"
|
||||||
|
log "niri-session wrapper installed at /usr/local/bin/niri-session"
|
||||||
}
|
}
|
||||||
|
|
||||||
_niri_setup_greetd() {
|
_niri_setup_greetd() {
|
||||||
@@ -143,7 +207,122 @@ EOF
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_niri_write_portal_config() {
|
||||||
|
local TARGET="$1"
|
||||||
|
# Tell xdg-desktop-portal to route all portals through the GTK backend when
|
||||||
|
# running under niri. Without this the dispatcher has no match for
|
||||||
|
# XDG_CURRENT_DESKTOP=niri and file-picker / open-with calls fail silently.
|
||||||
|
install -d -m 0755 "$TARGET/etc/xdg/xdg-desktop-portal"
|
||||||
|
cat > "$TARGET/etc/xdg/xdg-desktop-portal/niri-portals.conf" <<'EOF'
|
||||||
|
[preferred]
|
||||||
|
default=gtk
|
||||||
|
org.freedesktop.impl.portal.FileChooser=gtk
|
||||||
|
org.freedesktop.impl.portal.AppChooser=gtk
|
||||||
|
org.freedesktop.impl.portal.OpenURI=gtk
|
||||||
|
org.freedesktop.impl.portal.Print=gtk
|
||||||
|
org.freedesktop.impl.portal.Screenshot=gtk
|
||||||
|
org.freedesktop.impl.portal.Inhibit=gtk
|
||||||
|
org.freedesktop.impl.portal.Notification=gtk
|
||||||
|
org.freedesktop.impl.portal.Settings=gtk
|
||||||
|
EOF
|
||||||
|
log "niri portal config installed (gtk backend for all portals)"
|
||||||
|
}
|
||||||
|
|
||||||
|
_niri_write_sound_udev_rules() {
|
||||||
|
local TARGET="$1"
|
||||||
|
# PCM/control nodes are created root:root on some kernels before the audio
|
||||||
|
# group is provisioned. This persistent rule ensures correct ownership.
|
||||||
|
install -d -m 0755 "$TARGET/etc/udev/rules.d"
|
||||||
|
cat > "$TARGET/etc/udev/rules.d/70-sound-perms.rules" <<'EOF'
|
||||||
|
# Allow the audio group to access ALSA PCM and control devices.
|
||||||
|
SUBSYSTEM=="sound", GROUP="audio", MODE="0660"
|
||||||
|
EOF
|
||||||
|
log "sound udev rules installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
_niri_write_noctalia_defaults() {
|
||||||
|
local TARGET="$1"
|
||||||
|
# Write a baseline noctalia settings.json into skel so every new user
|
||||||
|
# (including the installed user) gets the correct wallpaper directory,
|
||||||
|
# dark mode, and Gruvbox colour scheme out of the box.
|
||||||
|
local skel_noc="$TARGET/etc/skel/.config/noctalia"
|
||||||
|
install -d -m 0755 "$skel_noc"
|
||||||
|
cat > "$skel_noc/settings.json" <<NOCEOF
|
||||||
|
{
|
||||||
|
"appLauncher": {
|
||||||
|
"iconMode": "apps",
|
||||||
|
"sortByMostUsed": true,
|
||||||
|
"showCategories": true,
|
||||||
|
"viewMode": "grid",
|
||||||
|
"pinnedApps": [],
|
||||||
|
"terminalCommand": "alacritty -e",
|
||||||
|
"density": "default",
|
||||||
|
"position": "center"
|
||||||
|
},
|
||||||
|
"colorSchemes": {
|
||||||
|
"darkMode": true,
|
||||||
|
"predefinedScheme": "Gruvbox",
|
||||||
|
"generationMethod": "tonal-spot",
|
||||||
|
"manualSunrise": "06:30",
|
||||||
|
"manualSunset": "18:30",
|
||||||
|
"monitorForColors": ""
|
||||||
|
},
|
||||||
|
"wallpaper": {
|
||||||
|
"enabled": true,
|
||||||
|
"directory": "/usr/share/backgrounds/void-installer",
|
||||||
|
"fillMode": "crop",
|
||||||
|
"fillColor": "#000000",
|
||||||
|
"automationEnabled": false,
|
||||||
|
"favorites": [],
|
||||||
|
"hideWallpaperFilenames": false,
|
||||||
|
"linkLightAndDarkWallpapers": true,
|
||||||
|
"monitorDirectories": [],
|
||||||
|
"enableMultiMonitorDirectories": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NOCEOF
|
||||||
|
chmod 0644 "$skel_noc/settings.json"
|
||||||
|
# Mirror into installed user's home
|
||||||
|
install -d -m 0755 "$TARGET/home/$USERNAME/.config/noctalia"
|
||||||
|
cp "$skel_noc/settings.json" "$TARGET/home/$USERNAME/.config/noctalia/settings.json"
|
||||||
|
run_chroot "chown -R $USERNAME:$USERNAME /home/$USERNAME/.config/noctalia" || true
|
||||||
|
log "noctalia default settings installed (wallpaper dir + Gruvbox dark)"
|
||||||
|
}
|
||||||
|
|
||||||
|
_niri_set_default_browser() {
|
||||||
|
local TARGET="$1"
|
||||||
|
# System-wide MIME defaults: google-chrome (installed via nix) as the
|
||||||
|
# default browser for http/https/html. Written to /etc/xdg/mimeapps.list
|
||||||
|
# (system default, read before ~/.config/mimeapps.list) and also into skel
|
||||||
|
# so the user-level entry is set from first login.
|
||||||
|
install -d -m 0755 "$TARGET/etc/xdg"
|
||||||
|
cat > "$TARGET/etc/xdg/mimeapps.list" <<'EOF'
|
||||||
|
[Default Applications]
|
||||||
|
text/html=google-chrome.desktop
|
||||||
|
x-scheme-handler/http=google-chrome.desktop
|
||||||
|
x-scheme-handler/https=google-chrome.desktop
|
||||||
|
x-scheme-handler/about=google-chrome.desktop
|
||||||
|
x-scheme-handler/unknown=google-chrome.desktop
|
||||||
|
application/pdf=google-chrome.desktop
|
||||||
|
application/xhtml+xml=google-chrome.desktop
|
||||||
|
application/xml=google-chrome.desktop
|
||||||
|
EOF
|
||||||
|
# Also set in user skel so ~/.config/mimeapps.list is populated on first login
|
||||||
|
install -d -m 0755 "$TARGET/etc/skel/.config"
|
||||||
|
cp "$TARGET/etc/xdg/mimeapps.list" "$TARGET/etc/skel/.config/mimeapps.list"
|
||||||
|
# Mirror into installed user home
|
||||||
|
install -d -m 0755 "$TARGET/home/$USERNAME/.config"
|
||||||
|
cp "$TARGET/etc/xdg/mimeapps.list" "$TARGET/home/$USERNAME/.config/mimeapps.list"
|
||||||
|
run_chroot "chown $USERNAME:$USERNAME /home/$USERNAME/.config/mimeapps.list" || true
|
||||||
|
log "google-chrome set as default browser (mimeapps.list)"
|
||||||
|
}
|
||||||
|
|
||||||
_niri_write_kdl "$TARGET"
|
_niri_write_kdl "$TARGET"
|
||||||
_niri_write_env "$TARGET"
|
_niri_write_env "$TARGET"
|
||||||
|
_niri_write_session_wrapper "$TARGET"
|
||||||
|
_niri_write_portal_config "$TARGET"
|
||||||
|
_niri_write_sound_udev_rules "$TARGET"
|
||||||
_niri_setup_greetd "$TARGET"
|
_niri_setup_greetd "$TARGET"
|
||||||
_niri_install_noctalia "$TARGET"
|
_niri_install_noctalia "$TARGET"
|
||||||
|
_niri_write_noctalia_defaults "$TARGET"
|
||||||
|
_niri_set_default_browser "$TARGET"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
# --- base / boot ---
|
# --- base / boot ---
|
||||||
base-system
|
base-system
|
||||||
linux-mainline
|
linux-mainline
|
||||||
|
linux-mainline-headers
|
||||||
linux-firmware
|
linux-firmware
|
||||||
linux-firmware-network
|
linux-firmware-network
|
||||||
intel-ucode
|
intel-ucode
|
||||||
@@ -49,6 +50,7 @@ openssh
|
|||||||
iwd
|
iwd
|
||||||
nftables
|
nftables
|
||||||
chrony
|
chrony
|
||||||
|
wireless-regdb
|
||||||
|
|
||||||
# --- audio (pipewire stack) ---
|
# --- audio (pipewire stack) ---
|
||||||
pipewire
|
pipewire
|
||||||
@@ -56,7 +58,9 @@ wireplumber
|
|||||||
alsa-pipewire
|
alsa-pipewire
|
||||||
pavucontrol
|
pavucontrol
|
||||||
alsa-utils
|
alsa-utils
|
||||||
|
alsa-ucm-conf
|
||||||
playerctl
|
playerctl
|
||||||
|
sof-firmware
|
||||||
|
|
||||||
# --- graphics / wayland ---
|
# --- graphics / wayland ---
|
||||||
wayland
|
wayland
|
||||||
@@ -70,12 +74,10 @@ libxkbcommon
|
|||||||
|
|
||||||
# --- nvidia (PRIME offload) ---
|
# --- nvidia (PRIME offload) ---
|
||||||
nvidia
|
nvidia
|
||||||
nvidia-libs-32bit
|
|
||||||
nvidia-vaapi-driver
|
nvidia-vaapi-driver
|
||||||
|
|
||||||
# --- niri compositor + wayland ecosystem ---
|
# --- niri compositor + wayland ecosystem ---
|
||||||
niri
|
niri
|
||||||
fuzzel
|
|
||||||
mako
|
mako
|
||||||
swaybg
|
swaybg
|
||||||
swayidle
|
swayidle
|
||||||
@@ -89,6 +91,12 @@ xdg-desktop-portal-wlr
|
|||||||
polkit-gnome
|
polkit-gnome
|
||||||
brightnessctl
|
brightnessctl
|
||||||
|
|
||||||
|
# --- file manager ---
|
||||||
|
nautilus
|
||||||
|
|
||||||
|
# --- keyring (Chrome / VSCode secret storage) ---
|
||||||
|
gnome-keyring
|
||||||
|
|
||||||
# --- noctalia shell runtime deps (noctalia-shell itself is installed in
|
# --- noctalia shell runtime deps (noctalia-shell itself is installed in
|
||||||
# niri.sh from the third-party XBPS repo at universalrepo.r1xelelo.workers.dev).
|
# niri.sh from the third-party XBPS repo at universalrepo.r1xelelo.workers.dev).
|
||||||
ImageMagick
|
ImageMagick
|
||||||
@@ -110,10 +118,12 @@ gvfs-smb
|
|||||||
file-roller
|
file-roller
|
||||||
gnome-keyring
|
gnome-keyring
|
||||||
seahorse
|
seahorse
|
||||||
network-manager-applet
|
|
||||||
blueman
|
blueman
|
||||||
bluez
|
bluez
|
||||||
|
|
||||||
|
# --- bluetooth audio ---
|
||||||
|
bluez-alsa
|
||||||
|
|
||||||
# --- display manager ---
|
# --- display manager ---
|
||||||
# niri can be launched directly via TTY (`niri-session`) or via a wayland-aware
|
# niri can be launched directly via TTY (`niri-session`) or via a wayland-aware
|
||||||
# greeter. We use greetd + tuigreet — lighter than lightdm under wayland.
|
# greeter. We use greetd + tuigreet — lighter than lightdm under wayland.
|
||||||
@@ -170,9 +180,6 @@ system-config-printer
|
|||||||
sane
|
sane
|
||||||
simple-scan
|
simple-scan
|
||||||
|
|
||||||
# --- bluetooth audio ---
|
|
||||||
bluez-alsa
|
|
||||||
|
|
||||||
# --- backups / snapshots ---
|
# --- backups / snapshots ---
|
||||||
timeshift
|
timeshift
|
||||||
grub-btrfs
|
grub-btrfs
|
||||||
|
|||||||
126
config/profiles/mainline-niri/packages.live-desktop.list
Normal file
126
config/profiles/mainline-niri/packages.live-desktop.list
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
# Packages included in the LIVE desktop ISO squashfs for the mainline-niri profile.
|
||||||
|
# Lines beginning with '#' or empty are skipped.
|
||||||
|
# noctalia-shell comes from the third-party repo added by build-niri-live-iso.sh.
|
||||||
|
|
||||||
|
# --- base / boot ---
|
||||||
|
base-system
|
||||||
|
linux-mainline
|
||||||
|
linux-mainline-headers
|
||||||
|
# Kernel 6 (stable) included for dual-boot menu entry fallback.
|
||||||
|
linux
|
||||||
|
linux-headers
|
||||||
|
linux-firmware
|
||||||
|
linux-firmware-network
|
||||||
|
intel-ucode
|
||||||
|
dracut
|
||||||
|
|
||||||
|
# --- core userspace ---
|
||||||
|
sudo
|
||||||
|
bash
|
||||||
|
bash-completion
|
||||||
|
git
|
||||||
|
curl
|
||||||
|
wget
|
||||||
|
vim
|
||||||
|
nano
|
||||||
|
htop
|
||||||
|
tmux
|
||||||
|
unzip
|
||||||
|
zip
|
||||||
|
xz
|
||||||
|
rsync
|
||||||
|
pciutils
|
||||||
|
usbutils
|
||||||
|
lsof
|
||||||
|
file
|
||||||
|
which
|
||||||
|
man-pages
|
||||||
|
mdocml
|
||||||
|
ca-certificates
|
||||||
|
xtools
|
||||||
|
gptfdisk
|
||||||
|
parted
|
||||||
|
btrfs-progs
|
||||||
|
dosfstools
|
||||||
|
efibootmgr
|
||||||
|
|
||||||
|
# --- networking ---
|
||||||
|
NetworkManager
|
||||||
|
NetworkManager-openvpn
|
||||||
|
openssh
|
||||||
|
iwd
|
||||||
|
chrony
|
||||||
|
wireless-regdb
|
||||||
|
|
||||||
|
# --- audio (pipewire stack) ---
|
||||||
|
pipewire
|
||||||
|
wireplumber
|
||||||
|
alsa-pipewire
|
||||||
|
pavucontrol
|
||||||
|
alsa-utils
|
||||||
|
alsa-ucm-conf
|
||||||
|
playerctl
|
||||||
|
sof-firmware
|
||||||
|
|
||||||
|
# --- Wayland session ---
|
||||||
|
mesa-dri
|
||||||
|
niri
|
||||||
|
xwayland-satellite
|
||||||
|
elogind
|
||||||
|
seatd
|
||||||
|
dbus
|
||||||
|
|
||||||
|
# --- nvidia PRIME (from nonfree repo) ---
|
||||||
|
nvidia
|
||||||
|
nvidia-vaapi-driver
|
||||||
|
|
||||||
|
# --- display manager ---
|
||||||
|
greetd
|
||||||
|
tuigreet
|
||||||
|
|
||||||
|
# --- terminal + launcher ---
|
||||||
|
alacritty
|
||||||
|
|
||||||
|
# --- notification + background ---
|
||||||
|
mako
|
||||||
|
swaybg
|
||||||
|
|
||||||
|
# --- bluetooth ---
|
||||||
|
bluez
|
||||||
|
blueman
|
||||||
|
|
||||||
|
# --- polkit (auth dialogs) ---
|
||||||
|
polkit
|
||||||
|
polkit-gnome
|
||||||
|
|
||||||
|
# --- noctalia-shell runtime deps ---
|
||||||
|
brightnessctl
|
||||||
|
ImageMagick
|
||||||
|
python3
|
||||||
|
upower
|
||||||
|
power-profiles-daemon
|
||||||
|
wl-clipboard
|
||||||
|
zenity
|
||||||
|
|
||||||
|
# --- XDG portals ---
|
||||||
|
xdg-desktop-portal
|
||||||
|
xdg-desktop-portal-gtk
|
||||||
|
xdg-desktop-portal-gnome
|
||||||
|
xdg-utils
|
||||||
|
xdg-user-dirs
|
||||||
|
|
||||||
|
# --- file manager ---
|
||||||
|
nautilus
|
||||||
|
|
||||||
|
# --- keyring (Chrome / VSCode secret storage) ---
|
||||||
|
gnome-keyring
|
||||||
|
|
||||||
|
# --- nix (for prebaked packages — spotify, discord, google-chrome, vscode, fastfetch, etc.) ---
|
||||||
|
nix
|
||||||
|
|
||||||
|
# --- noctalia-shell (from noctalia third-party XBPS repo) ---
|
||||||
|
noctalia-shell
|
||||||
|
|
||||||
|
# --- fonts ---
|
||||||
|
noto-fonts-ttf
|
||||||
|
noto-fonts-emoji
|
||||||
1
config/profiles/mainline-niri/packages.live.list
Symbolic link
1
config/profiles/mainline-niri/packages.live.list
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
packages.live-desktop.list
|
||||||
@@ -50,6 +50,7 @@ iwd
|
|||||||
wpa_supplicant
|
wpa_supplicant
|
||||||
nftables
|
nftables
|
||||||
chrony
|
chrony
|
||||||
|
wireless-regdb
|
||||||
|
|
||||||
# --- audio ---
|
# --- audio ---
|
||||||
pipewire
|
pipewire
|
||||||
@@ -57,6 +58,7 @@ wireplumber
|
|||||||
alsa-pipewire
|
alsa-pipewire
|
||||||
pavucontrol
|
pavucontrol
|
||||||
alsa-utils
|
alsa-utils
|
||||||
|
sof-firmware
|
||||||
|
|
||||||
# --- graphics / xorg ---
|
# --- graphics / xorg ---
|
||||||
xorg-minimal
|
xorg-minimal
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ sudo
|
|||||||
bash
|
bash
|
||||||
bash-completion
|
bash-completion
|
||||||
git
|
git
|
||||||
|
zenity
|
||||||
curl
|
curl
|
||||||
wget
|
wget
|
||||||
vim
|
vim
|
||||||
@@ -46,6 +47,7 @@ openssh
|
|||||||
iwd
|
iwd
|
||||||
wpa_supplicant
|
wpa_supplicant
|
||||||
chrony
|
chrony
|
||||||
|
wireless-regdb
|
||||||
|
|
||||||
# --- audio ---
|
# --- audio ---
|
||||||
pipewire
|
pipewire
|
||||||
@@ -53,6 +55,7 @@ wireplumber
|
|||||||
alsa-pipewire
|
alsa-pipewire
|
||||||
pavucontrol
|
pavucontrol
|
||||||
alsa-utils
|
alsa-utils
|
||||||
|
sof-firmware
|
||||||
|
|
||||||
# --- graphics / xorg ---
|
# --- graphics / xorg ---
|
||||||
xorg-minimal
|
xorg-minimal
|
||||||
|
|||||||
1
config/profiles/stable-cinnamon/packages.live.list
Symbolic link
1
config/profiles/stable-cinnamon/packages.live.list
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
packages.live-desktop.list
|
||||||
328
config/profiles/stable-niri/customizations/niri.sh
Normal file
328
config/profiles/stable-niri/customizations/niri.sh
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Niri-specific customizations. Sourced by customizations.sh after the generic
|
||||||
|
# helpers when PROFILE=mainline-niri.
|
||||||
|
# Available env: $TARGET, $USERNAME, $PROFILE, $PROFILE_DIR, all install.conf vars.
|
||||||
|
|
||||||
|
_niri_write_kdl() {
|
||||||
|
local TARGET="$1"
|
||||||
|
local cfg="$TARGET/etc/skel/.config/niri"
|
||||||
|
install -d -m 0755 "$cfg"
|
||||||
|
cat > "$cfg/config.kdl" <<'EOF'
|
||||||
|
// niri config — generated by void-installer (mainline-niri profile).
|
||||||
|
input {
|
||||||
|
keyboard {
|
||||||
|
xkb {
|
||||||
|
layout "ch"
|
||||||
|
variant "fr"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
touchpad {
|
||||||
|
tap
|
||||||
|
natural-scroll
|
||||||
|
dwt
|
||||||
|
}
|
||||||
|
mouse {
|
||||||
|
accel-speed 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout {
|
||||||
|
gaps 12
|
||||||
|
center-focused-column "never"
|
||||||
|
preset-column-widths {
|
||||||
|
proportion 0.33333
|
||||||
|
proportion 0.5
|
||||||
|
proportion 0.66667
|
||||||
|
}
|
||||||
|
default-column-width { proportion 0.5; }
|
||||||
|
focus-ring {
|
||||||
|
width 2
|
||||||
|
active-color "#fabd2f"
|
||||||
|
inactive-color "#3c3836"
|
||||||
|
}
|
||||||
|
border { off; }
|
||||||
|
}
|
||||||
|
|
||||||
|
prefer-no-csd
|
||||||
|
|
||||||
|
spawn-at-startup "swaybg" "-i" "/usr/share/backgrounds/void-installer/pxfuel.jpg"
|
||||||
|
spawn-at-startup "mako"
|
||||||
|
spawn-at-startup "/usr/libexec/polkit-gnome-authentication-agent-1"
|
||||||
|
spawn-at-startup "sh" "-c" "command -v gnome-keyring-daemon >/dev/null 2>&1 && gnome-keyring-daemon --start --components=secrets,pkcs11 >/dev/null 2>&1; true"
|
||||||
|
spawn-at-startup "sh" "-c" "i=0; while [ \$i -lt 30 ] && ! dbus-send --system --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:org.bluez >/dev/null 2>&1; do sleep 1; i=\$((i+1)); done; exec noctalia-shell"
|
||||||
|
|
||||||
|
cursor {
|
||||||
|
xcursor-theme "Bibata-Modern-Ice"
|
||||||
|
xcursor-size 24
|
||||||
|
}
|
||||||
|
|
||||||
|
binds {
|
||||||
|
Mod+T { spawn "alacritty"; }
|
||||||
|
Mod+D { spawn "sh" "-c" "quickshell msg -c noctalia-shell launcher toggle"; }
|
||||||
|
Mod+Q { close-window; }
|
||||||
|
Mod+Shift+E { quit; }
|
||||||
|
Print { screenshot; }
|
||||||
|
Mod+H { focus-column-left; }
|
||||||
|
Mod+L { focus-column-right; }
|
||||||
|
Mod+J { focus-window-down; }
|
||||||
|
Mod+K { focus-window-up; }
|
||||||
|
Mod+Shift+H { move-column-left; }
|
||||||
|
Mod+Shift+L { move-column-right; }
|
||||||
|
Mod+1 { focus-workspace 1; }
|
||||||
|
Mod+2 { focus-workspace 2; }
|
||||||
|
Mod+3 { focus-workspace 3; }
|
||||||
|
Mod+4 { focus-workspace 4; }
|
||||||
|
Mod+Shift+1 { move-column-to-workspace 1; }
|
||||||
|
Mod+Shift+2 { move-column-to-workspace 2; }
|
||||||
|
XF86AudioRaiseVolume { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "5%+"; }
|
||||||
|
XF86AudioLowerVolume { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "5%-"; }
|
||||||
|
XF86AudioMute { spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle"; }
|
||||||
|
XF86MonBrightnessUp { spawn "brightnessctl" "set" "+5%"; }
|
||||||
|
XF86MonBrightnessDown { spawn "brightnessctl" "set" "5%-"; }
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
# Mirror into the actual user home.
|
||||||
|
install -d -m 0755 "$TARGET/home/$USERNAME/.config/niri"
|
||||||
|
cp "$cfg/config.kdl" "$TARGET/home/$USERNAME/.config/niri/config.kdl"
|
||||||
|
run_chroot "chown -R $USERNAME:$USERNAME /home/$USERNAME/.config/niri" || true
|
||||||
|
log "niri KDL config installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
_niri_write_env() {
|
||||||
|
local TARGET="$1"
|
||||||
|
cat > "$TARGET/etc/profile.d/wayland.sh" <<'EOF'
|
||||||
|
# Wayland defaults installed by void-installer (mainline-niri profile).
|
||||||
|
export QT_QPA_PLATFORM="wayland;xcb"
|
||||||
|
export GDK_BACKEND=wayland,x11
|
||||||
|
export MOZ_ENABLE_WAYLAND=1
|
||||||
|
export _JAVA_AWT_WM_NONREPARENTING=1
|
||||||
|
export XDG_CURRENT_DESKTOP=niri
|
||||||
|
export XDG_SESSION_TYPE=wayland
|
||||||
|
export GTK_USE_PORTAL=1
|
||||||
|
export ELECTRON_OZONE_PLATFORM_HINT=auto
|
||||||
|
EOF
|
||||||
|
chmod 0644 "$TARGET/etc/profile.d/wayland.sh"
|
||||||
|
log "wayland environment installed at /etc/profile.d/wayland.sh"
|
||||||
|
|
||||||
|
# Expose nix .desktop files and icons (installed via first-boot-nix)
|
||||||
|
cat > "$TARGET/etc/profile.d/nix-xdg.sh" <<'NIXEOF'
|
||||||
|
# Add nix profile share directory so launchers and icon themes pick up nix apps.
|
||||||
|
if [[ -d "${HOME:-}/.nix-profile/share" ]]; then
|
||||||
|
case ":${XDG_DATA_DIRS:-}:" in
|
||||||
|
*":$HOME/.nix-profile/share:"*) ;;
|
||||||
|
*) export XDG_DATA_DIRS="$HOME/.nix-profile/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
NIXEOF
|
||||||
|
chmod 0644 "$TARGET/etc/profile.d/nix-xdg.sh"
|
||||||
|
|
||||||
|
# /etc/environment: baseline XDG_DATA_DIRS loaded by pam_env for ALL session
|
||||||
|
# types (TTY login, greetd). The nix profile share path must be absolute here
|
||||||
|
# because pam_env does not expand $HOME when the key uses = (not DEFAULT=).
|
||||||
|
# The installed user's home is /home/$USERNAME, so we hardcode it.
|
||||||
|
cat > "$TARGET/etc/environment" <<ENVEOF
|
||||||
|
XDG_DATA_DIRS=/home/${USERNAME}/.nix-profile/share:/usr/local/share:/usr/share
|
||||||
|
QT_QPA_PLATFORM=wayland;xcb
|
||||||
|
GDK_BACKEND=wayland,x11
|
||||||
|
MOZ_ENABLE_WAYLAND=1
|
||||||
|
LIBSEAT_BACKEND=logind
|
||||||
|
GTK_USE_PORTAL=1
|
||||||
|
ELECTRON_OZONE_PLATFORM_HINT=auto
|
||||||
|
ENVEOF
|
||||||
|
log "/etc/environment written with XDG_DATA_DIRS for nix profile"
|
||||||
|
|
||||||
|
# dconf system keyfile: GTK dark theme reported to all apps via xdg-portal
|
||||||
|
install -d -m 0755 "$TARGET/etc/dconf/db/local.d"
|
||||||
|
install -d -m 0755 "$TARGET/etc/dconf/profile"
|
||||||
|
cat > "$TARGET/etc/dconf/db/local.d/01-dark-theme" <<'EOF'
|
||||||
|
[org/gnome/desktop/interface]
|
||||||
|
color-scheme='prefer-dark'
|
||||||
|
gtk-theme='Gruvbox-Dark'
|
||||||
|
icon-theme='Gruvbox-Plus-Dark'
|
||||||
|
cursor-theme='Bibata-Modern-Ice'
|
||||||
|
cursor-size=24
|
||||||
|
EOF
|
||||||
|
echo 'user-db:user
|
||||||
|
system-db:local' > "$TARGET/etc/dconf/profile/user"
|
||||||
|
run_chroot "dconf update 2>/dev/null || true"
|
||||||
|
log "dconf dark theme profile installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
_niri_write_session_wrapper() {
|
||||||
|
local TARGET="$1"
|
||||||
|
# Create /usr/local/bin/niri-session: sources /etc/profile before exec'ing
|
||||||
|
# niri --session so that all /etc/profile.d/* scripts (nix paths,
|
||||||
|
# XDG_DATA_DIRS with ~/.nix-profile/share, wayland env, etc.) are in effect
|
||||||
|
# for the compositor and every app it spawns.
|
||||||
|
install -d -m 0755 "$TARGET/usr/local/bin"
|
||||||
|
cat > "$TARGET/usr/local/bin/niri-session" <<'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
# niri-session — wrapper started by greetd/tuigreet.
|
||||||
|
# Sources /etc/profile so that all /etc/profile.d/* scripts run
|
||||||
|
# (nix paths, wayland env, XDG_DATA_DIRS with ~/.nix-profile/share, etc.)
|
||||||
|
# before handing off to the compositor.
|
||||||
|
[ -f /etc/profile ] && . /etc/profile
|
||||||
|
exec niri --session "$@"
|
||||||
|
EOF
|
||||||
|
chmod 0755 "$TARGET/usr/local/bin/niri-session"
|
||||||
|
log "niri-session wrapper installed at /usr/local/bin/niri-session"
|
||||||
|
}
|
||||||
|
|
||||||
|
_niri_setup_greetd() {
|
||||||
|
local TARGET="$1"
|
||||||
|
install -d -m 0755 "$TARGET/etc/greetd"
|
||||||
|
cat > "$TARGET/etc/greetd/config.toml" <<EOF
|
||||||
|
[terminal]
|
||||||
|
vt = 1
|
||||||
|
|
||||||
|
[default_session]
|
||||||
|
command = "tuigreet --time --remember --cmd niri-session"
|
||||||
|
user = "_greeter"
|
||||||
|
EOF
|
||||||
|
log "greetd configured for niri-session"
|
||||||
|
}
|
||||||
|
|
||||||
|
_niri_install_noctalia() {
|
||||||
|
local TARGET="$1"
|
||||||
|
# Third-party Void repo that ships noctalia-shell + noctalia-qs.
|
||||||
|
# Source: https://docs.noctalia.dev/getting-started/installation/#void
|
||||||
|
install -d -m 0755 "$TARGET/etc/xbps.d"
|
||||||
|
cat > "$TARGET/etc/xbps.d/10-noctalia.conf" <<'EOF'
|
||||||
|
repository=https://universalrepo.r1xelelo.workers.dev/void
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# If quickshell is somehow installed it conflicts with noctalia-qs.
|
||||||
|
run_chroot "xbps-remove -y quickshell 2>/dev/null || true"
|
||||||
|
|
||||||
|
# Sync the new repo and install. Prefix with the proxy mirror configured
|
||||||
|
# by the installer environment so noctalia-shell deps still resolve fast.
|
||||||
|
if ! run_chroot "xbps-install -Sy"; then
|
||||||
|
log "WARN: noctalia repo sync failed; skipping noctalia-shell install"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if run_chroot "xbps-install -y noctalia-shell"; then
|
||||||
|
log "noctalia-shell installed from third-party repo"
|
||||||
|
else
|
||||||
|
log "WARN: noctalia-shell install failed (repo may be down); shell omitted"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_niri_write_portal_config() {
|
||||||
|
local TARGET="$1"
|
||||||
|
# Tell xdg-desktop-portal to route all portals through the GTK backend when
|
||||||
|
# running under niri. Without this the dispatcher has no match for
|
||||||
|
# XDG_CURRENT_DESKTOP=niri and file-picker / open-with calls fail silently.
|
||||||
|
install -d -m 0755 "$TARGET/etc/xdg/xdg-desktop-portal"
|
||||||
|
cat > "$TARGET/etc/xdg/xdg-desktop-portal/niri-portals.conf" <<'EOF'
|
||||||
|
[preferred]
|
||||||
|
default=gtk
|
||||||
|
org.freedesktop.impl.portal.FileChooser=gtk
|
||||||
|
org.freedesktop.impl.portal.AppChooser=gtk
|
||||||
|
org.freedesktop.impl.portal.OpenURI=gtk
|
||||||
|
org.freedesktop.impl.portal.Print=gtk
|
||||||
|
org.freedesktop.impl.portal.Screenshot=gtk
|
||||||
|
org.freedesktop.impl.portal.Inhibit=gtk
|
||||||
|
org.freedesktop.impl.portal.Notification=gtk
|
||||||
|
org.freedesktop.impl.portal.Settings=gtk
|
||||||
|
EOF
|
||||||
|
log "niri portal config installed (gtk backend for all portals)"
|
||||||
|
}
|
||||||
|
|
||||||
|
_niri_write_sound_udev_rules() {
|
||||||
|
local TARGET="$1"
|
||||||
|
# PCM/control nodes are created root:root on some kernels before the audio
|
||||||
|
# group is provisioned. This persistent rule ensures correct ownership.
|
||||||
|
install -d -m 0755 "$TARGET/etc/udev/rules.d"
|
||||||
|
cat > "$TARGET/etc/udev/rules.d/70-sound-perms.rules" <<'EOF'
|
||||||
|
# Allow the audio group to access ALSA PCM and control devices.
|
||||||
|
SUBSYSTEM=="sound", GROUP="audio", MODE="0660"
|
||||||
|
EOF
|
||||||
|
log "sound udev rules installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
_niri_write_noctalia_defaults() {
|
||||||
|
local TARGET="$1"
|
||||||
|
# Write a baseline noctalia settings.json into skel so every new user
|
||||||
|
# (including the installed user) gets the correct wallpaper directory,
|
||||||
|
# dark mode, and Gruvbox colour scheme out of the box.
|
||||||
|
local skel_noc="$TARGET/etc/skel/.config/noctalia"
|
||||||
|
install -d -m 0755 "$skel_noc"
|
||||||
|
cat > "$skel_noc/settings.json" <<NOCEOF
|
||||||
|
{
|
||||||
|
"appLauncher": {
|
||||||
|
"iconMode": "apps",
|
||||||
|
"sortByMostUsed": true,
|
||||||
|
"showCategories": true,
|
||||||
|
"viewMode": "grid",
|
||||||
|
"pinnedApps": [],
|
||||||
|
"terminalCommand": "alacritty -e",
|
||||||
|
"density": "default",
|
||||||
|
"position": "center"
|
||||||
|
},
|
||||||
|
"colorSchemes": {
|
||||||
|
"darkMode": true,
|
||||||
|
"predefinedScheme": "Gruvbox",
|
||||||
|
"generationMethod": "tonal-spot",
|
||||||
|
"manualSunrise": "06:30",
|
||||||
|
"manualSunset": "18:30",
|
||||||
|
"monitorForColors": ""
|
||||||
|
},
|
||||||
|
"wallpaper": {
|
||||||
|
"enabled": true,
|
||||||
|
"directory": "/usr/share/backgrounds/void-installer",
|
||||||
|
"fillMode": "crop",
|
||||||
|
"fillColor": "#000000",
|
||||||
|
"automationEnabled": false,
|
||||||
|
"favorites": [],
|
||||||
|
"hideWallpaperFilenames": false,
|
||||||
|
"linkLightAndDarkWallpapers": true,
|
||||||
|
"monitorDirectories": [],
|
||||||
|
"enableMultiMonitorDirectories": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NOCEOF
|
||||||
|
chmod 0644 "$skel_noc/settings.json"
|
||||||
|
# Mirror into installed user's home
|
||||||
|
install -d -m 0755 "$TARGET/home/$USERNAME/.config/noctalia"
|
||||||
|
cp "$skel_noc/settings.json" "$TARGET/home/$USERNAME/.config/noctalia/settings.json"
|
||||||
|
run_chroot "chown -R $USERNAME:$USERNAME /home/$USERNAME/.config/noctalia" || true
|
||||||
|
log "noctalia default settings installed (wallpaper dir + Gruvbox dark)"
|
||||||
|
}
|
||||||
|
|
||||||
|
_niri_set_default_browser() {
|
||||||
|
local TARGET="$1"
|
||||||
|
# System-wide MIME defaults: google-chrome (installed via nix) as the
|
||||||
|
# default browser for http/https/html. Written to /etc/xdg/mimeapps.list
|
||||||
|
# (system default, read before ~/.config/mimeapps.list) and also into skel
|
||||||
|
# so the user-level entry is set from first login.
|
||||||
|
install -d -m 0755 "$TARGET/etc/xdg"
|
||||||
|
cat > "$TARGET/etc/xdg/mimeapps.list" <<'EOF'
|
||||||
|
[Default Applications]
|
||||||
|
text/html=google-chrome.desktop
|
||||||
|
x-scheme-handler/http=google-chrome.desktop
|
||||||
|
x-scheme-handler/https=google-chrome.desktop
|
||||||
|
x-scheme-handler/about=google-chrome.desktop
|
||||||
|
x-scheme-handler/unknown=google-chrome.desktop
|
||||||
|
application/pdf=google-chrome.desktop
|
||||||
|
application/xhtml+xml=google-chrome.desktop
|
||||||
|
application/xml=google-chrome.desktop
|
||||||
|
EOF
|
||||||
|
# Also set in user skel so ~/.config/mimeapps.list is populated on first login
|
||||||
|
install -d -m 0755 "$TARGET/etc/skel/.config"
|
||||||
|
cp "$TARGET/etc/xdg/mimeapps.list" "$TARGET/etc/skel/.config/mimeapps.list"
|
||||||
|
# Mirror into installed user home
|
||||||
|
install -d -m 0755 "$TARGET/home/$USERNAME/.config"
|
||||||
|
cp "$TARGET/etc/xdg/mimeapps.list" "$TARGET/home/$USERNAME/.config/mimeapps.list"
|
||||||
|
run_chroot "chown $USERNAME:$USERNAME /home/$USERNAME/.config/mimeapps.list" || true
|
||||||
|
log "google-chrome set as default browser (mimeapps.list)"
|
||||||
|
}
|
||||||
|
|
||||||
|
_niri_write_kdl "$TARGET"
|
||||||
|
_niri_write_env "$TARGET"
|
||||||
|
_niri_write_session_wrapper "$TARGET"
|
||||||
|
_niri_write_portal_config "$TARGET"
|
||||||
|
_niri_write_sound_udev_rules "$TARGET"
|
||||||
|
_niri_setup_greetd "$TARGET"
|
||||||
|
_niri_install_noctalia "$TARGET"
|
||||||
|
_niri_write_noctalia_defaults "$TARGET"
|
||||||
|
_niri_set_default_browser "$TARGET"
|
||||||
190
config/profiles/stable-niri/packages.list
Normal file
190
config/profiles/stable-niri/packages.list
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
# Packages installed into the target system for the stable-niri profile.
|
||||||
|
# Identical to mainline-niri but uses Void's stable LTS kernel (linux, kernel 6)
|
||||||
|
# instead of linux-mainline.
|
||||||
|
# Lines beginning with '#' or empty are skipped.
|
||||||
|
|
||||||
|
# --- base / boot ---
|
||||||
|
base-system
|
||||||
|
linux
|
||||||
|
linux-headers
|
||||||
|
linux-firmware
|
||||||
|
linux-firmware-network
|
||||||
|
intel-ucode
|
||||||
|
grub-x86_64-efi
|
||||||
|
efibootmgr
|
||||||
|
os-prober
|
||||||
|
dracut
|
||||||
|
gptfdisk
|
||||||
|
parted
|
||||||
|
btrfs-progs
|
||||||
|
dosfstools
|
||||||
|
|
||||||
|
# --- core userspace ---
|
||||||
|
sudo
|
||||||
|
bash
|
||||||
|
bash-completion
|
||||||
|
git
|
||||||
|
curl
|
||||||
|
wget
|
||||||
|
vim
|
||||||
|
nano
|
||||||
|
htop
|
||||||
|
tmux
|
||||||
|
unzip
|
||||||
|
zip
|
||||||
|
xz
|
||||||
|
rsync
|
||||||
|
pciutils
|
||||||
|
usbutils
|
||||||
|
lsof
|
||||||
|
strace
|
||||||
|
file
|
||||||
|
which
|
||||||
|
man-pages
|
||||||
|
mdocml
|
||||||
|
ca-certificates
|
||||||
|
xtools
|
||||||
|
|
||||||
|
# --- networking ---
|
||||||
|
NetworkManager
|
||||||
|
NetworkManager-openvpn
|
||||||
|
openssh
|
||||||
|
iwd
|
||||||
|
nftables
|
||||||
|
chrony
|
||||||
|
wireless-regdb
|
||||||
|
|
||||||
|
# --- audio (pipewire stack + SoundWire / SOF support) ---
|
||||||
|
pipewire
|
||||||
|
wireplumber
|
||||||
|
alsa-pipewire
|
||||||
|
pavucontrol
|
||||||
|
alsa-utils
|
||||||
|
alsa-ucm-conf
|
||||||
|
playerctl
|
||||||
|
sof-firmware
|
||||||
|
|
||||||
|
# --- graphics / wayland ---
|
||||||
|
wayland
|
||||||
|
wayland-protocols
|
||||||
|
xorg-server-xwayland
|
||||||
|
mesa-dri
|
||||||
|
mesa-vulkan-intel
|
||||||
|
intel-video-accel
|
||||||
|
vulkan-loader
|
||||||
|
libxkbcommon
|
||||||
|
|
||||||
|
# --- nvidia (PRIME offload) ---
|
||||||
|
nvidia
|
||||||
|
nvidia-vaapi-driver
|
||||||
|
|
||||||
|
# --- niri compositor + wayland ecosystem ---
|
||||||
|
niri
|
||||||
|
mako
|
||||||
|
swaybg
|
||||||
|
swayidle
|
||||||
|
swaylock
|
||||||
|
grim
|
||||||
|
slurp
|
||||||
|
wl-clipboard
|
||||||
|
xdg-desktop-portal
|
||||||
|
xdg-desktop-portal-gtk
|
||||||
|
xdg-desktop-portal-wlr
|
||||||
|
polkit-gnome
|
||||||
|
brightnessctl
|
||||||
|
|
||||||
|
# --- file manager ---
|
||||||
|
nautilus
|
||||||
|
|
||||||
|
# --- keyring (Chrome / VSCode secret storage) ---
|
||||||
|
gnome-keyring
|
||||||
|
|
||||||
|
# --- noctalia shell runtime deps (noctalia-shell itself is installed in
|
||||||
|
# niri.sh from the third-party XBPS repo at universalrepo.r1xelelo.workers.dev).
|
||||||
|
ImageMagick
|
||||||
|
python3
|
||||||
|
ddcutil
|
||||||
|
power-profiles-daemon
|
||||||
|
upower
|
||||||
|
cliphist
|
||||||
|
wlsunset
|
||||||
|
evolution-data-server
|
||||||
|
|
||||||
|
# --- file manager extras ---
|
||||||
|
Thunar
|
||||||
|
thunar-volman
|
||||||
|
thunar-archive-plugin
|
||||||
|
gvfs
|
||||||
|
gvfs-mtp
|
||||||
|
gvfs-smb
|
||||||
|
file-roller
|
||||||
|
seahorse
|
||||||
|
|
||||||
|
# --- bluetooth ---
|
||||||
|
blueman
|
||||||
|
bluez
|
||||||
|
bluez-alsa
|
||||||
|
|
||||||
|
# --- display manager ---
|
||||||
|
greetd
|
||||||
|
tuigreet
|
||||||
|
|
||||||
|
# --- fonts ---
|
||||||
|
noto-fonts-ttf
|
||||||
|
noto-fonts-emoji
|
||||||
|
noto-fonts-cjk
|
||||||
|
liberation-fonts-ttf
|
||||||
|
dejavu-fonts-ttf
|
||||||
|
font-awesome6
|
||||||
|
|
||||||
|
# --- containers ---
|
||||||
|
docker
|
||||||
|
docker-compose
|
||||||
|
|
||||||
|
# --- terminal ---
|
||||||
|
alacritty
|
||||||
|
|
||||||
|
# --- gtk theming deps ---
|
||||||
|
sassc
|
||||||
|
gnome-themes-extra
|
||||||
|
gtk-engine-murrine
|
||||||
|
dconf
|
||||||
|
|
||||||
|
# --- media / utilities ---
|
||||||
|
vlc
|
||||||
|
obs
|
||||||
|
|
||||||
|
# --- nix package manager ---
|
||||||
|
nix
|
||||||
|
|
||||||
|
# --- zram / swap ---
|
||||||
|
zramen
|
||||||
|
|
||||||
|
# --- power / laptop ---
|
||||||
|
tlp
|
||||||
|
tlp-rdw
|
||||||
|
acpi
|
||||||
|
acpid
|
||||||
|
upower
|
||||||
|
|
||||||
|
# --- printing ---
|
||||||
|
cups
|
||||||
|
cups-filters
|
||||||
|
cups-pk-helper
|
||||||
|
ghostscript
|
||||||
|
foomatic-db
|
||||||
|
gutenprint
|
||||||
|
hplip
|
||||||
|
system-config-printer
|
||||||
|
sane
|
||||||
|
simple-scan
|
||||||
|
|
||||||
|
# --- backups / snapshots ---
|
||||||
|
timeshift
|
||||||
|
grub-btrfs
|
||||||
|
inotify-tools
|
||||||
|
|
||||||
|
# --- trackpad gestures ---
|
||||||
|
libinput-gestures
|
||||||
|
xdotool
|
||||||
|
python3-setproctitle
|
||||||
135
config/profiles/stable-niri/packages.live.list
Normal file
135
config/profiles/stable-niri/packages.live.list
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
# Packages included in the LIVE desktop ISO squashfs for the stable-niri profile.
|
||||||
|
# Boots into a niri/noctalia session. Single kernel (Void's stable LTS — no
|
||||||
|
# dual-kernel menu needed here; use mainline-niri if you want kernel 7 + fallback).
|
||||||
|
# Lines beginning with '#' or empty are skipped.
|
||||||
|
|
||||||
|
# --- base / boot ---
|
||||||
|
base-system
|
||||||
|
linux
|
||||||
|
linux-headers
|
||||||
|
linux-firmware
|
||||||
|
linux-firmware-network
|
||||||
|
intel-ucode
|
||||||
|
dracut
|
||||||
|
|
||||||
|
# --- core userspace ---
|
||||||
|
sudo
|
||||||
|
bash
|
||||||
|
bash-completion
|
||||||
|
git
|
||||||
|
curl
|
||||||
|
wget
|
||||||
|
vim
|
||||||
|
nano
|
||||||
|
htop
|
||||||
|
tmux
|
||||||
|
unzip
|
||||||
|
zip
|
||||||
|
xz
|
||||||
|
rsync
|
||||||
|
pciutils
|
||||||
|
usbutils
|
||||||
|
lsof
|
||||||
|
file
|
||||||
|
which
|
||||||
|
man-pages
|
||||||
|
mdocml
|
||||||
|
ca-certificates
|
||||||
|
xtools
|
||||||
|
gptfdisk
|
||||||
|
parted
|
||||||
|
btrfs-progs
|
||||||
|
dosfstools
|
||||||
|
efibootmgr
|
||||||
|
|
||||||
|
# --- networking ---
|
||||||
|
NetworkManager
|
||||||
|
NetworkManager-openvpn
|
||||||
|
openssh
|
||||||
|
iwd
|
||||||
|
chrony
|
||||||
|
wireless-regdb
|
||||||
|
|
||||||
|
# --- audio (pipewire stack + SoundWire / SOF support) ---
|
||||||
|
pipewire
|
||||||
|
wireplumber
|
||||||
|
alsa-pipewire
|
||||||
|
pavucontrol
|
||||||
|
alsa-utils
|
||||||
|
alsa-ucm-conf
|
||||||
|
playerctl
|
||||||
|
sof-firmware
|
||||||
|
|
||||||
|
# --- Wayland session ---
|
||||||
|
mesa-dri
|
||||||
|
niri
|
||||||
|
xwayland-satellite
|
||||||
|
elogind
|
||||||
|
seatd
|
||||||
|
dbus
|
||||||
|
wayland
|
||||||
|
|
||||||
|
# --- nvidia PRIME (from nonfree repo) ---
|
||||||
|
nvidia
|
||||||
|
nvidia-vaapi-driver
|
||||||
|
|
||||||
|
# --- display manager ---
|
||||||
|
greetd
|
||||||
|
tuigreet
|
||||||
|
|
||||||
|
# --- terminal + launcher ---
|
||||||
|
alacritty
|
||||||
|
|
||||||
|
# --- notification + background ---
|
||||||
|
mako
|
||||||
|
swaybg
|
||||||
|
|
||||||
|
# --- bluetooth ---
|
||||||
|
bluez
|
||||||
|
blueman
|
||||||
|
|
||||||
|
# --- polkit (auth dialogs) ---
|
||||||
|
polkit
|
||||||
|
polkit-gnome
|
||||||
|
|
||||||
|
# --- noctalia-shell runtime deps ---
|
||||||
|
brightnessctl
|
||||||
|
ImageMagick
|
||||||
|
python3
|
||||||
|
upower
|
||||||
|
power-profiles-daemon
|
||||||
|
wl-clipboard
|
||||||
|
zenity
|
||||||
|
|
||||||
|
# --- XDG portals ---
|
||||||
|
xdg-desktop-portal
|
||||||
|
xdg-desktop-portal-gtk
|
||||||
|
xdg-desktop-portal-gnome
|
||||||
|
xdg-utils
|
||||||
|
xdg-user-dirs
|
||||||
|
|
||||||
|
# --- file manager ---
|
||||||
|
nautilus
|
||||||
|
|
||||||
|
# --- keyring ---
|
||||||
|
gnome-keyring
|
||||||
|
|
||||||
|
# --- nix (for prebaked packages) ---
|
||||||
|
nix
|
||||||
|
|
||||||
|
# --- noctalia-shell (from noctalia third-party XBPS repo) ---
|
||||||
|
noctalia-shell
|
||||||
|
|
||||||
|
# --- fonts ---
|
||||||
|
noto-fonts-ttf
|
||||||
|
noto-fonts-emoji
|
||||||
|
noto-fonts-cjk
|
||||||
|
liberation-fonts-ttf
|
||||||
|
dejavu-fonts-ttf
|
||||||
|
font-awesome6
|
||||||
|
|
||||||
|
# --- gtk theming deps ---
|
||||||
|
sassc
|
||||||
|
gnome-themes-extra
|
||||||
|
gtk-engine-murrine
|
||||||
|
dconf
|
||||||
28
config/profiles/stable-niri/profile.conf
Normal file
28
config/profiles/stable-niri/profile.conf
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Stable-niri profile.
|
||||||
|
# Void's stable LTS kernel (linux, kernel 6) + niri Wayland tiling compositor + noctalia-shell.
|
||||||
|
PROFILE_NAME="stable-niri"
|
||||||
|
PROFILE_DESC="Stable Void kernel + niri Wayland (scrolling tiler) + noctalia-shell"
|
||||||
|
|
||||||
|
# Kernel — use Void's stable LTS.
|
||||||
|
KERNEL_PKG="linux"
|
||||||
|
|
||||||
|
# Display server / DE.
|
||||||
|
DISPLAY_SERVER="wayland"
|
||||||
|
DESKTOP="niri"
|
||||||
|
|
||||||
|
# noctalia-shell via third-party XBPS repo (universalrepo.r1xelelo.workers.dev).
|
||||||
|
WAYLAND_SHELL="noctalia"
|
||||||
|
|
||||||
|
# Package list (relative to repo root).
|
||||||
|
PROFILE_PACKAGES_FILE="config/profiles/stable-niri/packages.list"
|
||||||
|
|
||||||
|
# Theme settings (gtk3/gtk4 apps under wayland read these).
|
||||||
|
GTK_THEME="Gruvbox-Dark"
|
||||||
|
ICON_THEME="Gruvbox-Plus-Dark"
|
||||||
|
DEFAULT_TERMINAL="alacritty"
|
||||||
|
CURSOR_THEME="Bibata-Modern-Ice"
|
||||||
|
|
||||||
|
# Wayland env defaults (exported into /etc/environment by profile customisation).
|
||||||
|
QT_QPA_PLATFORM="wayland;xcb"
|
||||||
|
GDK_BACKEND="wayland,x11"
|
||||||
|
MOZ_ENABLE_WAYLAND="1"
|
||||||
122
docs/KERNEL7_AUDIO_XPS9700.md
Normal file
122
docs/KERNEL7_AUDIO_XPS9700.md
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
# Kernel 7 Audio Troubleshooting for Dell XPS 17 9700
|
||||||
|
|
||||||
|
## Symptom
|
||||||
|
On the Niri live ISO booting kernel 7, audio shows only HDMI devices and "Dummy Output" in `wpctl status`. Internal speakers and headphone jack do not appear.
|
||||||
|
|
||||||
|
## Root Cause
|
||||||
|
The XPS 17 9700 is a Dell SoundWire platform requiring **SOF + SoundWire** for internal audio on modern Linux kernels. The issue is **not** PipeWire misconfiguration. Common causes are:
|
||||||
|
|
||||||
|
1. Kernel driver stack selection issue (wrong path selected at boot)
|
||||||
|
2. Missing or mismatched SOF firmware/topology
|
||||||
|
3. Missing or mismatched `sof-soundwire` UCM profiles
|
||||||
|
4. A kernel SoundWire regression
|
||||||
|
|
||||||
|
## Diagnostic Steps
|
||||||
|
|
||||||
|
### 1. Verify the driver stack is loading
|
||||||
|
Boot into the live ISO and check which driver is active:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Should show SOF driver for internal audio
|
||||||
|
lsmod | grep -E '^sof|^snd_sof'
|
||||||
|
|
||||||
|
# Should show the SoundWire machine driver
|
||||||
|
lsmod | grep -E 'sof_sdw|sof.*mach'
|
||||||
|
|
||||||
|
# Check kernel logs for SoundWire errors
|
||||||
|
sudo dmesg | grep -Ei 'soundwire|sdw|sof.*error|topology.*-22'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Test explicit SOF driver selection
|
||||||
|
If internal audio is missing, the kernel's auto-detection may have selected the wrong path. At the GRUB/boot menu, edit the kernel command line and add:
|
||||||
|
|
||||||
|
```
|
||||||
|
snd-intel-dspcfg.dsp_driver=3
|
||||||
|
```
|
||||||
|
|
||||||
|
This explicitly forces SOF (value `3`) for the audio stack. Options are:
|
||||||
|
- `0`: auto (kernel's default)
|
||||||
|
- `1`: legacy HDA
|
||||||
|
- `3`: SOF (correct for this laptop)
|
||||||
|
- `4`: AVS
|
||||||
|
|
||||||
|
Then boot and re-check:
|
||||||
|
```bash
|
||||||
|
wpctl status
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Verify package completeness
|
||||||
|
Ensure the live image has the required audio support packages:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
xbps-query -l | grep -E '^ii.*sof-firmware|alsa-ucm-conf|alsa-utils'
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output should include:
|
||||||
|
- `sof-firmware` (Sound Open Firmware binaries and topology)
|
||||||
|
- `alsa-ucm-conf` (Use Case Manager profiles for `sof-soundwire`)
|
||||||
|
- `alsa-utils` (ALSA utilities and initial mixer state)
|
||||||
|
|
||||||
|
### 4. Check PipeWire/WirePlumber state
|
||||||
|
Once the kernel exposes the internal audio devices (they should appear in `wpctl status`), verify PipeWire is reading them correctly:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List all devices seen by PipeWire
|
||||||
|
pw-cli ls Device
|
||||||
|
|
||||||
|
# Check WirePlumber's ALSA monitor for errors
|
||||||
|
journalctl -u wireplumber.service -n 50
|
||||||
|
|
||||||
|
# Manually re-scan if needed
|
||||||
|
pw-cli list-objects Module | grep monitor
|
||||||
|
```
|
||||||
|
|
||||||
|
## If It Still Fails
|
||||||
|
|
||||||
|
### Check for a kernel regression
|
||||||
|
Recent kernel versions 6.9 and 6.10 had SoundWire regressions affecting XPS-series Dell laptops. These were fixed in:
|
||||||
|
- 6.9.x (fixed in 6.9 stable releases)
|
||||||
|
- 6.10.11+
|
||||||
|
|
||||||
|
If kernel 7.x shows the same symptoms, check the [SOF upstream issues](https://github.com/thesofproject/linux/issues) for similar reports.
|
||||||
|
|
||||||
|
### Compare against a known-good kernel
|
||||||
|
If kernel 7 still fails with `dsp_driver=3`:
|
||||||
|
1. Boot with the fallback kernel 6 (available in the Niri live ISO GRUB menu)
|
||||||
|
2. Test audio on kernel 6
|
||||||
|
3. If audio works on kernel 6 but not kernel 7, there is likely a kernel-7-specific regression
|
||||||
|
|
||||||
|
Report findings to:
|
||||||
|
- [SOF upstream](https://github.com/thesofproject/linux/issues)
|
||||||
|
- [Void Linux](https://github.com/void-linux/void-packages)
|
||||||
|
|
||||||
|
### Manual ALSA routing (for microphone issues)
|
||||||
|
If speakers work but the internal microphone does not, manually set the mic input mux:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
amixer --card 1 set 'rt715 ADC 24 Mux' 'DMIC3'
|
||||||
|
```
|
||||||
|
|
||||||
|
Then persist the state:
|
||||||
|
```bash
|
||||||
|
sudo alsactl store
|
||||||
|
```
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [ArchWiki: Dell XPS 17 (9700)](https://wiki.archlinux.org/title/Dell_XPS_17_(9700))
|
||||||
|
- [ArchWiki: Sound Open Firmware](https://wiki.archlinux.org/title/Sound_Open_Firmware)
|
||||||
|
- [SOF upstream issue 4999: 6.8.9→6.9.0 regression](https://github.com/thesofproject/linux/issues/4999)
|
||||||
|
- [Kernel docs: intel-dsp-config](https://github.com/torvalds/linux/blob/master/sound/hda/core/intel-dsp-config.c)
|
||||||
|
- [XPS 9700 Ubuntu fix guide](https://askubuntu.com/questions/1270442/no-sound-on-xps-17-9700)
|
||||||
|
|
||||||
|
## Live ISO Packages
|
||||||
|
|
||||||
|
The mainline-niri Niri live ISO includes:
|
||||||
|
- `sof-firmware`: Intel SOF binary and topology files
|
||||||
|
- `alsa-ucm-conf`: ALSA Use Case Manager profiles, including `sof-soundwire`
|
||||||
|
- `pipewire` and `wireplumber`: Session and policy management
|
||||||
|
- `linux-mainline`: Kernel 7.x with SOF support
|
||||||
|
- `linux`: Kernel 6.x fallback entry in GRUB
|
||||||
|
|
||||||
|
The build ensures both kernels are available to test audio driver behavior across kernel versions.
|
||||||
205
docs/LIVE_ISO.md
205
docs/LIVE_ISO.md
@@ -85,44 +85,74 @@ The `/etc/lightdm/.session` file (content: `cinnamon`) is read by the hook to se
|
|||||||
|
|
||||||
## Nix Integration
|
## Nix Integration
|
||||||
|
|
||||||
### Daemon mode (not single-user)
|
### Prebake architecture (packages baked into squashfs)
|
||||||
The Void `nix` xbps package ships `nix-daemon` with a runit service at `/etc/sv/nix-daemon`. The daemon puts its socket at:
|
Nix packages are **pre-installed at ISO build time** inside the Docker container and the entire `/nix` store is rsynced into the squashfs overlay. This means packages are available immediately on boot — no downloads, no tmpfs space pressure.
|
||||||
```
|
|
||||||
/var/nix/daemon-socket/socket
|
**Why not install at first login?** The live system mounts squashfs + tmpfs overlay. Installing ~4 GB of nix packages at runtime fills the tmpfs overlay and causes out-of-space failures. Baking them into squashfs sidesteps this completely.
|
||||||
|
|
||||||
|
### Build-time nix install (inside Docker, single-user)
|
||||||
|
Docker runs as root. Nix is installed in single-user mode (no daemon, no nixbld group):
|
||||||
|
```sh
|
||||||
|
mkdir -m 0755 -p /nix
|
||||||
|
export NIX_CONFIG="build-users-group = " # suppress nixbld group requirement
|
||||||
|
curl -L https://nixos.org/nix/install | sh -s -- --no-daemon
|
||||||
|
source /root/.nix-profile/etc/profile.d/nix.sh
|
||||||
|
export PATH="/root/.nix-profile/bin:$PATH"
|
||||||
|
NIXPKGS_ALLOW_UNFREE=1 nix profile add \
|
||||||
|
--extra-experimental-features "nix-command flakes" --impure \
|
||||||
|
nixpkgs#spotify nixpkgs#discord ...
|
||||||
```
|
```
|
||||||
|
|
||||||
We use daemon mode (not single-user) because `/nix/store` stays root-owned. The live user is granted trust via `nix.conf`:
|
The full `/nix` directory is then staged into the squashfs overlay:
|
||||||
|
```sh
|
||||||
|
rsync -a /nix/ "$INCLUDE_DIR/nix/"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nix prebake cache
|
||||||
|
To avoid re-downloading packages on every build, the nix store is cached at:
|
||||||
|
```
|
||||||
|
cache/nix-prebake/<md5-of-package-list>/
|
||||||
|
```
|
||||||
|
If the cache exists and the package list md5 matches, the build restores from cache instead of re-running `nix profile add`. Cache is ~5 GB. Subsequent builds with an unchanged package list complete the nix step in ~1 minute instead of ~20 minutes.
|
||||||
|
|
||||||
|
### Current packages (NIX_USER_PACKAGES in build-live-iso.sh)
|
||||||
|
- `nixpkgs#google-chrome` — replaces chromium (removed from xbps packages)
|
||||||
|
- `nixpkgs#spotify`
|
||||||
|
- `nixpkgs#discord`
|
||||||
|
- `nixpkgs#localsend`
|
||||||
|
- `nixpkgs#mission-center`
|
||||||
|
- `nixpkgs#vscode`
|
||||||
|
|
||||||
|
### XDG / PATH setup for live user
|
||||||
|
For Cinnamon to find nix `.desktop` files and for terminals to find nix binaries:
|
||||||
|
- `/etc/environment`: `XDG_DATA_DIRS=/home/live/.nix-profile/share:/usr/local/share:/usr/share`
|
||||||
|
- `/etc/profile.d/nix-prebaked.sh`: adds nix profile to `PATH` for terminal sessions
|
||||||
|
- `/etc/skel/.nix-profile` → symlink to the pre-baked store profile, copied to `/home/live/` when the live user is created by the dracut hook
|
||||||
|
|
||||||
|
### Live system nix-daemon (daemon mode)
|
||||||
|
On the **booted live system**, the Void `nix` xbps package provides `nix-daemon` as a runit service. `/nix/store` stays root-owned; the live user is granted trust via `nix.conf`:
|
||||||
```
|
```
|
||||||
experimental-features = nix-command flakes
|
experimental-features = nix-command flakes
|
||||||
sandbox = false
|
sandbox = false
|
||||||
auto-optimise-store = true
|
auto-optimise-store = true
|
||||||
trusted-users = root live
|
trusted-users = root live
|
||||||
```
|
```
|
||||||
|
The daemon socket is at `/var/nix/daemon-socket/socket` (Void's path, not the upstream default `/nix/var/nix/daemon-socket/socket`).
|
||||||
|
|
||||||
`sandbox = false` is required because the live system has no `nixbld` users and no user namespaces in the dracut initramfs environment.
|
`sandbox = false` is required — no `nixbld` users exist in the dracut initramfs environment.
|
||||||
|
|
||||||
### Package list
|
|
||||||
`/usr/local/libexec/nix-packages.list` is written at ISO build time from `NIX_USER_PACKAGES` in `config/install.conf`. At first login, `first-login.sh` reads this file and runs `nix profile install --impure` with `NIXPKGS_ALLOW_UNFREE=1`.
|
|
||||||
|
|
||||||
Current packages:
|
|
||||||
- `nixpkgs#google-chrome`
|
|
||||||
- `nixpkgs#spotify`
|
|
||||||
- `nixpkgs#discord`
|
|
||||||
- `nixpkgs#localsend`
|
|
||||||
- `nixpkgs#mission-center`
|
|
||||||
|
|
||||||
### postinstall.sh socket path (installed system)
|
### postinstall.sh socket path (installed system)
|
||||||
In the **installed system** (not live), `installer/lib/postinstall.sh` polls for the nix-daemon socket. The correct path is:
|
In the **installed system** (not live), `installer/lib/postinstall.sh` polls for the nix-daemon socket at:
|
||||||
```
|
```
|
||||||
/var/nix/daemon-socket/socket
|
/var/nix/daemon-socket/socket
|
||||||
```
|
```
|
||||||
Not `/nix/var/nix/daemon-socket/socket` (upstream Nix default) — Void's package uses `/var/nix/`.
|
Not `/nix/var/nix/daemon-socket/socket` — Void's package uses `/var/nix/`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## dconf / Theme
|
## dconf / Theme
|
||||||
|
|
||||||
The Gruvbox-Dark GTK theme and Cinnamon dconf settings are pre-applied via a system-db. The dconf binary database must be compiled at **ISO build time**, not at runtime.
|
Cinnamon settings (theme, keyboard layout, dark mode, etc.) are pre-applied via a dconf system-db. The binary database is compiled at **ISO build time** inside the Docker container.
|
||||||
|
|
||||||
### Build-time compilation
|
### Build-time compilation
|
||||||
`iso/_inner-build-live.sh` runs inside the Debian Docker container. The Dockerfile installs `dconf-cli` for this step. The correct Debian `dconf-cli` API is:
|
`iso/_inner-build-live.sh` runs inside the Debian Docker container. The Dockerfile installs `dconf-cli` for this step. The correct Debian `dconf-cli` API is:
|
||||||
@@ -143,20 +173,47 @@ system-db:local
|
|||||||
```
|
```
|
||||||
Without this file, the compiled system-db is ignored and Cinnamon shows a black wallpaper with default GTK theme.
|
Without this file, the compiled system-db is ignored and Cinnamon shows a black wallpaper with default GTK theme.
|
||||||
|
|
||||||
|
### System DB keyfile (`/etc/dconf/db/local.d/00-cinnamon`)
|
||||||
|
Built by `iso/build-live-iso.sh` from config values. Relevant excerpts:
|
||||||
|
```ini
|
||||||
|
[org/gnome/desktop/input-sources]
|
||||||
|
sources=[('xkb', 'ch+fr_nodeadkeys')]
|
||||||
|
|
||||||
|
[org/gnome/desktop/interface]
|
||||||
|
color-scheme='prefer-dark'
|
||||||
|
```
|
||||||
|
The `KEYMAP` variable comes from `config/install.conf` as `ch-fr_nodeadkeys` (vconsole dash format). The system DB uses XKB plus format. The substitution `${KEYMAP//-/+}` handles this conversion at build time.
|
||||||
|
|
||||||
|
### dconf lock file (critical for keyboard)
|
||||||
|
A lock file at `/etc/dconf/db/local.d/locks/keyboard` lists:
|
||||||
|
```
|
||||||
|
/org/gnome/desktop/input-sources/sources
|
||||||
|
```
|
||||||
|
This makes the keyboard setting **non-writable from the user session** — `gsettings set org.gnome.desktop.input-sources sources ...` silently does nothing when this lock is in place. The correct value must be set in the system DB itself (see above). Do not attempt to override the keyboard via `gsettings` from `apply-live-settings.sh` or any autostart script.
|
||||||
|
|
||||||
|
### Keyboard format: vconsole (dash) vs XKB (plus)
|
||||||
|
- mklive.sh `-k` flag accepts vconsole format: `ch-fr_nodeadkeys` (dash-separated)
|
||||||
|
- XKB / gsettings / dconf uses plus format: `ch+fr_nodeadkeys`
|
||||||
|
- Bash substitution: `${KEYMAP//-/+}` converts vconsole → XKB
|
||||||
|
- `KEYMAP` is defined in `config/install.conf` in vconsole (dash) format
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## First-Login Setup (`installer/first-login.sh`)
|
## First-Login Setup (`apply-live-settings.sh`)
|
||||||
|
|
||||||
Runs once via XDG autostart (`~/.config/autostart/void-live-first-login.desktop`) when Cinnamon first loads. Installs:
|
A lightweight XDG autostart script runs once when Cinnamon first loads and applies theme/UX settings via `gsettings`. It does **not** install packages (packages are pre-baked into squashfs).
|
||||||
|
|
||||||
1. **Claude Code** — official installer from `https://claude.ai/install.sh`
|
**Location in ISO:** `/usr/local/libexec/apply-live-settings.sh`
|
||||||
2. **Nix user packages** — from `/usr/local/libexec/nix-packages.list`
|
**Autostart:** `/etc/xdg/autostart/void-live-settings.desktop` (only in Cinnamon: `OnlyShowIn=X-Cinnamon`)
|
||||||
3. **NVM + Node LTS**
|
**Idempotency guard:** creates `~/.void-live-settings-done` on success
|
||||||
4. **VS Code extensions** — from `/etc/installer-vscode-extensions.txt`
|
|
||||||
|
|
||||||
Idempotent: creates `~/.first-login-done` on success. Logs to `~/.first-login.log`.
|
Settings applied:
|
||||||
|
- GTK/icon/cursor theme (Gruvbox-Dark)
|
||||||
|
- Cinnamon shell theme
|
||||||
|
- Wallpaper
|
||||||
|
- Default terminal (alacritty)
|
||||||
|
|
||||||
The script does NOT use `set -u` because `nvm.sh` references unbound variables.
|
The script waits for `DBUS_SESSION_BUS_ADDRESS` to be set before calling `gsettings`. It does **not** set keyboard layout — that is locked in the dconf system DB (see dconf section above).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -164,19 +221,45 @@ The script does NOT use `set -u` because `nvm.sh` references unbound variables.
|
|||||||
|
|
||||||
```
|
```
|
||||||
iso/build-live-iso.sh (host — stages overlay, builds Docker image if needed)
|
iso/build-live-iso.sh (host — stages overlay, builds Docker image if needed)
|
||||||
└─ Docker: void-installer-builder:latest
|
└─ Docker: void-installer-builder:latest (debian:stable-slim)
|
||||||
└─ iso/_inner-build-live.sh
|
└─ iso/_inner-build-live.sh
|
||||||
├─ dconf compile (pre-bakes system-db)
|
├─ nix prebake: install packages into /nix, rsync to $INCLUDE_DIR/nix/
|
||||||
└─ void-mklive/mklive.sh -a x86_64 -r <repo> -I <include_dir> ...
|
│ └─ cache/nix-prebake/<md5>/ used if package list unchanged
|
||||||
└─ squashfs + GRUB + ISO 9660
|
├─ dconf compile (compiles system-db binary from keyfile)
|
||||||
|
├─ void-mklive/mklive.sh -a x86_64 -r <repo> -I <include_dir> ...
|
||||||
|
│ └─ squashfs (xz) + GRUB + ISO 9660
|
||||||
|
└─ chown -R $HOST_UID:$HOST_GID $INCLUDE_DIR (fix Docker root ownership)
|
||||||
```
|
```
|
||||||
|
|
||||||
Output: `out/void-live-stable.iso` (~2.9 GB)
|
Output: `out/void-live-stable.iso` (~4.8 GB, xz-compressed squashfs ~22 GB uncompressed)
|
||||||
|
|
||||||
|
### Docker UID/GID ownership fix
|
||||||
|
Docker runs as root. Without remediation, files created inside the container (especially the ~5 GB nix store) are owned by `root` on the host, causing `rm -rf build/live-includes` to fail with `Permission denied` on the next build.
|
||||||
|
|
||||||
|
**Fix in `_inner-build-live.sh`** (end of script):
|
||||||
|
```sh
|
||||||
|
# Fix ownership so host user can clean up on next build
|
||||||
|
if [[ -n "${HOST_UID:-}" && "$HOST_UID" != "0" ]]; then
|
||||||
|
chmod -R u+w "$INCLUDE_DIR" 2>/dev/null || true
|
||||||
|
chown -R "${HOST_UID}:${HOST_GID}" "$INCLUDE_DIR" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
`HOST_UID` and `HOST_GID` are passed via `docker run -e HOST_UID=$(id -u) -e HOST_GID=$(id -g)`.
|
||||||
|
|
||||||
|
**Belt-and-suspenders guard in `build-live-iso.sh`** (before `rm -rf $INCLUDE_DIR`):
|
||||||
|
```sh
|
||||||
|
chmod -R u+w "$INCLUDE_DIR/nix" 2>/dev/null || sudo rm -rf "$INCLUDE_DIR/nix"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Emergency manual cleanup:** `sudo rm -rf build/live-includes/nix`
|
||||||
|
|
||||||
|
### Dockerfile dependencies
|
||||||
|
`iso/Dockerfile` (based on `debian:stable-slim`) installs: `bash git curl ca-certificates xz-utils tar patch python3 mtools xorriso squashfs-tools dosfstools e2fsprogs kmod dconf-cli rsync`. The `rsync` package is required for nix store staging.
|
||||||
|
|
||||||
### Build artifacts that must NOT be committed
|
### Build artifacts that must NOT be committed
|
||||||
- `build/live-includes/` — generated staging tree (hundreds of binary assets)
|
- `build/live-includes/` — generated staging tree (hundreds of binary assets, nix store)
|
||||||
- `out/` — ISO output
|
- `out/` — ISO output
|
||||||
- `cache/` — cloned void-mklive, xbps package cache
|
- `cache/` — cloned void-mklive, xbps/nix package cache
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -200,12 +283,50 @@ Use `nix profile add` instead. `nix profile install` is an alias that emits a wa
|
|||||||
**Cause:** QEMU's user-mode DNS proxy may not forward queries correctly depending on the host network configuration.
|
**Cause:** QEMU's user-mode DNS proxy may not forward queries correctly depending on the host network configuration.
|
||||||
**Workaround for QEMU testing:** `echo nameserver 8.8.8.8 > /etc/resolv.conf`. This is not needed on real hardware.
|
**Workaround for QEMU testing:** `echo nameserver 8.8.8.8 > /etc/resolv.conf`. This is not needed on real hardware.
|
||||||
|
|
||||||
|
### Docker root-owned files break next build
|
||||||
|
**Symptom:** `rm -rf build/live-includes` or `rm -rf build/live-includes/nix` fails with `Permission denied` at the start of a rebuild.
|
||||||
|
**Cause:** Docker runs as root. The ~5 GB nix store rsynced into `build/live-includes/nix/` is owned by `root:root` on the host.
|
||||||
|
**Fix:** `_inner-build-live.sh` now `chown -R $HOST_UID:$HOST_GID $INCLUDE_DIR` at the end of each Docker run. `HOST_UID`/`HOST_GID` are passed as env vars. See Build Pipeline section.
|
||||||
|
**Emergency cleanup:** `sudo rm -rf build/live-includes/nix`
|
||||||
|
|
||||||
|
### dconf lock file silently blocks `gsettings set`
|
||||||
|
**Symptom:** `gsettings set org.gnome.desktop.input-sources sources "[('xkb', 'ch+fr_nodeadkeys')]"` runs without error but the keyboard layout is not applied.
|
||||||
|
**Cause:** `/etc/dconf/db/local.d/locks/keyboard` locks the `input-sources` key. Any `gsettings set` targeting a locked key is silently ignored in the user session.
|
||||||
|
**Fix:** Set the correct value in the system dconf DB keyfile at ISO build time. Do not attempt to set it from an autostart script.
|
||||||
|
|
||||||
|
### Keyboard format mismatch (vconsole dash vs XKB plus)
|
||||||
|
**Symptom:** Keyboard layout reverts to US QWERTY even though `KEYMAP=ch-fr_nodeadkeys` is set.
|
||||||
|
**Cause:** mklive.sh accepts the vconsole format (`ch-fr_nodeadkeys`, dash-separated). XKB / dconf uses plus format (`ch+fr_nodeadkeys`). Passing the vconsole string directly to the dconf system DB or to `gsettings` sets an unknown layout that falls back to US.
|
||||||
|
**Fix:** In `build-live-iso.sh`, use `${KEYMAP//-/+}` when writing the dconf keyfile:
|
||||||
|
```ini
|
||||||
|
[org/gnome/desktop/input-sources]
|
||||||
|
sources=[('xkb', 'ch+fr_nodeadkeys')] # generated as: ${KEYMAP//-/+}
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## QEMU Testing
|
||||||
|
|
||||||
|
### Quick launch
|
||||||
|
```bash
|
||||||
|
bash tests/launch-live-qemu.sh
|
||||||
|
# or via Makefile:
|
||||||
|
make live-qemu
|
||||||
|
```
|
||||||
|
|
||||||
|
### What `launch-live-qemu.sh` does
|
||||||
|
- RAM: 12288 MB, 4 CPUs, KVM acceleration
|
||||||
|
- Device: `virtio-vga` with `display gtk,gl=off` (no hardware GL)
|
||||||
|
- Searches `out/void-live-stable*.iso` for the ISO
|
||||||
|
- Serial console socket: `out/live-serial.sock`
|
||||||
|
- Monitor socket: `out/qemu-monitor.sock`
|
||||||
|
- Credentials: `live`/`voidlinux` (desktop), `root`/`voidlinux` (TTY)
|
||||||
|
|
||||||
|
### Manual launch (if needed)
|
||||||
```bash
|
```bash
|
||||||
cp /usr/share/OVMF/OVMF_VARS.fd out/OVMF_VARS.live.fd
|
cp /usr/share/OVMF/OVMF_VARS.fd out/OVMF_VARS.live.fd
|
||||||
qemu-system-x86_64 -name void-live-test -machine q35,accel=kvm:tcg -cpu max \
|
qemu-system-x86_64 -name void-live-test -machine q35,accel=kvm:tcg -cpu max \
|
||||||
-m 4096 -smp 4 \
|
-m 12288 -smp 4 \
|
||||||
-drive "if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE.fd" \
|
-drive "if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE.fd" \
|
||||||
-drive "if=pflash,format=raw,file=out/OVMF_VARS.live.fd" \
|
-drive "if=pflash,format=raw,file=out/OVMF_VARS.live.fd" \
|
||||||
-cdrom out/void-live-stable.iso -boot order=d,menu=off \
|
-cdrom out/void-live-stable.iso -boot order=d,menu=off \
|
||||||
@@ -215,12 +336,20 @@ qemu-system-x86_64 -name void-live-test -machine q35,accel=kvm:tcg -cpu max \
|
|||||||
-device virtio-vga -display gtk,gl=off &
|
-device virtio-vga -display gtk,gl=off &
|
||||||
```
|
```
|
||||||
|
|
||||||
Serial console access (root shell for diagnostics):
|
### Serial console access (Python)
|
||||||
```python
|
```python
|
||||||
import socket, time
|
import socket
|
||||||
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
s.connect('out/live-serial.sock')
|
s.connect('out/live-serial.sock')
|
||||||
# send commands, read output
|
# send commands, read output
|
||||||
```
|
```
|
||||||
|
|
||||||
GPU in QEMU: `virtio-vga` is detected as virtual → `modesetting + LIBGL_ALWAYS_SOFTWARE=1`.
|
### GPU in QEMU
|
||||||
|
`virtio-vga` is detected as a virtual GPU by `live-setup.sh` → writes `modesetting + AccelMethod none` xorg conf, sets `LIBGL_ALWAYS_SOFTWARE=1` in `/etc/profile.d/live-env.sh`.
|
||||||
|
|
||||||
|
### Verifying keyboard layout (in live session)
|
||||||
|
```bash
|
||||||
|
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
|
||||||
|
gsettings get org.gnome.desktop.input-sources sources
|
||||||
|
# expected: [('xkb', 'ch+fr_nodeadkeys')]
|
||||||
|
```
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# First-login one-shot setup for the user.
|
# First-login one-shot setup for the user.
|
||||||
# Installs: Claude Code, NVM + node LTS, VS Code extensions,
|
# Installs: Claude Code, NVM + node LTS, VS Code extensions,
|
||||||
# and (if NIX_PACKAGES_FILE is present) nix user packages
|
# and (if NIX_PACKAGES_FILE is present) nix user packages
|
||||||
# (google-chrome, spotify, discord, localsend, mission-center).
|
# (google-chrome, spotify, discord, localsend, mission-center, vscode).
|
||||||
# Idempotent: creates ~/.first-login-done marker on success.
|
# Idempotent: creates ~/.first-login-done marker on success.
|
||||||
|
|
||||||
# NOTE: do NOT use `set -u` here — nvm.sh references unbound vars.
|
# NOTE: do NOT use `set -u` here — nvm.sh references unbound vars.
|
||||||
@@ -23,16 +23,17 @@ if ! curl -fsSL --max-time 3 --connect-timeout 3 -o /dev/null https://api.github
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Claude Code (official native installer) ---
|
|
||||||
mkdir -p "$HOME/.local/bin"
|
mkdir -p "$HOME/.local/bin"
|
||||||
export PATH="$HOME/.local/bin:$PATH"
|
export PATH="$HOME/.local/bin:$PATH"
|
||||||
|
|
||||||
|
# --- Claude Code (official native installer) ---
|
||||||
if ! command -v claude >/dev/null 2>&1 && [[ ! -x "$HOME/.local/bin/claude" ]]; then
|
if ! command -v claude >/dev/null 2>&1 && [[ ! -x "$HOME/.local/bin/claude" ]]; then
|
||||||
echo "==> installing Claude Code via official installer"
|
echo "==> installing Claude Code via official installer"
|
||||||
curl -fsSL https://claude.ai/install.sh | bash || {
|
curl -fsSL https://claude.ai/install.sh | bash || {
|
||||||
echo "!! claude install failed"; }
|
echo "!! claude install failed"; }
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Nix user packages (google-chrome, spotify, discord, etc.) ---
|
# --- Nix user packages (google-chrome, spotify, discord, vscode, etc.) ---
|
||||||
# Present when running from the live ISO (written by build-live-iso.sh).
|
# Present when running from the live ISO (written by build-live-iso.sh).
|
||||||
# In the installed system the packages come from first-boot-nix.sh instead.
|
# In the installed system the packages come from first-boot-nix.sh instead.
|
||||||
# NOTE: nix packages are intentionally skipped in the live session — they
|
# NOTE: nix packages are intentionally skipped in the live session — they
|
||||||
@@ -72,6 +73,7 @@ if [[ -r "$NIX_PACKAGES_FILE" ]] && command -v nix >/dev/null 2>&1; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
export NIXPKGS_ALLOW_UNFREE=1
|
export NIXPKGS_ALLOW_UNFREE=1
|
||||||
|
export NIX_REMOTE=local
|
||||||
|
|
||||||
mapfile -t pkgs < <(grep -vE '^\s*(#|$)' "$NIX_PACKAGES_FILE")
|
mapfile -t pkgs < <(grep -vE '^\s*(#|$)' "$NIX_PACKAGES_FILE")
|
||||||
if [[ ${#pkgs[@]} -gt 0 ]]; then
|
if [[ ${#pkgs[@]} -gt 0 ]]; then
|
||||||
|
|||||||
@@ -35,12 +35,18 @@ export PKG_LIST_FILE
|
|||||||
[[ -r "$PKG_LIST_FILE" ]] || die "packages.list $PKG_LIST_FILE missing"
|
[[ -r "$PKG_LIST_FILE" ]] || die "packages.list $PKG_LIST_FILE missing"
|
||||||
|
|
||||||
# ---------- profile ----------
|
# ---------- profile ----------
|
||||||
|
# PROFILE can be set on the command line or in the environment.
|
||||||
|
# If not set, fall back to DEFAULT_PROFILE which the live ISO writes to
|
||||||
|
# /etc/profile.d/00-void-installer.sh so the embedded installer defaults to
|
||||||
|
# the same configuration the live session was built with.
|
||||||
|
PROFILE="${PROFILE:-${DEFAULT_PROFILE:-stable-cinnamon}}"
|
||||||
|
export PROFILE
|
||||||
PROJECT_DIR="${PROJECT_DIR:-$SHARE_DIR}"
|
PROJECT_DIR="${PROJECT_DIR:-$SHARE_DIR}"
|
||||||
PROFILES_DIR="${PROFILES_DIR:-$SHARE_DIR/profiles}"
|
PROFILES_DIR="${PROFILES_DIR:-$SHARE_DIR/profiles}"
|
||||||
export PROJECT_DIR PROFILES_DIR
|
export PROJECT_DIR PROFILES_DIR
|
||||||
# shellcheck source=lib/profiles.sh
|
# shellcheck source=lib/profiles.sh
|
||||||
source "$INSTALLER_DIR/lib/profiles.sh"
|
source "$INSTALLER_DIR/lib/profiles.sh"
|
||||||
load_profile || die "could not load profile '${PROFILE:-stable-cinnamon}'"
|
load_profile || die "could not load profile '${PROFILE}'"
|
||||||
# Profile may override the package list.
|
# Profile may override the package list.
|
||||||
[[ -r "$PROFILE_PACKAGES_FILE" ]] && PKG_LIST_FILE="$PROFILE_PACKAGES_FILE"
|
[[ -r "$PROFILE_PACKAGES_FILE" ]] && PKG_LIST_FILE="$PROFILE_PACKAGES_FILE"
|
||||||
log "using packages list: $PKG_LIST_FILE"
|
log "using packages list: $PKG_LIST_FILE"
|
||||||
@@ -98,7 +104,7 @@ main() {
|
|||||||
configure_nvidia_prime
|
configure_nvidia_prime
|
||||||
configure_zram
|
configure_zram
|
||||||
configure_nix
|
configure_nix
|
||||||
install_vscode_real
|
[[ "${DESKTOP:-cinnamon}" != "niri" ]] && install_vscode_real
|
||||||
install_customizations
|
install_customizations
|
||||||
enable_services
|
enable_services
|
||||||
install_grub
|
install_grub
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ install_grub() {
|
|||||||
GRUB_DEFAULT=0
|
GRUB_DEFAULT=0
|
||||||
GRUB_TIMEOUT=5
|
GRUB_TIMEOUT=5
|
||||||
GRUB_DISTRIBUTOR="Void"
|
GRUB_DISTRIBUTOR="Void"
|
||||||
GRUB_CMDLINE_LINUX_DEFAULT="loglevel=4 nvidia-drm.modeset=1"
|
GRUB_CMDLINE_LINUX_DEFAULT="loglevel=4 nvidia-drm.modeset=1 rd.driver.blacklist=nouveau modprobe.blacklist=nouveau btusb.enable_autosuspend=0"
|
||||||
GRUB_CMDLINE_LINUX=""
|
GRUB_CMDLINE_LINUX=""
|
||||||
GRUB_DISABLE_OS_PROBER=false
|
GRUB_DISABLE_OS_PROBER=false
|
||||||
GRUB_TERMINAL_OUTPUT="gfxterm"
|
GRUB_TERMINAL_OUTPUT="gfxterm"
|
||||||
|
|||||||
@@ -88,6 +88,25 @@ EOF
|
|||||||
fi
|
fi
|
||||||
chmod 440 "$TARGET/etc/sudoers.d/10-wheel"
|
chmod 440 "$TARGET/etc/sudoers.d/10-wheel"
|
||||||
|
|
||||||
|
# git: GUI askpass so prompts work without a controlling terminal
|
||||||
|
install -d -m 0755 "$TARGET/usr/local/bin"
|
||||||
|
cat > "$TARGET/usr/local/bin/git-askpass" <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
for cmd in zenity qarma; do
|
||||||
|
command -v "$cmd" >/dev/null 2>&1 || continue
|
||||||
|
case "$1" in
|
||||||
|
*[Uu]sername*) exec "$cmd" --entry --title="Git Credentials" --text="$1" ;;
|
||||||
|
*) exec "$cmd" --password --title="Git Credentials" --text="$1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
printf '%s' "$1" >&2; read -r answer; printf '%s\n' "$answer"
|
||||||
|
EOF
|
||||||
|
chmod 0755 "$TARGET/usr/local/bin/git-askpass"
|
||||||
|
cat > "$TARGET/etc/gitconfig" <<'EOF'
|
||||||
|
[core]
|
||||||
|
askPass = /usr/local/bin/git-askpass
|
||||||
|
EOF
|
||||||
|
|
||||||
ok "user '$USERNAME' created and added to: $USER_GROUPS"
|
ok "user '$USERNAME' created and added to: $USER_GROUPS"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +160,19 @@ Section "OutputClass"
|
|||||||
EndSection
|
EndSection
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# 2) Modules to load early for KMS.
|
# 2) Blacklist nouveau so it doesn't grab the GPU before nvidia loads.
|
||||||
|
install -d -m 0755 "$TARGET/etc/modprobe.d"
|
||||||
|
cat > "$TARGET/etc/modprobe.d/blacklist-nouveau.conf" <<'EOF'
|
||||||
|
blacklist nouveau
|
||||||
|
options nouveau modeset=0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# btusb USB autosuspend causes firmware download failures on Intel BT.
|
||||||
|
cat > "$TARGET/etc/modprobe.d/btusb-quirks.conf" <<'EOF'
|
||||||
|
options btusb enable_autosuspend=0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 3) Modules to load early for KMS.
|
||||||
install -d -m 0755 "$TARGET/etc/modules-load.d"
|
install -d -m 0755 "$TARGET/etc/modules-load.d"
|
||||||
cat > "$TARGET/etc/modules-load.d/nvidia.conf" <<'EOF'
|
cat > "$TARGET/etc/modules-load.d/nvidia.conf" <<'EOF'
|
||||||
nvidia
|
nvidia
|
||||||
@@ -150,7 +181,7 @@ nvidia_uvm
|
|||||||
nvidia_drm
|
nvidia_drm
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# 3) Wrapper script + desktop file: run any app on NVIDIA via `prime-run`.
|
# 4) Wrapper script + desktop file: run any app on NVIDIA via `prime-run`.
|
||||||
install -d -m 0755 "$TARGET/usr/local/bin"
|
install -d -m 0755 "$TARGET/usr/local/bin"
|
||||||
cat > "$TARGET/usr/local/bin/prime-run" <<'EOF'
|
cat > "$TARGET/usr/local/bin/prime-run" <<'EOF'
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
@@ -162,10 +193,11 @@ exec env __NV_PRIME_RENDER_OFFLOAD=1 \
|
|||||||
EOF
|
EOF
|
||||||
chmod 0755 "$TARGET/usr/local/bin/prime-run"
|
chmod 0755 "$TARGET/usr/local/bin/prime-run"
|
||||||
|
|
||||||
# 4) Make sure dracut picks up nvidia modules.
|
# 5) dracut: include nvidia modules in initramfs; explicitly omit nouveau.
|
||||||
install -d -m 0755 "$TARGET/etc/dracut.conf.d"
|
install -d -m 0755 "$TARGET/etc/dracut.conf.d"
|
||||||
cat > "$TARGET/etc/dracut.conf.d/10-nvidia.conf" <<'EOF'
|
cat > "$TARGET/etc/dracut.conf.d/10-nvidia.conf" <<'EOF'
|
||||||
add_drivers+=" nvidia nvidia_modeset nvidia_uvm nvidia_drm "
|
add_drivers+=" nvidia nvidia_modeset nvidia_uvm nvidia_drm "
|
||||||
|
omit_drivers+=" nouveau "
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
ok "NVIDIA PRIME offload configured (use 'prime-run <app>')"
|
ok "NVIDIA PRIME offload configured (use 'prime-run <app>')"
|
||||||
@@ -206,13 +238,12 @@ mark=/var/lib/first-boot-nix.done
|
|||||||
[[ -f "\$mark" ]] && exit 0
|
[[ -f "\$mark" ]] && exit 0
|
||||||
|
|
||||||
# Wait for nix-daemon to be available.
|
# Wait for nix-daemon to be available.
|
||||||
# The Void xbps nix package puts the socket at /var/nix/daemon-socket/socket.
|
|
||||||
for _ in \$(seq 1 60); do
|
for _ in \$(seq 1 60); do
|
||||||
[[ -S /var/nix/daemon-socket/socket ]] && break
|
[[ -S /nix/var/nix/daemon-socket/socket ]] && break
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ ! -S /var/nix/daemon-socket/socket ]]; then
|
if [[ ! -S /nix/var/nix/daemon-socket/socket ]]; then
|
||||||
echo "nix-daemon not available; aborting first-boot nix install" >&2
|
echo "nix-daemon not available; aborting first-boot nix install" >&2
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
@@ -230,6 +261,12 @@ touch "\$mark"
|
|||||||
EOF
|
EOF
|
||||||
chmod 0755 "$TARGET/usr/local/libexec/first-boot-nix.sh"
|
chmod 0755 "$TARGET/usr/local/libexec/first-boot-nix.sh"
|
||||||
|
|
||||||
|
# Persistent nixpkgs config so the installed user can install unfree packages
|
||||||
|
# without needing to export NIXPKGS_ALLOW_UNFREE=1 every time.
|
||||||
|
install -d -m 0755 "$TARGET/home/$USERNAME/.config/nixpkgs"
|
||||||
|
echo '{ allowUnfree = true; }' > "$TARGET/home/$USERNAME/.config/nixpkgs/config.nix"
|
||||||
|
run_chroot "chown -R $USERNAME:$USERNAME /home/$USERNAME/.config/nixpkgs"
|
||||||
|
|
||||||
# runit one-shot service.
|
# runit one-shot service.
|
||||||
install -d -m 0755 "$TARGET/etc/sv/first-boot-nix"
|
install -d -m 0755 "$TARGET/etc/sv/first-boot-nix"
|
||||||
cat > "$TARGET/etc/sv/first-boot-nix/run" <<'EOF'
|
cat > "$TARGET/etc/sv/first-boot-nix/run" <<'EOF'
|
||||||
@@ -312,10 +349,8 @@ enable_services() {
|
|||||||
local enabled=(
|
local enabled=(
|
||||||
dbus
|
dbus
|
||||||
NetworkManager
|
NetworkManager
|
||||||
lightdm
|
|
||||||
polkitd
|
polkitd
|
||||||
docker
|
docker
|
||||||
bluetoothd
|
|
||||||
acpid
|
acpid
|
||||||
tlp
|
tlp
|
||||||
elogind
|
elogind
|
||||||
@@ -326,6 +361,14 @@ enable_services() {
|
|||||||
cupsd
|
cupsd
|
||||||
cups-browsed
|
cups-browsed
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Display manager: greetd for wayland/niri, lightdm for cinnamon.
|
||||||
|
if [[ "${DESKTOP:-cinnamon}" == "niri" ]]; then
|
||||||
|
enabled+=(greetd bluetoothd)
|
||||||
|
else
|
||||||
|
enabled+=(lightdm bluetoothd)
|
||||||
|
fi
|
||||||
|
|
||||||
[[ "${SSHD_ENABLE:-no}" == "yes" ]] && enabled+=(sshd)
|
[[ "${SSHD_ENABLE:-no}" == "yes" ]] && enabled+=(sshd)
|
||||||
|
|
||||||
for svc in "${enabled[@]}"; do
|
for svc in "${enabled[@]}"; do
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ ENV DEBIAN_FRONTEND=noninteractive
|
|||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
bash git curl ca-certificates xz-utils tar patch python3 \
|
bash git curl ca-certificates xz-utils tar patch python3 \
|
||||||
mtools xorriso squashfs-tools dosfstools e2fsprogs \
|
mtools xorriso squashfs-tools dosfstools e2fsprogs \
|
||||||
kmod dconf-cli rsync \
|
kmod dconf-cli rsync openssl \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# xbps-static is downloaded into /cache by the host script and added to PATH
|
# xbps-static is downloaded into /cache by the host script and added to PATH
|
||||||
|
|||||||
@@ -27,14 +27,35 @@ command -v xbps-install.static >/dev/null \
|
|||||||
|
|
||||||
mkdir -p "$(dirname "$OUT_ISO")"
|
mkdir -p "$(dirname "$OUT_ISO")"
|
||||||
|
|
||||||
# Compile dconf system-db inside the include dir so it ships compiled.
|
# Compile dconf system-db using Void's own dconf binary (inside the Void
|
||||||
# Debian's dconf-cli provides 'dconf compile <output_db> <keyfile_dir>'.
|
# rootfs chroot via mklive's -x postsetup hook). This guarantees the GVDB
|
||||||
if command -v dconf >/dev/null 2>&1 && [[ -d "$INCLUDE_DIR/etc/dconf/db/local.d" ]]; then
|
# binary is produced by the exact same dconf/glib version that runs on the
|
||||||
dconf compile "$INCLUDE_DIR/etc/dconf/db/local" \
|
# live system — no cross-distro format mismatch possible.
|
||||||
"$INCLUDE_DIR/etc/dconf/db/local.d" 2>/dev/null \
|
# (We do NOT pre-compile with Debian's dconf here; that caused silent failures
|
||||||
&& echo "dconf: compiled system-db/local" \
|
# when the GVDB format differed between the host and Void's glib.)
|
||||||
|| echo "dconf: compile failed (non-fatal)"
|
_DCONF_POSTSETUP="$(mktemp -p "$MKLIVE_DIR" postsetup-dconf.XXXXX.sh)"
|
||||||
|
cat > "$_DCONF_POSTSETUP" <<'PSEOF'
|
||||||
|
#!/bin/bash
|
||||||
|
# Postsetup script: compile dconf system-db AND user skel db with Void's own binary.
|
||||||
|
ROOTFS="$1"
|
||||||
|
if [[ -x "$ROOTFS/usr/bin/dconf" ]] && [[ -d "$ROOTFS/etc/dconf/db/local.d" ]]; then
|
||||||
|
# 1. Compile system-db (read by all users via /etc/dconf/profile/user)
|
||||||
|
chroot "$ROOTFS" dconf compile /etc/dconf/db/local /etc/dconf/db/local.d \
|
||||||
|
&& echo "postsetup: system-db compiled ($(chroot "$ROOTFS" dconf --version 2>/dev/null))" \
|
||||||
|
|| echo "postsetup: system-db compile failed (non-fatal)"
|
||||||
|
# 2. Compile a USER dconf db directly into /etc/skel/.config/dconf/user.
|
||||||
|
# dracut's adduser.sh copies skel → /home/live on first boot, so the live
|
||||||
|
# user starts with the keyboard in their OWN user db — no dependency on
|
||||||
|
# dconf profile/system-db loading order.
|
||||||
|
mkdir -p "$ROOTFS/etc/skel/.config/dconf"
|
||||||
|
chroot "$ROOTFS" dconf compile /etc/skel/.config/dconf/user /etc/dconf/db/local.d \
|
||||||
|
&& echo "postsetup: skel user dconf db compiled" \
|
||||||
|
|| echo "postsetup: skel user dconf db compile failed (non-fatal)"
|
||||||
|
else
|
||||||
|
echo "postsetup: dconf or keyfile dir not found in rootfs — skipping dconf compile"
|
||||||
fi
|
fi
|
||||||
|
PSEOF
|
||||||
|
chmod +x "$_DCONF_POSTSETUP"
|
||||||
|
|
||||||
cd "$MKLIVE_DIR"
|
cd "$MKLIVE_DIR"
|
||||||
|
|
||||||
@@ -91,6 +112,8 @@ if [[ -n "${NIX_PACKAGES_PREBAKE:-}" ]]; then
|
|||||||
echo " staging /nix into overlay ($(du -sh /nix/store 2>/dev/null | cut -f1))"
|
echo " staging /nix into overlay ($(du -sh /nix/store 2>/dev/null | cut -f1))"
|
||||||
mkdir -p "$INCLUDE_DIR/nix"
|
mkdir -p "$INCLUDE_DIR/nix"
|
||||||
rsync -a /nix/ "$INCLUDE_DIR/nix/" 2>&1 | tail -1
|
rsync -a /nix/ "$INCLUDE_DIR/nix/" 2>&1 | tail -1
|
||||||
|
# Single-user nix: the live user (uid 1000) must own the store to create lock files and new paths.
|
||||||
|
chown -R 1000:1000 "$INCLUDE_DIR/nix"
|
||||||
|
|
||||||
# /etc/skel/.nix-profile → the pre-baked store profile path.
|
# /etc/skel/.nix-profile → the pre-baked store profile path.
|
||||||
# dracut's adduser.sh runs 'useradd -m' which copies skel → /home/live,
|
# dracut's adduser.sh runs 'useradd -m' which copies skel → /home/live,
|
||||||
@@ -132,6 +155,13 @@ trap _cleanup_mklive_builds EXIT
|
|||||||
-p "$ISO_PKGS" \
|
-p "$ISO_PKGS" \
|
||||||
-I "$INCLUDE_DIR" \
|
-I "$INCLUDE_DIR" \
|
||||||
-C "${BOOT_CMDLINE:-}" \
|
-C "${BOOT_CMDLINE:-}" \
|
||||||
|
-x "$_DCONF_POSTSETUP" \
|
||||||
-o "$OUT_ISO"
|
-o "$OUT_ISO"
|
||||||
|
|
||||||
chown "$(stat -c '%u:%g' "$PROJECT_DIR")" "$OUT_ISO" "${OUT_ISO}".* 2>/dev/null || true
|
# ownership of OUT_ISO is fixed unconditionally below with the include dir
|
||||||
|
|
||||||
|
# Fix ownership of include dir so the host user can clean up without sudo.
|
||||||
|
# u+rwX: sets read+write on all, execute only on directories (capital X).
|
||||||
|
chmod -R u+rwX "$INCLUDE_DIR" 2>/dev/null || true
|
||||||
|
chown -R "${HOST_UID:-1000}:${HOST_GID:-1000}" "$INCLUDE_DIR" 2>/dev/null || true
|
||||||
|
chown -R "${HOST_UID:-1000}:${HOST_GID:-1000}" "$OUT_ISO" "${OUT_ISO}".* 2>/dev/null || true
|
||||||
|
|||||||
270
iso/_inner-build-niri-live.sh
Executable file
270
iso/_inner-build-niri-live.sh
Executable file
@@ -0,0 +1,270 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Runs INSIDE the docker container (as root). Invoked by iso/build-niri-live-iso.sh.
|
||||||
|
# Niri/Wayland variant: nix prebake (shared cache with Cinnamon), adds noctalia repo.
|
||||||
|
# Expects the project bind-mounted at /work and the cache at /cache.
|
||||||
|
#
|
||||||
|
# Required env (set by build-niri-live-iso.sh):
|
||||||
|
# ARCH, REPO_URL, KEYMAP, LOCALE, ISO_PKGS, ISO_TITLE, OUT_ISO_REL,
|
||||||
|
# INCLUDE_DIR_REL, NIX_PACKAGES_PREBAKE (optional)
|
||||||
|
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
: "${ARCH:?}"; : "${REPO_URL:?}"; : "${KEYMAP:?}"; : "${LOCALE:?}"
|
||||||
|
: "${ISO_PKGS:?}"; : "${ISO_TITLE:?}"; : "${OUT_ISO_REL:?}"
|
||||||
|
: "${INCLUDE_DIR_REL:?}"
|
||||||
|
|
||||||
|
CACHE_DIR=/cache
|
||||||
|
PROJECT_DIR=/work
|
||||||
|
MKLIVE_DIR="$CACHE_DIR/void-mklive-niri" # separate clone — avoids race with Cinnamon parallel build
|
||||||
|
INCLUDE_DIR="$PROJECT_DIR/$INCLUDE_DIR_REL"
|
||||||
|
OUT_ISO="$PROJECT_DIR/$OUT_ISO_REL"
|
||||||
|
|
||||||
|
# Third-party Void repo that ships noctalia-shell + noctalia-qs.
|
||||||
|
NOCTALIA_REPO="${NOCTALIA_REPO:-https://universalrepo.r1xelelo.workers.dev/void}"
|
||||||
|
|
||||||
|
export PATH="$CACHE_DIR/xbps-static/usr/bin:$PATH"
|
||||||
|
|
||||||
|
[[ -d "$MKLIVE_DIR" ]] || { echo "ERROR: $MKLIVE_DIR missing"; exit 1; }
|
||||||
|
[[ -d "$INCLUDE_DIR" ]] || { echo "ERROR: $INCLUDE_DIR missing"; exit 1; }
|
||||||
|
command -v xbps-install.static >/dev/null \
|
||||||
|
|| { echo "ERROR: xbps-install.static not on PATH"; exit 1; }
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$OUT_ISO")"
|
||||||
|
|
||||||
|
# ── Audio and Theme Support ──────────────────────────────────────────────
|
||||||
|
# The Niri live ISO includes:
|
||||||
|
# 1. sof-firmware: Intel Sound Open Firmware (required for modern Intel audio)
|
||||||
|
# 2. alsa-ucm-conf: ALSA Use Case Manager profiles (sof-soundwire for SoundWire hardware)
|
||||||
|
# 3. Removed forced audio kernel parameters: The kernel auto-selects SOF/HDA/AVS
|
||||||
|
# based on hardware IDs. Forced parameters (snd-intel-dspcfg.dsp_driver=1)
|
||||||
|
# broke audio on SoundWire platforms like XPS 9700.
|
||||||
|
# See iso/build-niri-live-iso.sh (BOOT_CMDLINE) and docs/KERNEL7_AUDIO_XPS9700.md
|
||||||
|
# 4. Dark theme dconf database: Compiled here during ISO build.
|
||||||
|
|
||||||
|
# Compile dconf system-db using Void's own dconf binary inside the target
|
||||||
|
# rootfs. The Niri live builder writes /etc/dconf/db/local.d/01-dark-theme,
|
||||||
|
# but the live system will not report the dark theme unless the GVDB is
|
||||||
|
# compiled into /etc/dconf/db/local (and into skel for the live user).
|
||||||
|
_DCONF_POSTSETUP="$(mktemp -p "$MKLIVE_DIR" postsetup-dconf.XXXXX.sh)"
|
||||||
|
cat > "$_DCONF_POSTSETUP" <<'PSEOF'
|
||||||
|
#!/bin/bash
|
||||||
|
ROOTFS="$1"
|
||||||
|
if [[ -x "$ROOTFS/usr/bin/dconf" ]] && [[ -d "$ROOTFS/etc/dconf/db/local.d" ]]; then
|
||||||
|
chroot "$ROOTFS" dconf compile /etc/dconf/db/local /etc/dconf/db/local.d \
|
||||||
|
&& echo "postsetup: system-db compiled ($(chroot "$ROOTFS" dconf --version 2>/dev/null))" \
|
||||||
|
|| echo "postsetup: system-db compile failed (non-fatal)"
|
||||||
|
mkdir -p "$ROOTFS/etc/skel/.config/dconf"
|
||||||
|
chroot "$ROOTFS" dconf compile /etc/skel/.config/dconf/user /etc/dconf/db/local.d \
|
||||||
|
&& echo "postsetup: skel user dconf db compiled" \
|
||||||
|
|| echo "postsetup: skel user dconf db compile failed (non-fatal)"
|
||||||
|
else
|
||||||
|
echo "postsetup: dconf or keyfile dir not found in rootfs - skipping dconf compile"
|
||||||
|
fi
|
||||||
|
PSEOF
|
||||||
|
chmod +x "$_DCONF_POSTSETUP"
|
||||||
|
|
||||||
|
cd "$MKLIVE_DIR"
|
||||||
|
|
||||||
|
# ── Pre-bake nix packages ────────────────────────────────────────────────
|
||||||
|
# Shared with the Cinnamon build — same cache dir, same store.
|
||||||
|
if [[ -n "${NIX_PACKAGES_PREBAKE:-}" ]]; then
|
||||||
|
echo ">>> pre-baking nix packages"
|
||||||
|
read -r -a _NIX_PKGS <<< "$NIX_PACKAGES_PREBAKE"
|
||||||
|
|
||||||
|
_NIX_CACHE="$CACHE_DIR/nix-prebake"
|
||||||
|
_CACHE_KEY="$_NIX_CACHE/.done.$(printf '%s\n' "${_NIX_PKGS[@]}" | sort | md5sum | cut -c1-8)"
|
||||||
|
|
||||||
|
mkdir -p "$_NIX_CACHE"
|
||||||
|
|
||||||
|
if [[ -f "$_CACHE_KEY" ]] && [[ -d "$_NIX_CACHE/store" ]] && [[ -f "$_NIX_CACHE/.profile-path" ]]; then
|
||||||
|
echo " restoring cached nix store ($(du -sh "$_NIX_CACHE/store" 2>/dev/null | cut -f1))"
|
||||||
|
mkdir -p /nix
|
||||||
|
rsync -a "$_NIX_CACHE/" /nix/ 2>&1 | tail -1
|
||||||
|
else
|
||||||
|
echo " installing nix (single-user, no-daemon)..."
|
||||||
|
rm -rf /nix ~/.nix-profile ~/.nix-defexpr ~/.nix-channels
|
||||||
|
mkdir -m 0755 -p /nix
|
||||||
|
export NIX_CONFIG="build-users-group = "
|
||||||
|
curl -fsSL https://nixos.org/nix/install | \
|
||||||
|
NIX_INSTALLER_TRUST_INSTALLER=1 sh -s -- --no-daemon --no-channel-add
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
. /root/.nix-profile/etc/profile.d/nix.sh 2>/dev/null || true
|
||||||
|
export PATH="/root/.nix-profile/bin:/nix/var/nix/profiles/default/bin:$PATH"
|
||||||
|
|
||||||
|
export NIXPKGS_ALLOW_UNFREE=1
|
||||||
|
echo " nix profile install: ${_NIX_PKGS[*]}"
|
||||||
|
nix profile add --extra-experimental-features "nix-command flakes" \
|
||||||
|
--impure "${_NIX_PKGS[@]}" 2>&1
|
||||||
|
|
||||||
|
readlink -f /root/.nix-profile > "$_NIX_CACHE/.profile-path"
|
||||||
|
rsync -a /nix/ "$_NIX_CACHE/" 2>&1 | tail -1
|
||||||
|
touch "$_CACHE_KEY"
|
||||||
|
echo " cached nix store: $(du -sh "$_NIX_CACHE/store" 2>/dev/null | cut -f1)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " staging /nix into overlay ($(du -sh /nix/store 2>/dev/null | cut -f1))"
|
||||||
|
mkdir -p "$INCLUDE_DIR/nix"
|
||||||
|
rsync -a /nix/ "$INCLUDE_DIR/nix/" 2>&1 | tail -1
|
||||||
|
# Single-user nix: the live user (uid 1000) must own the store to create lock files and new paths.
|
||||||
|
chown -R 1000:1000 "$INCLUDE_DIR/nix"
|
||||||
|
|
||||||
|
_STORE_PROFILE=$(cat "$_NIX_CACHE/.profile-path" 2>/dev/null \
|
||||||
|
|| readlink -f /root/.nix-profile 2>/dev/null || echo "")
|
||||||
|
if [[ -n "$_STORE_PROFILE" && -d "$_STORE_PROFILE" ]]; then
|
||||||
|
mkdir -p "$INCLUDE_DIR/etc/skel"
|
||||||
|
ln -sf "$_STORE_PROFILE" "$INCLUDE_DIR/etc/skel/.nix-profile"
|
||||||
|
echo " skel/.nix-profile → $_STORE_PROFILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# ── end nix prebake ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# ── Noctalia: build a locally SIGNED XBPS repo ───────────────────────────
|
||||||
|
# noctalia-qs has a broken .sig2 on the CDN (RSA signature not valid).
|
||||||
|
# noctalia-shell's CDN key import also fails intermittently (EAGAIN).
|
||||||
|
# Solution: download both .xbps archives directly (no sig check), create a
|
||||||
|
# LOCAL SIGNED repo with a fresh keypair, register our public key in
|
||||||
|
# mklive/keys/ so copy_void_keys pre-trusts it in the rootfs.
|
||||||
|
# Our local signed repo gets HIGHEST priority (-r last = prepended first),
|
||||||
|
# so xbps resolves and verifies both packages against our trusted key.
|
||||||
|
echo ">>> building local signed noctalia XBPS repo (CDN .sig2 workaround)"
|
||||||
|
_NOC_LOCAL="/tmp/noctalia-local"
|
||||||
|
_NOC_HOME="/tmp/noc-sign-home"
|
||||||
|
_ARCH="${ARCH:-x86_64}"
|
||||||
|
mkdir -p "$_NOC_LOCAL" "$_NOC_HOME"
|
||||||
|
export HOME="$_NOC_HOME"
|
||||||
|
|
||||||
|
# Discover exact package versions from CDN repodata (try multiple User-Agents).
|
||||||
|
# Falls back to versions confirmed by previous build errors.
|
||||||
|
_NOC_VERS=$(python3 - <<'PYEOF' 2>/dev/null
|
||||||
|
import urllib.request, plistlib, tarfile, io, sys, os
|
||||||
|
repo = os.environ.get("NOCTALIA_REPO", "https://universalrepo.r1xelelo.workers.dev/void")
|
||||||
|
arch = os.environ.get("ARCH", "x86_64")
|
||||||
|
want = {"noctalia-qs", "noctalia-shell"}
|
||||||
|
found = {}
|
||||||
|
for ua in ("curl/8.0", "xbps/0.59.2", "Mozilla/5.0 (X11; Linux x86_64)"):
|
||||||
|
try:
|
||||||
|
req = urllib.request.Request(f"{repo}/{arch}-repodata", headers={"User-Agent": ua})
|
||||||
|
data = urllib.request.urlopen(req, timeout=15).read()
|
||||||
|
tf = tarfile.open(fileobj=io.BytesIO(data))
|
||||||
|
idx = plistlib.loads(tf.extractfile("index.plist").read())
|
||||||
|
# index.plist keys are package names; pkgver field holds the versioned name
|
||||||
|
for pkgname, meta in idx.items():
|
||||||
|
if isinstance(meta, dict) and pkgname in want:
|
||||||
|
found[pkgname] = meta.get("pkgver", pkgname)
|
||||||
|
if len(found) >= len(want):
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
# Fallback to versions confirmed by last build errors
|
||||||
|
defaults = {"noctalia-qs": "noctalia-qs-0.0.12_0", "noctalia-shell": "noctalia-shell-4.7.6_1"}
|
||||||
|
for pkg, ver in defaults.items():
|
||||||
|
if pkg not in found:
|
||||||
|
found[pkg] = ver
|
||||||
|
for ver in found.values():
|
||||||
|
print(ver)
|
||||||
|
PYEOF
|
||||||
|
)
|
||||||
|
|
||||||
|
# Download both .xbps archives directly (curl never checks .sig2)
|
||||||
|
for _ver in $_NOC_VERS; do
|
||||||
|
_fname="${_ver}.${_ARCH}.xbps"
|
||||||
|
# Clear any cached bad sig2 from a previous failed build
|
||||||
|
rm -f "$CACHE_DIR/xbps-niri-pkgs/${_ver}"* 2>/dev/null || true
|
||||||
|
if [[ ! -f "$_NOC_LOCAL/$_fname" ]]; then
|
||||||
|
echo " downloading $_fname ..."
|
||||||
|
curl -fsSL "$NOCTALIA_REPO/$_fname" -o "$_NOC_LOCAL/$_fname" \
|
||||||
|
|| { echo " WARNING: failed to download $_fname"; rm -f "$_NOC_LOCAL/$_fname"; }
|
||||||
|
else
|
||||||
|
echo " cached: $_fname"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Build index
|
||||||
|
xbps-rindex.static -a "$_NOC_LOCAL"/*.xbps
|
||||||
|
|
||||||
|
# Generate RSA keypair. xbps-rindex requires --privkey passed explicitly.
|
||||||
|
mkdir -p "$_NOC_HOME/.xbps-sign"
|
||||||
|
openssl genrsa -out "$_NOC_HOME/.xbps-sign/privkey.pem" 4096 2>/dev/null
|
||||||
|
[[ -s "$_NOC_HOME/.xbps-sign/privkey.pem" ]] \
|
||||||
|
|| { echo "ERROR: openssl genrsa failed"; exit 1; }
|
||||||
|
|
||||||
|
_NOC_PRIVKEY="$_NOC_HOME/.xbps-sign/privkey.pem"
|
||||||
|
|
||||||
|
# Sign repodata then each package (separate calls — xbps-rindex restriction).
|
||||||
|
xbps-rindex.static --sign --privkey "$_NOC_PRIVKEY" \
|
||||||
|
--signedby "noctalia-local" "$_NOC_LOCAL"
|
||||||
|
for _pkg in "$_NOC_LOCAL"/*.xbps; do
|
||||||
|
xbps-rindex.static --sign-pkg --privkey "$_NOC_PRIVKEY" \
|
||||||
|
--signedby "noctalia-local" "$_pkg"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Register public key in mklive/keys/ so copy_void_keys installs it in the rootfs.
|
||||||
|
# xbps fingerprint = MD5 of DER-encoded public key, formatted as aa:bb:cc:...
|
||||||
|
openssl rsa -in "$_NOC_PRIVKEY" \
|
||||||
|
-pubout -outform DER -out "$_NOC_HOME/pubkey.der" 2>/dev/null
|
||||||
|
_FINGERPRINT=$(md5sum "$_NOC_HOME/pubkey.der" \
|
||||||
|
| cut -d' ' -f1 | sed 's/../&:/g; s/:$//')
|
||||||
|
# The plist <data> field = base64 of the PEM public key (headers included)
|
||||||
|
_PUBKEY_B64=$(openssl rsa -in "$_NOC_PRIVKEY" \
|
||||||
|
-pubout 2>/dev/null | base64 -w 0)
|
||||||
|
cat > "$MKLIVE_DIR/keys/$_FINGERPRINT.plist" <<KEOF
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>public-key</key>
|
||||||
|
<data>$_PUBKEY_B64</data>
|
||||||
|
<key>public-key-size</key>
|
||||||
|
<integer>4096</integer>
|
||||||
|
<key>signature-by</key>
|
||||||
|
<string>noctalia-local</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
KEOF
|
||||||
|
echo " local signed noctalia repo ready — key: $_FINGERPRINT"
|
||||||
|
unset HOME
|
||||||
|
# ── end noctalia local repo ───────────────────────────────────────────────
|
||||||
|
|
||||||
|
_cleanup_mklive_builds() {
|
||||||
|
local d sub
|
||||||
|
for d in "$MKLIVE_DIR"/mklive-build.*/; do
|
||||||
|
[[ -d "$d" ]] || continue
|
||||||
|
for sub in tmp-rootfs/sys tmp-rootfs/proc tmp-rootfs/dev tmp-rootfs/run \
|
||||||
|
image/rootfs/sys image/rootfs/proc image/rootfs/dev image/rootfs/run; do
|
||||||
|
[[ -d "$d$sub" ]] && umount -R --lazy "$d$sub" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
rm -rf "$d" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
}
|
||||||
|
trap _cleanup_mklive_builds EXIT
|
||||||
|
|
||||||
|
# mklive prepends -r args: LAST -r = HIGHEST priority.
|
||||||
|
# Our local signed repo is last so xbps resolves noctalia-* from it.
|
||||||
|
# -v linux-mainline: makes mainline (kernel 7) the PRIMARY boot kernel;
|
||||||
|
# mklive.sh sets KERNELVERSION from it and ignores the linux metapackage.
|
||||||
|
# The plain 'linux' (kernel 6) in ISO_PKGS still gets installed and the
|
||||||
|
# secondary-kernel loop in mklive.sh builds its initramfs + boot entry.
|
||||||
|
./mklive.sh \
|
||||||
|
-a "$ARCH" \
|
||||||
|
-r "$REPO_URL" \
|
||||||
|
-r "${REPO_URL%/current}/current/nonfree" \
|
||||||
|
-r "$NOCTALIA_REPO" \
|
||||||
|
-r "$_NOC_LOCAL" \
|
||||||
|
-c "$CACHE_DIR/xbps-niri-pkgs" \
|
||||||
|
-H "$CACHE_DIR/xbps-host-pkgs" \
|
||||||
|
-k "$KEYMAP" \
|
||||||
|
-l "$LOCALE" \
|
||||||
|
-T "$ISO_TITLE" \
|
||||||
|
-v linux-mainline \
|
||||||
|
-p "$ISO_PKGS" \
|
||||||
|
-I "$INCLUDE_DIR" \
|
||||||
|
-x "$_DCONF_POSTSETUP" \
|
||||||
|
-x "$PROJECT_DIR/iso/postsetup-nvidia.sh" \
|
||||||
|
-C "${BOOT_CMDLINE:-}" \
|
||||||
|
-o "$OUT_ISO"
|
||||||
|
|
||||||
|
# Fix ownership so the host user can clean up without sudo.
|
||||||
|
# u+rwX: sets read+write on all, execute only on directories (capital X).
|
||||||
|
chmod -R u+rwX "$INCLUDE_DIR" 2>/dev/null || true
|
||||||
|
chown -R "${HOST_UID:-1000}:${HOST_GID:-1000}" "$INCLUDE_DIR" 2>/dev/null || true
|
||||||
|
chown -R "${HOST_UID:-1000}:${HOST_GID:-1000}" "$OUT_ISO" "${OUT_ISO}".* 2>/dev/null || true
|
||||||
307
iso/_inner-build-unified.sh
Executable file
307
iso/_inner-build-unified.sh
Executable file
@@ -0,0 +1,307 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Unified inner-build script — runs INSIDE the docker container (as root).
|
||||||
|
# Invoked by iso/build.sh via 'docker run'.
|
||||||
|
#
|
||||||
|
# Replaces: _inner-build.sh, _inner-build-live.sh, _inner-build-niri-live.sh
|
||||||
|
#
|
||||||
|
# Required env:
|
||||||
|
# ARCH REPO_URL KEYMAP LOCALE ISO_PKGS ISO_TITLE OUT_ISO_REL INCLUDE_DIR_REL
|
||||||
|
# BUILD_TYPE — installer | live
|
||||||
|
# DESKTOP — cinnamon | niri
|
||||||
|
# KERNEL_PKG — linux | linux-mainline
|
||||||
|
#
|
||||||
|
# Optional env:
|
||||||
|
# NOCTALIA_REPO — CDN URL for noctalia-shell/noctalia-qs (niri only)
|
||||||
|
# NIX_PACKAGES_PREBAKE — space-separated nix package attrs (live only)
|
||||||
|
# BOOT_CMDLINE — extra kernel command-line
|
||||||
|
# HOST_UID / HOST_GID — fix output ownership for host user (default 1000)
|
||||||
|
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
# ── validate required env ─────────────────────────────────────────────────
|
||||||
|
: "${ARCH:?}"; : "${REPO_URL:?}"; : "${KEYMAP:?}"; : "${LOCALE:?}"
|
||||||
|
: "${ISO_PKGS:?}"; : "${ISO_TITLE:?}";
|
||||||
|
: "${OUT_ISO_REL:?}"; : "${INCLUDE_DIR_REL:?}"
|
||||||
|
: "${BUILD_TYPE:?}"; : "${DESKTOP:?}"; : "${KERNEL_PKG:?}"
|
||||||
|
|
||||||
|
# ── paths ─────────────────────────────────────────────────────────────────
|
||||||
|
CACHE_DIR=/cache
|
||||||
|
PROJECT_DIR=/work
|
||||||
|
INCLUDE_DIR="$PROJECT_DIR/$INCLUDE_DIR_REL"
|
||||||
|
OUT_ISO="$PROJECT_DIR/$OUT_ISO_REL"
|
||||||
|
|
||||||
|
# Niri profiles use a separate mklive clone to avoid races on parallel builds.
|
||||||
|
case "$DESKTOP" in
|
||||||
|
niri) MKLIVE_DIR="$CACHE_DIR/void-mklive-niri" ;;
|
||||||
|
*) MKLIVE_DIR="$CACHE_DIR/void-mklive" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# xbps package cache dir (per-desktop, same reason as above)
|
||||||
|
case "$DESKTOP" in
|
||||||
|
niri) XBPS_CACHE="$CACHE_DIR/xbps-niri-pkgs" ;;
|
||||||
|
*) XBPS_CACHE="$CACHE_DIR/xbps-live-pkgs" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
export PATH="$CACHE_DIR/xbps-static/usr/bin:$PATH"
|
||||||
|
|
||||||
|
# ── sanity checks ─────────────────────────────────────────────────────────
|
||||||
|
[[ -d "$MKLIVE_DIR" ]] || { echo "ERROR: $MKLIVE_DIR missing (should have been cloned on host)"; exit 1; }
|
||||||
|
[[ -d "$INCLUDE_DIR" ]] || { echo "ERROR: $INCLUDE_DIR missing (staging failed on host)"; exit 1; }
|
||||||
|
command -v xbps-install.static >/dev/null \
|
||||||
|
|| { echo "ERROR: xbps-install.static not on PATH"; exit 1; }
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$OUT_ISO")" "$XBPS_CACHE"
|
||||||
|
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
# 1) NIX PREBAKE (live ISOs only)
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
if [[ "$BUILD_TYPE" == "live" && -n "${NIX_PACKAGES_PREBAKE:-}" ]]; then
|
||||||
|
echo ">>> pre-baking nix packages"
|
||||||
|
read -r -a _NIX_PKGS <<< "$NIX_PACKAGES_PREBAKE"
|
||||||
|
|
||||||
|
_NIX_CACHE="$CACHE_DIR/nix-prebake"
|
||||||
|
_CACHE_KEY="$_NIX_CACHE/.done.$(printf '%s\n' "${_NIX_PKGS[@]}" | sort | md5sum | cut -c1-8)"
|
||||||
|
|
||||||
|
mkdir -p "$_NIX_CACHE"
|
||||||
|
|
||||||
|
if [[ -f "$_CACHE_KEY" && -d "$_NIX_CACHE/store" && -f "$_NIX_CACHE/.profile-path" ]]; then
|
||||||
|
echo " restoring cached nix store ($(du -sh "$_NIX_CACHE/store" 2>/dev/null | cut -f1))"
|
||||||
|
mkdir -p /nix
|
||||||
|
rsync -a "$_NIX_CACHE/" /nix/ 2>&1 | tail -1
|
||||||
|
else
|
||||||
|
echo " installing nix (single-user, no-daemon) ..."
|
||||||
|
rm -rf /nix ~/.nix-profile ~/.nix-defexpr ~/.nix-channels
|
||||||
|
mkdir -m 0755 -p /nix
|
||||||
|
export NIX_CONFIG="build-users-group = "
|
||||||
|
curl -fsSL https://nixos.org/nix/install | \
|
||||||
|
NIX_INSTALLER_TRUST_INSTALLER=1 sh -s -- --no-daemon --no-channel-add
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
. /root/.nix-profile/etc/profile.d/nix.sh 2>/dev/null || true
|
||||||
|
export PATH="/root/.nix-profile/bin:/nix/var/nix/profiles/default/bin:$PATH"
|
||||||
|
|
||||||
|
export NIXPKGS_ALLOW_UNFREE=1
|
||||||
|
echo " nix profile install: ${_NIX_PKGS[*]}"
|
||||||
|
nix profile add --extra-experimental-features "nix-command flakes" \
|
||||||
|
--impure "${_NIX_PKGS[@]}" 2>&1
|
||||||
|
|
||||||
|
readlink -f /root/.nix-profile > "$_NIX_CACHE/.profile-path"
|
||||||
|
rsync -a /nix/ "$_NIX_CACHE/" 2>&1 | tail -1
|
||||||
|
touch "$_CACHE_KEY"
|
||||||
|
echo " cached nix store: $(du -sh "$_NIX_CACHE/store" 2>/dev/null | cut -f1)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " staging /nix into overlay ($(du -sh /nix/store 2>/dev/null | cut -f1))"
|
||||||
|
mkdir -p "$INCLUDE_DIR/nix"
|
||||||
|
rsync -a /nix/ "$INCLUDE_DIR/nix/" 2>&1 | tail -1
|
||||||
|
# Single-user nix: live user (uid 1000) owns the store.
|
||||||
|
chown -R 1000:1000 "$INCLUDE_DIR/nix"
|
||||||
|
|
||||||
|
_STORE_PROFILE=$(cat "$_NIX_CACHE/.profile-path" 2>/dev/null \
|
||||||
|
|| readlink -f /root/.nix-profile 2>/dev/null || echo "")
|
||||||
|
if [[ -n "$_STORE_PROFILE" && -d "$_STORE_PROFILE" ]]; then
|
||||||
|
mkdir -p "$INCLUDE_DIR/etc/skel"
|
||||||
|
ln -sf "$_STORE_PROFILE" "$INCLUDE_DIR/etc/skel/.nix-profile"
|
||||||
|
echo " skel/.nix-profile → $_STORE_PROFILE"
|
||||||
|
else
|
||||||
|
echo " WARNING: could not determine nix store profile path"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
# 2) NOCTALIA LOCAL SIGNED REPO (niri profiles only)
|
||||||
|
#
|
||||||
|
# noctalia-qs has a broken .sig2 on the CDN; noctalia-shell's CDN key import
|
||||||
|
# also fails intermittently (EAGAIN). Workaround: download both .xbps archives
|
||||||
|
# directly (curl skips sig checks), create a LOCAL SIGNED repo with a fresh RSA
|
||||||
|
# keypair, and register the public key in mklive/keys/ so copy_void_keys
|
||||||
|
# pre-trusts it in the rootfs. Our local repo is passed last to mklive.sh
|
||||||
|
# (-r last = HIGHEST priority) so xbps resolves and verifies both packages
|
||||||
|
# against our trusted key.
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
_NOC_LOCAL=""
|
||||||
|
if [[ "$DESKTOP" == "niri" && -n "${NOCTALIA_REPO:-}" ]]; then
|
||||||
|
echo ">>> building local signed noctalia XBPS repo (CDN .sig2 workaround)"
|
||||||
|
_NOC_LOCAL="/tmp/noctalia-local"
|
||||||
|
_NOC_HOME="/tmp/noc-sign-home"
|
||||||
|
mkdir -p "$_NOC_LOCAL" "$_NOC_HOME"
|
||||||
|
export HOME="$_NOC_HOME"
|
||||||
|
|
||||||
|
# Discover exact package versions from CDN repodata
|
||||||
|
_NOC_VERS=$(python3 - <<'PYEOF' 2>/dev/null
|
||||||
|
import urllib.request, plistlib, tarfile, io, os
|
||||||
|
repo = os.environ.get("NOCTALIA_REPO", "https://universalrepo.r1xelelo.workers.dev/void")
|
||||||
|
arch = os.environ.get("ARCH", "x86_64")
|
||||||
|
want = {"noctalia-qs", "noctalia-shell"}
|
||||||
|
found = {}
|
||||||
|
for ua in ("curl/8.0", "xbps/0.59.2", "Mozilla/5.0 (X11; Linux x86_64)"):
|
||||||
|
try:
|
||||||
|
req = urllib.request.Request(f"{repo}/{arch}-repodata", headers={"User-Agent": ua})
|
||||||
|
data = urllib.request.urlopen(req, timeout=15).read()
|
||||||
|
tf = tarfile.open(fileobj=io.BytesIO(data))
|
||||||
|
idx = plistlib.loads(tf.extractfile("index.plist").read())
|
||||||
|
for pkgname, meta in idx.items():
|
||||||
|
if isinstance(meta, dict) and pkgname in want:
|
||||||
|
found[pkgname] = meta.get("pkgver", pkgname)
|
||||||
|
if len(found) >= len(want):
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
# Fallback to versions confirmed by previous builds
|
||||||
|
defaults = {"noctalia-qs": "noctalia-qs-0.0.12_0", "noctalia-shell": "noctalia-shell-4.7.6_1"}
|
||||||
|
for pkg, ver in defaults.items():
|
||||||
|
if pkg not in found:
|
||||||
|
found[pkg] = ver
|
||||||
|
for ver in found.values():
|
||||||
|
print(ver)
|
||||||
|
PYEOF
|
||||||
|
)
|
||||||
|
|
||||||
|
for _ver in $_NOC_VERS; do
|
||||||
|
_fname="${_ver}.${ARCH}.xbps"
|
||||||
|
# Clear any cached bad sig2 from a previous failed build
|
||||||
|
rm -f "$CACHE_DIR/xbps-niri-pkgs/${_ver}"* 2>/dev/null || true
|
||||||
|
if [[ ! -f "$_NOC_LOCAL/$_fname" ]]; then
|
||||||
|
echo " downloading $_fname ..."
|
||||||
|
curl -fsSL "$NOCTALIA_REPO/$_fname" -o "$_NOC_LOCAL/$_fname" \
|
||||||
|
|| { echo " WARNING: failed to download $_fname"; rm -f "$_NOC_LOCAL/$_fname"; }
|
||||||
|
else
|
||||||
|
echo " cached: $_fname"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
xbps-rindex.static -a "$_NOC_LOCAL"/*.xbps
|
||||||
|
|
||||||
|
mkdir -p "$_NOC_HOME/.xbps-sign"
|
||||||
|
openssl genrsa -out "$_NOC_HOME/.xbps-sign/privkey.pem" 4096 2>/dev/null
|
||||||
|
[[ -s "$_NOC_HOME/.xbps-sign/privkey.pem" ]] \
|
||||||
|
|| { echo "ERROR: openssl genrsa failed"; exit 1; }
|
||||||
|
|
||||||
|
_NOC_PRIVKEY="$_NOC_HOME/.xbps-sign/privkey.pem"
|
||||||
|
|
||||||
|
xbps-rindex.static --sign --privkey "$_NOC_PRIVKEY" \
|
||||||
|
--signedby "noctalia-local" "$_NOC_LOCAL"
|
||||||
|
for _pkg in "$_NOC_LOCAL"/*.xbps; do
|
||||||
|
xbps-rindex.static --sign-pkg --privkey "$_NOC_PRIVKEY" \
|
||||||
|
--signedby "noctalia-local" "$_pkg"
|
||||||
|
done
|
||||||
|
|
||||||
|
openssl rsa -in "$_NOC_PRIVKEY" \
|
||||||
|
-pubout -outform DER -out "$_NOC_HOME/pubkey.der" 2>/dev/null
|
||||||
|
_FINGERPRINT=$(md5sum "$_NOC_HOME/pubkey.der" \
|
||||||
|
| cut -d' ' -f1 | sed 's/../&:/g; s/:$//')
|
||||||
|
_PUBKEY_B64=$(openssl rsa -in "$_NOC_PRIVKEY" \
|
||||||
|
-pubout 2>/dev/null | base64 -w 0)
|
||||||
|
cat > "$MKLIVE_DIR/keys/$_FINGERPRINT.plist" <<KEOF
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>public-key</key>
|
||||||
|
<data>$_PUBKEY_B64</data>
|
||||||
|
<key>public-key-size</key>
|
||||||
|
<integer>4096</integer>
|
||||||
|
<key>signature-by</key>
|
||||||
|
<string>noctalia-local</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
KEOF
|
||||||
|
echo " local signed noctalia repo ready — key: $_FINGERPRINT"
|
||||||
|
unset HOME
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
# 3) DCONF POSTSETUP SCRIPT (live ISOs only — both cinnamon and niri)
|
||||||
|
#
|
||||||
|
# Compile system-db AND the skel user dconf db using Void's own binary inside
|
||||||
|
# the mklive rootfs chroot. No cross-distro format mismatch possible.
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
_DCONF_POSTSETUP=""
|
||||||
|
if [[ "$BUILD_TYPE" == "live" ]]; then
|
||||||
|
_DCONF_POSTSETUP="$(mktemp -p "$MKLIVE_DIR" postsetup-dconf.XXXXX.sh)"
|
||||||
|
cat > "$_DCONF_POSTSETUP" <<'PSEOF'
|
||||||
|
#!/bin/bash
|
||||||
|
ROOTFS="$1"
|
||||||
|
if [[ -x "$ROOTFS/usr/bin/dconf" ]] && [[ -d "$ROOTFS/etc/dconf/db/local.d" ]]; then
|
||||||
|
chroot "$ROOTFS" dconf compile /etc/dconf/db/local /etc/dconf/db/local.d \
|
||||||
|
&& echo "postsetup-dconf: system-db compiled ($(chroot "$ROOTFS" dconf --version 2>/dev/null))" \
|
||||||
|
|| echo "postsetup-dconf: system-db compile failed (non-fatal)"
|
||||||
|
mkdir -p "$ROOTFS/etc/skel/.config/dconf"
|
||||||
|
chroot "$ROOTFS" dconf compile /etc/skel/.config/dconf/user /etc/dconf/db/local.d \
|
||||||
|
&& echo "postsetup-dconf: skel user dconf db compiled" \
|
||||||
|
|| echo "postsetup-dconf: skel user dconf db compile failed (non-fatal)"
|
||||||
|
else
|
||||||
|
echo "postsetup-dconf: dconf or keyfile dir not found in rootfs — skipping"
|
||||||
|
fi
|
||||||
|
PSEOF
|
||||||
|
chmod +x "$_DCONF_POSTSETUP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
# 4) CLEANUP TRAP
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
cd "$MKLIVE_DIR"
|
||||||
|
|
||||||
|
_cleanup_mklive_builds() {
|
||||||
|
local d sub
|
||||||
|
for d in "$MKLIVE_DIR"/mklive-build.*/; do
|
||||||
|
[[ -d "$d" ]] || continue
|
||||||
|
for sub in tmp-rootfs/sys tmp-rootfs/proc tmp-rootfs/dev tmp-rootfs/run \
|
||||||
|
image/rootfs/sys image/rootfs/proc image/rootfs/dev image/rootfs/run; do
|
||||||
|
[[ -d "$d$sub" ]] && umount -R --lazy "$d$sub" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
rm -rf "$d" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
}
|
||||||
|
trap _cleanup_mklive_builds EXIT
|
||||||
|
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
# 5) BUILD MKLIVE ARGS
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
_MKLIVE_ARGS=(
|
||||||
|
-a "$ARCH"
|
||||||
|
-r "$REPO_URL"
|
||||||
|
-r "${REPO_URL%/current}/current/nonfree"
|
||||||
|
-c "$XBPS_CACHE"
|
||||||
|
-H "$CACHE_DIR/xbps-host-pkgs"
|
||||||
|
-k "$KEYMAP"
|
||||||
|
-l "$LOCALE"
|
||||||
|
-T "$ISO_TITLE"
|
||||||
|
-p "$ISO_PKGS"
|
||||||
|
-I "$INCLUDE_DIR"
|
||||||
|
-C "${BOOT_CMDLINE:-}"
|
||||||
|
-o "$OUT_ISO"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Mainline kernel: pass as primary kernel so mklive builds the right initramfs.
|
||||||
|
# On dual-kernel ISOs the patched mklive loop also builds an entry for 'linux'.
|
||||||
|
[[ "$KERNEL_PKG" == "linux-mainline" ]] && _MKLIVE_ARGS+=( -v linux-mainline )
|
||||||
|
|
||||||
|
# Noctalia repos (niri only).
|
||||||
|
# Order matters: LAST -r = HIGHEST priority.
|
||||||
|
# We add CDN first, then our locally-signed repo so xbps resolves noctalia-*
|
||||||
|
# from the trusted local copy.
|
||||||
|
if [[ "$DESKTOP" == "niri" && -n "${NOCTALIA_REPO:-}" ]]; then
|
||||||
|
_MKLIVE_ARGS+=( -r "$NOCTALIA_REPO" )
|
||||||
|
[[ -n "$_NOC_LOCAL" ]] && _MKLIVE_ARGS+=( -r "$_NOC_LOCAL" )
|
||||||
|
fi
|
||||||
|
|
||||||
|
# NVIDIA postsetup (all builds)
|
||||||
|
_MKLIVE_ARGS+=( -x "$PROJECT_DIR/iso/postsetup-nvidia.sh" )
|
||||||
|
|
||||||
|
# dconf postsetup (live ISOs only)
|
||||||
|
[[ -n "$_DCONF_POSTSETUP" ]] && _MKLIVE_ARGS+=( -x "$_DCONF_POSTSETUP" )
|
||||||
|
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
# 6) RUN MKLIVE
|
||||||
|
# ═════════════════════════════════════════════════════════════════════════════
|
||||||
|
echo ">>> running mklive.sh"
|
||||||
|
echo " type : $BUILD_TYPE"
|
||||||
|
echo " desktop : $DESKTOP"
|
||||||
|
echo " kernel : $KERNEL_PKG"
|
||||||
|
echo " output : $OUT_ISO"
|
||||||
|
./mklive.sh "${_MKLIVE_ARGS[@]}"
|
||||||
|
|
||||||
|
# Fix ownership so the host user can clean up without sudo.
|
||||||
|
chmod -R u+rwX "$INCLUDE_DIR" 2>/dev/null || true
|
||||||
|
chown -R "${HOST_UID:-1000}:${HOST_GID:-1000}" "$INCLUDE_DIR" 2>/dev/null || true
|
||||||
|
chown -R "${HOST_UID:-1000}:${HOST_GID:-1000}" "$OUT_ISO" "${OUT_ISO}".* 2>/dev/null || true
|
||||||
@@ -47,6 +47,7 @@ trap _cleanup_mklive_builds EXIT
|
|||||||
./mklive.sh \
|
./mklive.sh \
|
||||||
-a "$ARCH" \
|
-a "$ARCH" \
|
||||||
-r "$REPO_URL" \
|
-r "$REPO_URL" \
|
||||||
|
-r "${REPO_URL%/current}/current/nonfree" \
|
||||||
-c "$CACHE_DIR/xbps-live-pkgs" \
|
-c "$CACHE_DIR/xbps-live-pkgs" \
|
||||||
-H "$CACHE_DIR/xbps-host-pkgs" \
|
-H "$CACHE_DIR/xbps-host-pkgs" \
|
||||||
-k "$KEYMAP" \
|
-k "$KEYMAP" \
|
||||||
@@ -54,6 +55,7 @@ trap _cleanup_mklive_builds EXIT
|
|||||||
-T "$ISO_TITLE" \
|
-T "$ISO_TITLE" \
|
||||||
-p "$ISO_PKGS" \
|
-p "$ISO_PKGS" \
|
||||||
-I "$INCLUDE_DIR" \
|
-I "$INCLUDE_DIR" \
|
||||||
|
-x "$PROJECT_DIR/iso/postsetup-nvidia.sh" \
|
||||||
-C "${BOOT_CMDLINE:-}" \
|
-C "${BOOT_CMDLINE:-}" \
|
||||||
-o "$OUT_ISO"
|
-o "$OUT_ISO"
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ fi
|
|||||||
|
|
||||||
# 3) build includes overlay
|
# 3) build includes overlay
|
||||||
echo ">>> staging live includes overlay at $INCLUDE_DIR"
|
echo ">>> staging live includes overlay at $INCLUDE_DIR"
|
||||||
|
# The nix store (staged by Docker/root) uses 444/555 permissions — chmod first.
|
||||||
|
chmod -R u+rwX "$INCLUDE_DIR" 2>/dev/null || true
|
||||||
rm -rf "$INCLUDE_DIR"
|
rm -rf "$INCLUDE_DIR"
|
||||||
mkdir -p "$INCLUDE_DIR"
|
mkdir -p "$INCLUDE_DIR"
|
||||||
|
|
||||||
@@ -88,7 +90,7 @@ LIVE_USER="${USERNAME:-live}"
|
|||||||
LIVE_USER="${USERNAME:-live}"
|
LIVE_USER="${USERNAME:-live}"
|
||||||
|
|
||||||
# Extra groups (dracut only adds audio,video,wheel)
|
# Extra groups (dracut only adds audio,video,wheel)
|
||||||
for g in plugdev input network docker; do
|
for g in plugdev input network docker bluetooth; do
|
||||||
groupadd -f "$g" 2>/dev/null || true
|
groupadd -f "$g" 2>/dev/null || true
|
||||||
usermod -aG "$g" "$LIVE_USER" 2>/dev/null || true
|
usermod -aG "$g" "$LIVE_USER" 2>/dev/null || true
|
||||||
done
|
done
|
||||||
@@ -105,6 +107,7 @@ if [ -x /usr/bin/nix ]; then
|
|||||||
install -d -m 0755 /etc/nix
|
install -d -m 0755 /etc/nix
|
||||||
cat > /etc/nix/nix.conf <<NIXCONF
|
cat > /etc/nix/nix.conf <<NIXCONF
|
||||||
experimental-features = nix-command flakes
|
experimental-features = nix-command flakes
|
||||||
|
build-users-group =
|
||||||
sandbox = false
|
sandbox = false
|
||||||
auto-optimise-store = true
|
auto-optimise-store = true
|
||||||
trusted-users = root $LIVE_USER
|
trusted-users = root $LIVE_USER
|
||||||
@@ -132,6 +135,17 @@ if [ -f /etc/nsswitch.conf ]; then
|
|||||||
echo "live-setup: removed mdns from nsswitch.conf (hosts line)"
|
echo "live-setup: removed mdns from nsswitch.conf (hosts line)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ── Timezone ──────────────────────────────────────────────────────────────
|
||||||
|
ln -sf /usr/share/zoneinfo/Europe/Zurich /etc/localtime 2>/dev/null || true
|
||||||
|
echo "live-setup: timezone set to Europe/Zurich"
|
||||||
|
|
||||||
|
# ── Fix sound device permissions ───────────────────────────────────────────
|
||||||
|
# PCM/control nodes may be root:root at early boot before the audio group
|
||||||
|
# exists. Re-apply correct ownership so PipeWire/ALSA can open the devices.
|
||||||
|
chown root:audio /dev/snd/pcmC* /dev/snd/controlC* /dev/snd/hwC* 2>/dev/null || true
|
||||||
|
chmod 660 /dev/snd/pcmC* /dev/snd/controlC* /dev/snd/hwC* 2>/dev/null || true
|
||||||
|
udevadm trigger --subsystem-match=sound 2>/dev/null || true
|
||||||
|
|
||||||
# ── DNS: ensure a working nameserver is configured ───────────────────────
|
# ── DNS: ensure a working nameserver is configured ───────────────────────
|
||||||
# NetworkManager will overwrite resolv.conf once DHCP completes.
|
# NetworkManager will overwrite resolv.conf once DHCP completes.
|
||||||
# If the DHCP-provided nameserver is broken (e.g. QEMU's 10.0.2.3), add
|
# If the DHCP-provided nameserver is broken (e.g. QEMU's 10.0.2.3), add
|
||||||
@@ -261,6 +275,16 @@ chmod 0755 "$INCLUDE_DIR/etc/runit/2"
|
|||||||
|
|
||||||
install -d -m 0755 "$INCLUDE_DIR/etc/runit/runsvdir/default"
|
install -d -m 0755 "$INCLUDE_DIR/etc/runit/runsvdir/default"
|
||||||
|
|
||||||
|
# Write all repos to xbps.d so they persist in the live squashfs.
|
||||||
|
# The nonfree repo is needed for nvidia and other proprietary drivers.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/xbps.d"
|
||||||
|
cat > "$INCLUDE_DIR/etc/xbps.d/00-void-repos.conf" <<EOF
|
||||||
|
repository=${REPO_URL:-https://repo-default.voidlinux.org/current}
|
||||||
|
repository=${REPO_URL%/current}/current/nonfree
|
||||||
|
repository=${REPO_URL%/current}/current/multilib
|
||||||
|
repository=${REPO_URL%/current}/current/multilib/nonfree
|
||||||
|
EOF
|
||||||
|
|
||||||
# ── 3b) LightDM autologin ───────────────────────────────────────────────
|
# ── 3b) LightDM autologin ───────────────────────────────────────────────
|
||||||
install -d -m 0755 "$INCLUDE_DIR/etc/lightdm"
|
install -d -m 0755 "$INCLUDE_DIR/etc/lightdm"
|
||||||
# .session file: read by the vmklive dracut hook (display-manager-autologin.sh)
|
# .session file: read by the vmklive dracut hook (display-manager-autologin.sh)
|
||||||
@@ -286,7 +310,7 @@ EOF
|
|||||||
|
|
||||||
install -d -m 0755 "$INCLUDE_DIR/etc/runit/runsvdir/default"
|
install -d -m 0755 "$INCLUDE_DIR/etc/runit/runsvdir/default"
|
||||||
# Enable services for the live session.
|
# Enable services for the live session.
|
||||||
for svc in dbus NetworkManager lightdm nix-daemon; do
|
for svc in dbus NetworkManager lightdm bluetoothd; do
|
||||||
ln -sf "/etc/sv/$svc" "$INCLUDE_DIR/etc/runit/runsvdir/default/$svc" 2>/dev/null || true
|
ln -sf "/etc/sv/$svc" "$INCLUDE_DIR/etc/runit/runsvdir/default/$svc" 2>/dev/null || true
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -408,7 +432,10 @@ picture-uri='file:///usr/share/backgrounds/void-installer/${WALLPAPER_FILE}'
|
|||||||
picture-options='zoom'
|
picture-options='zoom'
|
||||||
|
|
||||||
[org/gnome/desktop/input-sources]
|
[org/gnome/desktop/input-sources]
|
||||||
sources=[('xkb', 'ch+fr')]
|
sources=[('xkb', '${KEYMAP//-/+}')]
|
||||||
|
|
||||||
|
[org/gnome/desktop/interface]
|
||||||
|
color-scheme='prefer-dark'
|
||||||
|
|
||||||
[org/cinnamon/desktop/default-applications/terminal]
|
[org/cinnamon/desktop/default-applications/terminal]
|
||||||
exec='alacritty'
|
exec='alacritty'
|
||||||
@@ -530,8 +557,9 @@ gsettings set org.cinnamon.desktop.default-applications.terminal exec-arg '-e'
|
|||||||
gsettings set org.gnome.desktop.default-applications.terminal exec '${DEFAULT_TERMINAL:-alacritty}'
|
gsettings set org.gnome.desktop.default-applications.terminal exec '${DEFAULT_TERMINAL:-alacritty}'
|
||||||
gsettings set org.gnome.desktop.default-applications.terminal exec-arg '-e'
|
gsettings set org.gnome.desktop.default-applications.terminal exec-arg '-e'
|
||||||
|
|
||||||
# Keyboard layout (Swiss French)
|
# Keyboard layout — set explicitly via gsettings (belt-and-suspenders alongside
|
||||||
gsettings set org.gnome.desktop.input-sources sources "[('xkb', '${KEYMAP:-ch+fr_nodeadkeys}')]"
|
# the user dconf db pre-baked in /etc/skel at build time).
|
||||||
|
gsettings set org.gnome.desktop.input-sources sources "[('xkb', '${KEYMAP//-/+}')]"
|
||||||
|
|
||||||
touch "\$DONE"
|
touch "\$DONE"
|
||||||
EOF
|
EOF
|
||||||
@@ -554,6 +582,55 @@ cat > "$INCLUDE_DIR/etc/environment" <<'ENVEOF'
|
|||||||
XDG_DATA_DIRS=/home/live/.nix-profile/share:/usr/local/share:/usr/share
|
XDG_DATA_DIRS=/home/live/.nix-profile/share:/usr/local/share:/usr/share
|
||||||
ENVEOF
|
ENVEOF
|
||||||
|
|
||||||
|
# ── Timezone ──────────────────────────────────────────────────────────────
|
||||||
|
ln -sf /usr/share/zoneinfo/Europe/Zurich "$INCLUDE_DIR/etc/localtime"
|
||||||
|
cat > "$INCLUDE_DIR/etc/rc.conf" <<'RCEOF'
|
||||||
|
KEYMAP="ch"
|
||||||
|
HARDWARECLOCK="UTC"
|
||||||
|
TIMEZONE="Europe/Zurich"
|
||||||
|
RCEOF
|
||||||
|
|
||||||
|
# ── Sound device udev rules ──────────────────────────────────────────────
|
||||||
|
# PCM/control nodes are created root:root at early boot before the audio group
|
||||||
|
# is provisioned; this rule ensures correct ownership on every boot.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/udev/rules.d"
|
||||||
|
cat > "$INCLUDE_DIR/etc/udev/rules.d/70-sound-perms.rules" <<'EOF'
|
||||||
|
SUBSYSTEM=="sound", GROUP="audio", MODE="0660"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# ── NVIDIA PRIME overlay ────────────────────────────────────────────────
|
||||||
|
# Blacklist nouveau — the live-setup.sh PRIME detection block already writes
|
||||||
|
# Xorg config, but the kernel must also not load nouveau.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/modprobe.d"
|
||||||
|
cat > "$INCLUDE_DIR/etc/modprobe.d/blacklist-nouveau.conf" <<'EOF'
|
||||||
|
blacklist nouveau
|
||||||
|
options nouveau modeset=0
|
||||||
|
EOF
|
||||||
|
cat > "$INCLUDE_DIR/etc/modprobe.d/btusb-quirks.conf" <<'EOF'
|
||||||
|
options btusb enable_autosuspend=0
|
||||||
|
EOF
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/modules-load.d"
|
||||||
|
cat > "$INCLUDE_DIR/etc/modules-load.d/nvidia.conf" <<'EOF'
|
||||||
|
nvidia
|
||||||
|
nvidia_modeset
|
||||||
|
nvidia_uvm
|
||||||
|
nvidia_drm
|
||||||
|
EOF
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/dracut.conf.d"
|
||||||
|
cat > "$INCLUDE_DIR/etc/dracut.conf.d/10-nvidia.conf" <<'EOF'
|
||||||
|
add_drivers+=" nvidia nvidia_modeset nvidia_uvm nvidia_drm "
|
||||||
|
omit_drivers+=" nouveau "
|
||||||
|
EOF
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/usr/local/bin"
|
||||||
|
cat > "$INCLUDE_DIR/usr/local/bin/prime-run" <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
exec env __NV_PRIME_RENDER_OFFLOAD=1 \
|
||||||
|
__VK_LAYER_NV_optimus=NVIDIA_only \
|
||||||
|
__GLX_VENDOR_LIBRARY_NAME=nvidia \
|
||||||
|
"$@"
|
||||||
|
EOF
|
||||||
|
chmod 0755 "$INCLUDE_DIR/usr/local/bin/prime-run"
|
||||||
|
|
||||||
# /etc/profile.d: PATH for interactive terminals (alacritty, etc.)
|
# /etc/profile.d: PATH for interactive terminals (alacritty, etc.)
|
||||||
install -d -m 0755 "$INCLUDE_DIR/etc/profile.d"
|
install -d -m 0755 "$INCLUDE_DIR/etc/profile.d"
|
||||||
cat > "$INCLUDE_DIR/etc/profile.d/nix-prebaked.sh" <<'NIXEOF'
|
cat > "$INCLUDE_DIR/etc/profile.d/nix-prebaked.sh" <<'NIXEOF'
|
||||||
@@ -564,6 +641,13 @@ if [[ -d "${HOME:-}/.nix-profile/bin" ]]; then
|
|||||||
*) export PATH="$HOME/.nix-profile/bin:$PATH" ;;
|
*) export PATH="$HOME/.nix-profile/bin:$PATH" ;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
export NIXPKGS_ALLOW_UNFREE=1
|
||||||
|
# Pre-baked nix is single-user (no daemon) — bypass daemon connection attempt
|
||||||
|
export NIX_REMOTE=local
|
||||||
|
# Flake commands ignore NIXPKGS_ALLOW_UNFREE unless --impure is passed.
|
||||||
|
# Wrap nix so interactive installs work without extra flags.
|
||||||
|
nix() { command nix "$@" --impure; }
|
||||||
|
export -f nix
|
||||||
NIXEOF
|
NIXEOF
|
||||||
|
|
||||||
|
|
||||||
@@ -635,6 +719,29 @@ cat > "$INCLUDE_DIR/etc/profile.d/nix-packages-path.sh" <<'EOF'
|
|||||||
export NIX_PACKAGES_FILE=/usr/local/libexec/nix-packages.list
|
export NIX_PACKAGES_FILE=/usr/local/libexec/nix-packages.list
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
# nixpkgs config: allow unfree packages for all users
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/skel/.config/nixpkgs"
|
||||||
|
echo '{ allowUnfree = true; }' > "$INCLUDE_DIR/etc/skel/.config/nixpkgs/config.nix"
|
||||||
|
|
||||||
|
# git: GUI askpass so prompts work without a controlling terminal
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/usr/local/bin"
|
||||||
|
cat > "$INCLUDE_DIR/usr/local/bin/git-askpass" <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
for cmd in zenity qarma; do
|
||||||
|
command -v "$cmd" >/dev/null 2>&1 || continue
|
||||||
|
case "$1" in
|
||||||
|
*[Uu]sername*) exec "$cmd" --entry --title="Git Credentials" --text="$1" ;;
|
||||||
|
*) exec "$cmd" --password --title="Git Credentials" --text="$1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
printf '%s' "$1" >&2; read -r answer; printf '%s\n' "$answer"
|
||||||
|
EOF
|
||||||
|
chmod 0755 "$INCLUDE_DIR/usr/local/bin/git-askpass"
|
||||||
|
cat > "$INCLUDE_DIR/etc/gitconfig" <<'EOF'
|
||||||
|
[core]
|
||||||
|
askPass = /usr/local/bin/git-askpass
|
||||||
|
EOF
|
||||||
|
|
||||||
# ── 3g) Skel: .bash_profile sources .bashrc only (no first-login autorun) ──
|
# ── 3g) Skel: .bash_profile sources .bashrc only (no first-login autorun) ──
|
||||||
install -d -m 0755 "$INCLUDE_DIR/etc/skel"
|
install -d -m 0755 "$INCLUDE_DIR/etc/skel"
|
||||||
cat > "$INCLUDE_DIR/etc/skel/.bash_profile" <<'EOF'
|
cat > "$INCLUDE_DIR/etc/skel/.bash_profile" <<'EOF'
|
||||||
@@ -659,7 +766,7 @@ TS="$(date -u +%Y%m%d)"
|
|||||||
OUT_ISO="${OUTPUT_ISO:-$OUT_DIR/void-live-stable-${TS}.iso}"
|
OUT_ISO="${OUTPUT_ISO:-$OUT_DIR/void-live-stable-${TS}.iso}"
|
||||||
# live.user=live → vmklive dracut hook creates user 'live' (default would be 'anon')
|
# live.user=live → vmklive dracut hook creates user 'live' (default would be 'anon')
|
||||||
# console=ttyS0 → serial output for QEMU/real hardware debugging
|
# console=ttyS0 → serial output for QEMU/real hardware debugging
|
||||||
BOOT_CMDLINE="${BOOT_CMDLINE:-live.user=${LIVE_USER} console=tty0 console=ttyS0,115200}"
|
BOOT_CMDLINE="${BOOT_CMDLINE:-live.user=${LIVE_USER} console=tty0 console=ttyS0,115200 nvidia-drm.modeset=1 rd.driver.blacklist=nouveau modprobe.blacklist=nouveau btusb.enable_autosuspend=0}"
|
||||||
|
|
||||||
echo ">>> running mklive.sh inside docker — output: $OUT_ISO"
|
echo ">>> running mklive.sh inside docker — output: $OUT_ISO"
|
||||||
"$DOCKER" run --rm --privileged \
|
"$DOCKER" run --rm --privileged \
|
||||||
|
|||||||
895
iso/build-niri-live-iso.sh
Executable file
895
iso/build-niri-live-iso.sh
Executable file
@@ -0,0 +1,895 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Build a niri/Wayland LIVE desktop ISO (mainline-niri profile).
|
||||||
|
#
|
||||||
|
# Boots directly into a niri session with noctalia-shell as user 'live'
|
||||||
|
# (no password). agetty autologin on tty1 → .bash_profile → dbus-run-session niri.
|
||||||
|
# All themes, wallpapers, and the
|
||||||
|
# void-installer are pre-baked into the squashfs.
|
||||||
|
#
|
||||||
|
# Requires (host): bash, git, curl, docker, and Bibata-Modern-Ice cursor
|
||||||
|
# installed at /usr/share/icons/Bibata-Modern-Ice.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# iso/build-niri-live-iso.sh
|
||||||
|
# OUTPUT_ISO=/path/to/output.iso iso/build-niri-live-iso.sh
|
||||||
|
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
CACHE_DIR="${CACHE_DIR:-$PROJECT_DIR/cache}"
|
||||||
|
OUT_DIR="${OUT_DIR:-$PROJECT_DIR/out}"
|
||||||
|
BUILD_DIR="${BUILD_DIR:-$PROJECT_DIR/build}"
|
||||||
|
INCLUDE_DIR="$BUILD_DIR/niri-live-includes"
|
||||||
|
MKLIVE_DIR="$CACHE_DIR/void-mklive-niri" # separate clone — avoids race with Cinnamon parallel build
|
||||||
|
MKLIVE_REPO="${MKLIVE_REPO:-https://github.com/void-linux/void-mklive.git}"
|
||||||
|
MKLIVE_REF="${MKLIVE_REF:-master}"
|
||||||
|
PATCH_DIR="$PROJECT_DIR/iso/patches"
|
||||||
|
DOCKER_IMAGE="${DOCKER_IMAGE:-void-installer-builder:latest}"
|
||||||
|
DOCKER="${DOCKER:-docker}"
|
||||||
|
LIVE_USER="${LIVE_USER:-live}"
|
||||||
|
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source "$PROJECT_DIR/config/install.conf"
|
||||||
|
|
||||||
|
# Load niri profile settings (KERNEL_PKG, GTK_THEME, CURSOR_THEME, etc.)
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source "$PROJECT_DIR/config/profiles/mainline-niri/profile.conf"
|
||||||
|
|
||||||
|
command -v "$DOCKER" >/dev/null \
|
||||||
|
|| { echo "ERROR: '$DOCKER' not in PATH"; exit 1; }
|
||||||
|
"$DOCKER" info >/dev/null 2>&1 \
|
||||||
|
|| { echo "ERROR: '$DOCKER' daemon unreachable"; exit 1; }
|
||||||
|
|
||||||
|
mkdir -p "$CACHE_DIR" "$OUT_DIR" "$BUILD_DIR"
|
||||||
|
|
||||||
|
# 1) clone + patch mklive (shared with Cinnamon build)
|
||||||
|
if [[ ! -d "$MKLIVE_DIR/.git" ]]; then
|
||||||
|
echo ">>> cloning void-mklive"
|
||||||
|
git clone --depth=1 --branch "$MKLIVE_REF" "$MKLIVE_REPO" "$MKLIVE_DIR"
|
||||||
|
fi
|
||||||
|
if compgen -G "$PATCH_DIR/*.patch" >/dev/null; then
|
||||||
|
echo ">>> resetting + applying iso/patches/"
|
||||||
|
( cd "$MKLIVE_DIR" && git checkout -- . )
|
||||||
|
for p in "$PATCH_DIR"/*.patch; do
|
||||||
|
echo " $(basename "$p")"
|
||||||
|
( cd "$MKLIVE_DIR" && patch -p1 --silent < "$p" )
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2) xbps-static (shared cache)
|
||||||
|
XBPS_STATIC_DIR="$CACHE_DIR/xbps-static"
|
||||||
|
if [[ ! -x "$XBPS_STATIC_DIR/usr/bin/xbps-install.static" ]]; then
|
||||||
|
echo ">>> downloading xbps-static"
|
||||||
|
mkdir -p "$XBPS_STATIC_DIR"
|
||||||
|
curl -fsSL "https://repo-default.voidlinux.org/static/xbps-static-latest.x86_64-musl.tar.xz" \
|
||||||
|
| tar xJf - -C "$XBPS_STATIC_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3) build includes overlay (separate dir from Cinnamon build)
|
||||||
|
echo ">>> staging niri live includes overlay at $INCLUDE_DIR"
|
||||||
|
# The nix store (staged by Docker/root) uses 444/555 permissions — chmod first.
|
||||||
|
chmod -R u+rwX "$INCLUDE_DIR" 2>/dev/null || true
|
||||||
|
rm -rf "$INCLUDE_DIR"
|
||||||
|
mkdir -p "$INCLUDE_DIR"
|
||||||
|
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc"
|
||||||
|
|
||||||
|
# ── 3a) greetd config (fallback TUI on tty2) + agetty autologin on tty1 ─
|
||||||
|
# greetd's initial_session is not used: its PAM session setup fails silently
|
||||||
|
# in the live environment (pam_elogind ENOSYS, missing D-Bus session bus).
|
||||||
|
# Instead we autologin via agetty on tty1 and launch niri from .bash_profile.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/greetd"
|
||||||
|
cat > "$INCLUDE_DIR/etc/greetd/config.toml" <<'EOF'
|
||||||
|
[terminal]
|
||||||
|
vt = 2
|
||||||
|
|
||||||
|
[default_session]
|
||||||
|
command = "tuigreet --time --greeting 'Void Linux Live (niri)' --cmd niri-session"
|
||||||
|
user = "_greeter"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# agetty-tty1 autologin: override conf so agetty-tty1 (mklive's default sv)
|
||||||
|
# automatically logs in the live user on tty1 without racing with a custom sv.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/sv/agetty-tty1"
|
||||||
|
cat > "$INCLUDE_DIR/etc/sv/agetty-tty1/conf" <<EOF
|
||||||
|
if [ -x /sbin/agetty -o -x /bin/agetty ]; then
|
||||||
|
if [ "\${tty}" = "tty1" ]; then
|
||||||
|
GETTY_ARGS="--noclear --autologin ${LIVE_USER}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
BAUD_RATE=38400
|
||||||
|
TERM_NAME=linux
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# ── 3b) xbps repo configuration ─────────────────────────────────────────
|
||||||
|
# Write all repos into xbps.d so they are available in the live session
|
||||||
|
# (not just at build time). The nonfree repo is needed for nvidia et al.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/xbps.d"
|
||||||
|
cat > "$INCLUDE_DIR/etc/xbps.d/00-void-repos.conf" <<EOF
|
||||||
|
repository=${REPO_URL:-https://repo-default.voidlinux.org/current}
|
||||||
|
repository=${REPO_URL%/current}/current/nonfree
|
||||||
|
repository=${REPO_URL%/current}/current/multilib
|
||||||
|
repository=${REPO_URL%/current}/current/multilib/nonfree
|
||||||
|
EOF
|
||||||
|
cat > "$INCLUDE_DIR/etc/xbps.d/10-noctalia.conf" <<'EOF'
|
||||||
|
repository=https://universalrepo.r1xelelo.workers.dev/void
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# ── 3c) live-setup.sh (runs from runit/2 before any service starts) ────
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/runit"
|
||||||
|
cat > "$INCLUDE_DIR/etc/runit/live-setup.sh" <<'SV_EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
# Niri live session setup. Runs from /etc/runit/2 before services start.
|
||||||
|
|
||||||
|
LIVE_USER="${USERNAME:-live}"
|
||||||
|
[ -f /etc/default/live.conf ] && . /etc/default/live.conf
|
||||||
|
LIVE_USER="${LIVE_USER:-live}"
|
||||||
|
|
||||||
|
# Extra groups (dracut only adds audio,video,wheel)
|
||||||
|
for g in plugdev input network video audio _seatd bluetooth; do
|
||||||
|
groupadd -f "$g" 2>/dev/null || true
|
||||||
|
usermod -aG "$g" "$LIVE_USER" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
|
||||||
|
install -d -m 0755 /etc/sudoers.d
|
||||||
|
printf '%s ALL=(ALL) NOPASSWD: ALL\n' "$LIVE_USER" > /etc/sudoers.d/live
|
||||||
|
chmod 0440 /etc/sudoers.d/live
|
||||||
|
|
||||||
|
# nsswitch: remove mdns (library absent on Void; causes DNS lookup hangs)
|
||||||
|
if [ -f /etc/nsswitch.conf ]; then
|
||||||
|
sed -i '/^hosts:/s/mdns[^ ]* *//g' /etc/nsswitch.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fallback DNS (QEMU's 10.0.2.3 is unreliable; NM will overwrite once DHCP settles)
|
||||||
|
if ! grep -q '^nameserver' /etc/resolv.conf 2>/dev/null || \
|
||||||
|
grep -q '^nameserver 10\.0\.2\.3' /etc/resolv.conf 2>/dev/null; then
|
||||||
|
printf 'nameserver 8.8.8.8\nnameserver 1.1.1.1\n' > /etc/resolv.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure XDG_RUNTIME_DIR exists for the live user (greetd + elogind handle
|
||||||
|
# this normally, but set it here as a safety net).
|
||||||
|
XDG_RUN="/run/user/$(id -u "$LIVE_USER" 2>/dev/null || echo 1000)"
|
||||||
|
install -d -m 0700 "$XDG_RUN" 2>/dev/null || true
|
||||||
|
chown "$LIVE_USER" "$XDG_RUN" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Fix sound device permissions — PCM/control nodes are created root:root during
|
||||||
|
# early boot before the audio group is guaranteed to exist. Re-apply the correct
|
||||||
|
# ownership now that the group is present, then trigger udev to re-evaluate the
|
||||||
|
# sound subsystem so the persistent 70-sound-perms.rules rule is applied too.
|
||||||
|
chown root:audio /dev/snd/pcmC* /dev/snd/controlC* /dev/snd/hwC* 2>/dev/null || true
|
||||||
|
chmod 660 /dev/snd/pcmC* /dev/snd/controlC* /dev/snd/hwC* 2>/dev/null || true
|
||||||
|
udevadm trigger --subsystem-match=sound 2>/dev/null || true
|
||||||
|
|
||||||
|
# Timezone
|
||||||
|
ln -sf /usr/share/zoneinfo/Europe/Zurich /etc/localtime 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "niri live-setup: done (user=$LIVE_USER)"
|
||||||
|
SV_EOF
|
||||||
|
chmod 0755 "$INCLUDE_DIR/etc/runit/live-setup.sh"
|
||||||
|
|
||||||
|
# runit/2: standard Void runit stage 2 — runs live-setup then hands off to runsvdir
|
||||||
|
cat > "$INCLUDE_DIR/etc/runit/2" <<'SV_EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
PATH=/usr/bin:/usr/sbin
|
||||||
|
|
||||||
|
# Live session setup: groups, sudo, DNS
|
||||||
|
[ -x /etc/runit/live-setup.sh ] && /etc/runit/live-setup.sh
|
||||||
|
|
||||||
|
# Select runlevel from cmdline (default: default)
|
||||||
|
runlevel=default
|
||||||
|
for arg in $(cat /proc/cmdline); do
|
||||||
|
if [ -d /etc/runit/runsvdir/"$arg" ]; then
|
||||||
|
runlevel="$arg"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -x /etc/rc.local ] && /etc/rc.local
|
||||||
|
|
||||||
|
runsvchdir "${runlevel}"
|
||||||
|
mkdir -p /run/runit/runsvdir
|
||||||
|
ln -sf /etc/runit/runsvdir/current /run/runit/runsvdir/current
|
||||||
|
|
||||||
|
exec env - PATH=$PATH \
|
||||||
|
runsvdir -P /run/runit/runsvdir/current \
|
||||||
|
'log: ...........................................................................................................................................................................................................................................................................................................................................................................................................'
|
||||||
|
SV_EOF
|
||||||
|
chmod 0755 "$INCLUDE_DIR/etc/runit/2"
|
||||||
|
|
||||||
|
# Enable services for the niri live session
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/runit/runsvdir/default"
|
||||||
|
|
||||||
|
# Custom elogind sv: uses correct binary path and waits for dbus socket before
|
||||||
|
# starting (prevents "elogind is already running" spam from rapid runit restarts).
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/sv/elogind"
|
||||||
|
cat > "$INCLUDE_DIR/etc/sv/elogind/run" <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
exec 2>&1
|
||||||
|
|
||||||
|
# Helper: is elogind's login1 D-Bus name already registered on the system bus?
|
||||||
|
_login1_on_dbus() {
|
||||||
|
dbus-send --system --print-reply --dest=org.freedesktop.DBus \
|
||||||
|
/org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner \
|
||||||
|
string:org.freedesktop.login1 >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Helper: is elogind process alive via its PID file?
|
||||||
|
_elogind_alive() {
|
||||||
|
for _pf in /run/elogind.pid /run/elogind/elogind.pid; do
|
||||||
|
[ -f "$_pf" ] && kill -0 "$(cat "$_pf" 2>/dev/null)" 2>/dev/null && return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# If elogind is already running (process alive or D-Bus name taken), yield
|
||||||
|
# permanently so runit does not spam restarts.
|
||||||
|
if _elogind_alive || _login1_on_dbus; then
|
||||||
|
echo "elogind-sv: already running — yielding to avoid restart spam"
|
||||||
|
exec tail -f /dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Wait for dbus socket — poll every second, up to 30s
|
||||||
|
i=0
|
||||||
|
while [ $i -lt 30 ] && [ ! -S /run/dbus/system_bus_socket ]; do
|
||||||
|
sleep 1; i=$((i+1))
|
||||||
|
done
|
||||||
|
|
||||||
|
exec /usr/libexec/elogind/elogind.wrapper
|
||||||
|
EOF
|
||||||
|
chmod 0755 "$INCLUDE_DIR/etc/sv/elogind/run"
|
||||||
|
|
||||||
|
# finish: rate-limit restarts; if the run was very short (elogind crashed or
|
||||||
|
# reported "already running" before our detection), back off longer.
|
||||||
|
cat > "$INCLUDE_DIR/etc/sv/elogind/finish" <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
# $1=exitcode, $2=signal (or -1)
|
||||||
|
exitcode="$1"
|
||||||
|
# Non-zero exit with no signal = elogind bailed out (e.g. "already running").
|
||||||
|
# Sleep longer to avoid log spam; next run will yield via the D-Bus/PID check.
|
||||||
|
if [ "$exitcode" != "0" ] && [ "$2" = "-1" ]; then
|
||||||
|
sleep 10
|
||||||
|
else
|
||||||
|
sleep 3
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
chmod 0755 "$INCLUDE_DIR/etc/sv/elogind/finish"
|
||||||
|
|
||||||
|
for svc in dbus elogind NetworkManager bluetoothd sshd; do
|
||||||
|
ln -sf "/etc/sv/$svc" "$INCLUDE_DIR/etc/runit/runsvdir/default/$svc"
|
||||||
|
done
|
||||||
|
|
||||||
|
# ── 3d) Wayland environment ─────────────────────────────────────────────
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/profile.d"
|
||||||
|
cat > "$INCLUDE_DIR/etc/profile.d/wayland.sh" <<'EOF'
|
||||||
|
# Wayland defaults (mainline-niri live session)
|
||||||
|
export QT_QPA_PLATFORM="wayland;xcb"
|
||||||
|
export GDK_BACKEND="wayland,x11"
|
||||||
|
export MOZ_ENABLE_WAYLAND=1
|
||||||
|
export _JAVA_AWT_WM_NONREPARENTING=1
|
||||||
|
export XDG_CURRENT_DESKTOP=niri
|
||||||
|
export XDG_SESSION_TYPE=wayland
|
||||||
|
# Use elogind's logind backend — works correctly on Void/runit via audit session IDs
|
||||||
|
export LIBSEAT_BACKEND=logind
|
||||||
|
# Force GTK apps (and Electron/VSCode) to use XDG portal file dialogs
|
||||||
|
export GTK_USE_PORTAL=1
|
||||||
|
export ELECTRON_OZONE_PLATFORM_HINT=auto
|
||||||
|
EOF
|
||||||
|
chmod 0644 "$INCLUDE_DIR/etc/profile.d/wayland.sh"
|
||||||
|
|
||||||
|
# Nix profile.d: adds ~/.nix-profile/bin to PATH for interactive shells
|
||||||
|
cat > "$INCLUDE_DIR/etc/profile.d/nix-prebaked.sh" <<'EOF'
|
||||||
|
# Pre-baked nix profile — expose nix package binaries
|
||||||
|
if [[ -d "${HOME:-}/.nix-profile/bin" ]]; then
|
||||||
|
case ":$PATH:" in
|
||||||
|
*":$HOME/.nix-profile/bin:"*) ;;
|
||||||
|
*) export PATH="$HOME/.nix-profile/bin:$PATH" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
# Expose nix .desktop files and icons to XDG-compliant launchers/shells
|
||||||
|
if [[ -d "${HOME:-}/.nix-profile/share" ]]; then
|
||||||
|
case ":${XDG_DATA_DIRS:-}:" in
|
||||||
|
*":$HOME/.nix-profile/share:"*) ;;
|
||||||
|
*) export XDG_DATA_DIRS="$HOME/.nix-profile/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
export NIXPKGS_ALLOW_UNFREE=1
|
||||||
|
# Pre-baked nix is single-user (no daemon) — bypass daemon connection attempt
|
||||||
|
export NIX_REMOTE=local
|
||||||
|
# Flake commands ignore NIXPKGS_ALLOW_UNFREE unless --impure is passed.
|
||||||
|
# Wrap nix so interactive installs work without extra flags.
|
||||||
|
nix() { command nix "$@" --impure; }
|
||||||
|
export -f nix
|
||||||
|
EOF
|
||||||
|
chmod 0644 "$INCLUDE_DIR/etc/profile.d/nix-prebaked.sh"
|
||||||
|
|
||||||
|
# Nix daemon config (trusted live user so nix commands work without root)
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/nix"
|
||||||
|
cat > "$INCLUDE_DIR/etc/nix/nix.conf" <<EOF
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
build-users-group =
|
||||||
|
sandbox = false
|
||||||
|
auto-optimise-store = true
|
||||||
|
trusted-users = root ${LIVE_USER}
|
||||||
|
max-jobs = 2
|
||||||
|
http-connections = 10
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# nixpkgs config: allow unfree packages for all users
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/skel/.config/nixpkgs"
|
||||||
|
echo '{ allowUnfree = true; }' > "$INCLUDE_DIR/etc/skel/.config/nixpkgs/config.nix"
|
||||||
|
|
||||||
|
# git: GUI askpass so prompts work without a controlling terminal
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/usr/local/bin"
|
||||||
|
cat > "$INCLUDE_DIR/usr/local/bin/git-askpass" <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
for cmd in zenity qarma; do
|
||||||
|
command -v "$cmd" >/dev/null 2>&1 || continue
|
||||||
|
case "$1" in
|
||||||
|
*[Uu]sername*) exec "$cmd" --entry --title="Git Credentials" --text="$1" ;;
|
||||||
|
*) exec "$cmd" --password --title="Git Credentials" --text="$1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
printf '%s' "$1" >&2; read -r answer; printf '%s\n' "$answer"
|
||||||
|
EOF
|
||||||
|
chmod 0755 "$INCLUDE_DIR/usr/local/bin/git-askpass"
|
||||||
|
cat > "$INCLUDE_DIR/etc/gitconfig" <<'EOF'
|
||||||
|
[core]
|
||||||
|
askPass = /usr/local/bin/git-askpass
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# ── 3e) niri config.kdl in /etc/skel ───────────────────────────────────
|
||||||
|
# dracut's adduser.sh copies skel → /home/live, so the live user gets a
|
||||||
|
# ready niri config without any first-boot setup step.
|
||||||
|
|
||||||
|
# Pre-bake SSH authorized_keys from host so passwordless SSH just works in QEMU tests.
|
||||||
|
if _HOST_PUBKEY=$(ssh-add -L 2>/dev/null | head -1) && [ -n "$_HOST_PUBKEY" ]; then
|
||||||
|
install -d -m 0700 "$INCLUDE_DIR/etc/skel/.ssh"
|
||||||
|
echo "$_HOST_PUBKEY" > "$INCLUDE_DIR/etc/skel/.ssh/authorized_keys"
|
||||||
|
chmod 0600 "$INCLUDE_DIR/etc/skel/.ssh/authorized_keys"
|
||||||
|
fi
|
||||||
|
KEYMAP_XKB_LAYOUT="${KEYMAP%%-*}" # ch-fr_nodeadkeys → ch
|
||||||
|
KEYMAP_XKB_VARIANT="${KEYMAP#*-}" # ch-fr_nodeadkeys → fr_nodeadkeys
|
||||||
|
KEYMAP_XKB_VARIANT="${KEYMAP_XKB_VARIANT//_nodeadkeys/}" # strip trailing _nodeadkeys
|
||||||
|
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/skel/.config/niri"
|
||||||
|
cat > "$INCLUDE_DIR/etc/skel/.config/niri/config.kdl" <<EOF
|
||||||
|
// niri config — generated by void-installer (mainline-niri live session).
|
||||||
|
input {
|
||||||
|
keyboard {
|
||||||
|
xkb {
|
||||||
|
layout "${KEYMAP_XKB_LAYOUT}"
|
||||||
|
variant "${KEYMAP_XKB_VARIANT}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
touchpad {
|
||||||
|
tap
|
||||||
|
natural-scroll
|
||||||
|
dwt
|
||||||
|
}
|
||||||
|
mouse {
|
||||||
|
accel-speed 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout {
|
||||||
|
gaps 12
|
||||||
|
center-focused-column "never"
|
||||||
|
preset-column-widths {
|
||||||
|
proportion 0.33333
|
||||||
|
proportion 0.5
|
||||||
|
proportion 0.66667
|
||||||
|
}
|
||||||
|
default-column-width { proportion 0.5; }
|
||||||
|
focus-ring {
|
||||||
|
width 2
|
||||||
|
active-color "#fabd2f"
|
||||||
|
inactive-color "#3c3836"
|
||||||
|
}
|
||||||
|
border { off; }
|
||||||
|
}
|
||||||
|
|
||||||
|
prefer-no-csd
|
||||||
|
|
||||||
|
cursor {
|
||||||
|
xcursor-theme "${CURSOR_THEME:-Bibata-Modern-Ice}"
|
||||||
|
xcursor-size 24
|
||||||
|
}
|
||||||
|
|
||||||
|
// Audio / screen session services — started by niri as the live user
|
||||||
|
spawn-at-startup "pipewire"
|
||||||
|
spawn-at-startup "pipewire-pulse"
|
||||||
|
// Keep WirePlumber running: wait for the PipeWire socket then start it,
|
||||||
|
// restart on any crash or pipewire restart (e.g. after package installs).
|
||||||
|
spawn-at-startup "sh" "-c" "while true; do while [ ! -S /run/user/\$(id -u)/pipewire-0 ]; do sleep 0.2; done; wireplumber; sleep 1; done"
|
||||||
|
|
||||||
|
// Background, notifications and auth
|
||||||
|
spawn-at-startup "swaybg" "-i" "/usr/share/backgrounds/void-installer/pxfuel.jpg" "-m" "fill"
|
||||||
|
spawn-at-startup "mako"
|
||||||
|
spawn-at-startup "/usr/libexec/polkit-gnome-authentication-agent-1"
|
||||||
|
|
||||||
|
// noctalia-shell — wait for org.bluez before launching so the BT module
|
||||||
|
// initialises correctly (bluetoothd may not be on D-Bus yet at this point).
|
||||||
|
spawn-at-startup "sh" "-c" "i=0; while [ \$i -lt 30 ] && ! dbus-send --system --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:org.bluez >/dev/null 2>&1; do sleep 1; i=\$((i+1)); done; exec quickshell -c noctalia-shell"
|
||||||
|
|
||||||
|
// First-login setup: installs Claude Code (and NVM) once, then closes
|
||||||
|
spawn-at-startup "sh" "-c" "[ -f ~/.first-login-done ] || alacritty -T 'Void Setup' -e /usr/local/libexec/first-login.sh"
|
||||||
|
|
||||||
|
binds {
|
||||||
|
Mod+T { spawn "alacritty"; }
|
||||||
|
Mod+D { spawn "sh" "-c" "quickshell msg -c noctalia-shell launcher toggle"; }
|
||||||
|
Mod+Q { close-window; }
|
||||||
|
Mod+Shift+E { quit; }
|
||||||
|
Print { screenshot; }
|
||||||
|
Mod+H { focus-column-left; }
|
||||||
|
Mod+L { focus-column-right; }
|
||||||
|
Mod+J { focus-window-down; }
|
||||||
|
Mod+K { focus-window-up; }
|
||||||
|
Mod+Shift+H { move-column-left; }
|
||||||
|
Mod+Shift+L { move-column-right; }
|
||||||
|
Mod+1 { focus-workspace 1; }
|
||||||
|
Mod+2 { focus-workspace 2; }
|
||||||
|
Mod+3 { focus-workspace 3; }
|
||||||
|
Mod+4 { focus-workspace 4; }
|
||||||
|
Mod+Shift+1 { move-column-to-workspace 1; }
|
||||||
|
Mod+Shift+2 { move-column-to-workspace 2; }
|
||||||
|
XF86AudioRaiseVolume { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "5%+"; }
|
||||||
|
XF86AudioLowerVolume { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "5%-"; }
|
||||||
|
XF86AudioMute { spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle"; }
|
||||||
|
XF86MonBrightnessUp { spawn "brightnessctl" "set" "+5%"; }
|
||||||
|
XF86MonBrightnessDown { spawn "brightnessctl" "set" "5%-"; }
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# ── 3f) Themes / icons / wallpapers overlay ─────────────────────────────
|
||||||
|
echo ">>> staging niri customizations overlay"
|
||||||
|
OVERLAY="$INCLUDE_DIR/etc/installer-overlay"
|
||||||
|
install -d -m 0755 "$OVERLAY" "$OVERLAY/wallpapers" \
|
||||||
|
"$OVERLAY/themes" "$OVERLAY/icons"
|
||||||
|
|
||||||
|
# Wallpapers
|
||||||
|
WP_SRC="${WALLPAPERS_SRC:-$HOME/Scaricati}"
|
||||||
|
shopt -s nullglob
|
||||||
|
for f in "$WP_SRC"/pxfuel*.jpg; do
|
||||||
|
install -m 0644 "$f" "$OVERLAY/wallpapers/$(basename "$f")"
|
||||||
|
done
|
||||||
|
shopt -u nullglob
|
||||||
|
echo " wallpapers: $(ls "$OVERLAY/wallpapers" 2>/dev/null | wc -l) file(s)"
|
||||||
|
|
||||||
|
# Gruvbox GTK theme (for GTK apps running under niri)
|
||||||
|
THEME_CACHE="$CACHE_DIR/gruvbox-gtk-theme"
|
||||||
|
THEME_BUILD="$CACHE_DIR/gruvbox-gtk-built"
|
||||||
|
if [[ ! -d "$THEME_CACHE/.git" ]]; then
|
||||||
|
git clone --depth=1 https://github.com/Fausto-Korpsvart/Gruvbox-GTK-Theme.git "$THEME_CACHE" || true
|
||||||
|
fi
|
||||||
|
if [[ -x "$THEME_CACHE/themes/install.sh" && ! -d "$THEME_BUILD" ]]; then
|
||||||
|
echo " building gruvbox themes"
|
||||||
|
install -d -m 0755 "$THEME_BUILD"
|
||||||
|
"$DOCKER" run --rm \
|
||||||
|
-v "$THEME_CACHE":/src \
|
||||||
|
-v "$THEME_BUILD":/out \
|
||||||
|
debian:stable-slim sh -c '
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
apt-get update -qq >/dev/null
|
||||||
|
apt-get install -y --no-install-recommends sassc bash >/dev/null
|
||||||
|
cd /src/themes && bash install.sh -d /out -t default -c dark -s standard
|
||||||
|
' || true
|
||||||
|
fi
|
||||||
|
if [[ -d "$THEME_BUILD" ]]; then
|
||||||
|
for d in "$THEME_BUILD"/Gruvbox-Dark*; do
|
||||||
|
[[ -d "$d" ]] && cp -a "$d" "$OVERLAY/themes/$(basename "$d")"
|
||||||
|
done
|
||||||
|
echo " themes: $(ls "$OVERLAY/themes" 2>/dev/null | wc -l) variant(s)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Gruvbox Plus icons
|
||||||
|
ICON_CACHE="$CACHE_DIR/gruvbox-plus-icons"
|
||||||
|
if [[ ! -d "$ICON_CACHE/.git" ]]; then
|
||||||
|
git clone --depth=1 https://github.com/SylEleuth/gruvbox-plus-icon-pack.git "$ICON_CACHE" || true
|
||||||
|
fi
|
||||||
|
if [[ -d "$ICON_CACHE/Gruvbox-Plus-Dark" ]]; then
|
||||||
|
cp -a "$ICON_CACHE/Gruvbox-Plus-Dark" "$OVERLAY/icons/Gruvbox-Plus-Dark"
|
||||||
|
echo " icons: Gruvbox-Plus-Dark"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Bibata cursor
|
||||||
|
BIBATA_SRC="${BIBATA_SRC:-/usr/share/icons/Bibata-Modern-Ice}"
|
||||||
|
if [[ -d "$BIBATA_SRC" ]]; then
|
||||||
|
cp -a "$BIBATA_SRC" "$OVERLAY/icons/Bibata-Modern-Ice"
|
||||||
|
echo " cursor: Bibata-Modern-Ice"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# first-login.sh — deployed by _deploy_first_login() to the installed system.
|
||||||
|
[[ -r "$PROJECT_DIR/installer/first-login.sh" ]] && \
|
||||||
|
install -m 0755 "$PROJECT_DIR/installer/first-login.sh" "$OVERLAY/first-login.sh"
|
||||||
|
|
||||||
|
# Claude Code config + auth tokens from host (deployed to the installed system).
|
||||||
|
CLAUDE_SRC="${CLAUDE_SRC:-$HOME/.claude}"
|
||||||
|
[[ -d "$CLAUDE_SRC" ]] && { cp -a "$CLAUDE_SRC" "$OVERLAY/claude"; echo " claude: ~/.claude bundled"; }
|
||||||
|
[[ -r "${HOME}/.claude.json" ]] && install -m 0600 "${HOME}/.claude.json" "$OVERLAY/claude.json"
|
||||||
|
|
||||||
|
# VS Code user config + extension list from host.
|
||||||
|
VSCODE_SRC="${VSCODE_USER_SRC:-$HOME/.config/Code/User}"
|
||||||
|
install -d -m 0755 "$OVERLAY/vscode-user"
|
||||||
|
if [[ -d "$VSCODE_SRC" ]]; then
|
||||||
|
for f in settings.json keybindings.json; do
|
||||||
|
[[ -r "$VSCODE_SRC/$f" ]] && install -m 0644 "$VSCODE_SRC/$f" "$OVERLAY/vscode-user/$f"
|
||||||
|
done
|
||||||
|
[[ -d "$VSCODE_SRC/snippets" ]] && cp -a "$VSCODE_SRC/snippets" "$OVERLAY/vscode-user/snippets"
|
||||||
|
command -v code >/dev/null 2>&1 && \
|
||||||
|
code --list-extensions > "$OVERLAY/vscode-extensions.txt" 2>/dev/null || true
|
||||||
|
echo " vscode-user: staged from $VSCODE_SRC"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy wallpapers and assets into usr/share (rootfs overlay)
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/usr/share/backgrounds/void-installer"
|
||||||
|
cp -a "$OVERLAY/wallpapers"/. "$INCLUDE_DIR/usr/share/backgrounds/void-installer/" 2>/dev/null || true
|
||||||
|
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/usr/share/themes"
|
||||||
|
[[ -d "$OVERLAY/themes" ]] && cp -a "$OVERLAY/themes"/. "$INCLUDE_DIR/usr/share/themes/" 2>/dev/null || true
|
||||||
|
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/usr/share/icons"
|
||||||
|
[[ -d "$OVERLAY/icons" ]] && cp -a "$OVERLAY/icons"/. "$INCLUDE_DIR/usr/share/icons/" 2>/dev/null || true
|
||||||
|
|
||||||
|
# ── 3g) GTK settings + dark theme dconf ────────────────────────────────
|
||||||
|
# Write GTK2/3/4 settings to skel so the live user picks them up.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/skel/.config/gtk-3.0"
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/skel/.config/gtk-4.0"
|
||||||
|
|
||||||
|
# dconf system keyfile: ensures GTK dark theme is reported to all apps via
|
||||||
|
# xdg-desktop-portal-gtk regardless of whether the user has a dconf DB yet.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/dconf/db/local.d"
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/dconf/profile"
|
||||||
|
cat > "$INCLUDE_DIR/etc/dconf/db/local.d/01-dark-theme" <<'EOF'
|
||||||
|
[org/gnome/desktop/interface]
|
||||||
|
color-scheme='prefer-dark'
|
||||||
|
gtk-theme='${GTK_THEME}'
|
||||||
|
icon-theme='${ICON_THEME}'
|
||||||
|
cursor-theme='${CURSOR_THEME:-Bibata-Modern-Ice}'
|
||||||
|
cursor-size=24
|
||||||
|
EOF
|
||||||
|
sed -i "s/'\${GTK_THEME}'/'${GTK_THEME}'/; s/'\${ICON_THEME}'/'${ICON_THEME}'/; s/'\${CURSOR_THEME:-Bibata-Modern-Ice}'/'${CURSOR_THEME:-Bibata-Modern-Ice}'/" \
|
||||||
|
"$INCLUDE_DIR/etc/dconf/db/local.d/01-dark-theme"
|
||||||
|
printf 'user-db:user\nsystem-db:local\n' > "$INCLUDE_DIR/etc/dconf/profile/user"
|
||||||
|
|
||||||
|
cat > "$INCLUDE_DIR/etc/skel/.config/gtk-3.0/settings.ini" <<EOF
|
||||||
|
[Settings]
|
||||||
|
gtk-theme-name=${GTK_THEME}
|
||||||
|
gtk-icon-theme-name=${ICON_THEME}
|
||||||
|
gtk-cursor-theme-name=${CURSOR_THEME:-Bibata-Modern-Ice}
|
||||||
|
gtk-cursor-theme-size=24
|
||||||
|
gtk-font-name=Noto Sans 11
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cp "$INCLUDE_DIR/etc/skel/.config/gtk-3.0/settings.ini" \
|
||||||
|
"$INCLUDE_DIR/etc/skel/.config/gtk-4.0/settings.ini"
|
||||||
|
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/skel"
|
||||||
|
cat > "$INCLUDE_DIR/etc/skel/.gtkrc-2.0" <<EOF
|
||||||
|
gtk-theme-name="${GTK_THEME}"
|
||||||
|
gtk-icon-theme-name="${ICON_THEME}"
|
||||||
|
gtk-cursor-theme-name="${CURSOR_THEME:-Bibata-Modern-Ice}"
|
||||||
|
gtk-cursor-theme-size=24
|
||||||
|
gtk-font-name="Noto Sans 11"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# XDG_DATA_DIRS: include the pre-baked nix profile share dir so launchers
|
||||||
|
# and icon themes pick up nix-installed apps on first boot.
|
||||||
|
# /etc/environment is loaded by pam_env for ALL session types (tty autologin
|
||||||
|
# and greetd), so this is the most reliable place to set this baseline.
|
||||||
|
cat > "$INCLUDE_DIR/etc/environment" <<ENVEOF
|
||||||
|
XDG_DATA_DIRS=/home/${LIVE_USER}/.nix-profile/share:/usr/local/share:/usr/share
|
||||||
|
QT_QPA_PLATFORM=wayland;xcb
|
||||||
|
GDK_BACKEND=wayland,x11
|
||||||
|
MOZ_ENABLE_WAYLAND=1
|
||||||
|
LIBSEAT_BACKEND=logind
|
||||||
|
GTK_USE_PORTAL=1
|
||||||
|
ELECTRON_OZONE_PLATFORM_HINT=auto
|
||||||
|
ENVEOF
|
||||||
|
|
||||||
|
# ── noctalia default settings ─────────────────────────────────────────────
|
||||||
|
# Baseline settings.json placed in skel so the live user (and any installed
|
||||||
|
# user whose home is created from skel) starts with:
|
||||||
|
# - correct wallpaper directory pointing at the baked-in backgrounds
|
||||||
|
# - Gruvbox dark colour scheme
|
||||||
|
# - real app icons (iconMode=apps) instead of tabler monochrome icons
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/skel/.config/noctalia"
|
||||||
|
cat > "$INCLUDE_DIR/etc/skel/.config/noctalia/settings.json" <<NOCEOF
|
||||||
|
{
|
||||||
|
"appLauncher": {
|
||||||
|
"iconMode": "apps",
|
||||||
|
"sortByMostUsed": true,
|
||||||
|
"showCategories": true,
|
||||||
|
"viewMode": "grid",
|
||||||
|
"pinnedApps": [],
|
||||||
|
"terminalCommand": "alacritty -e",
|
||||||
|
"density": "default",
|
||||||
|
"position": "center"
|
||||||
|
},
|
||||||
|
"colorSchemes": {
|
||||||
|
"darkMode": true,
|
||||||
|
"predefinedScheme": "Gruvbox",
|
||||||
|
"generationMethod": "tonal-spot",
|
||||||
|
"manualSunrise": "06:30",
|
||||||
|
"manualSunset": "18:30",
|
||||||
|
"monitorForColors": ""
|
||||||
|
},
|
||||||
|
"wallpaper": {
|
||||||
|
"enabled": true,
|
||||||
|
"directory": "/usr/share/backgrounds/void-installer",
|
||||||
|
"fillMode": "crop",
|
||||||
|
"fillColor": "#000000",
|
||||||
|
"automationEnabled": false,
|
||||||
|
"favorites": [],
|
||||||
|
"hideWallpaperFilenames": false,
|
||||||
|
"linkLightAndDarkWallpapers": true,
|
||||||
|
"monitorDirectories": [],
|
||||||
|
"enableMultiMonitorDirectories": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NOCEOF
|
||||||
|
|
||||||
|
# ── Default browser: google-chrome (nix) ──────────────────────────────────
|
||||||
|
# System-wide MIME defaults so chrome is the default browser from first boot.
|
||||||
|
# Written to /etc/xdg/mimeapps.list (system default) and skel.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/xdg"
|
||||||
|
cat > "$INCLUDE_DIR/etc/xdg/mimeapps.list" <<'EOF'
|
||||||
|
[Default Applications]
|
||||||
|
text/html=google-chrome.desktop
|
||||||
|
x-scheme-handler/http=google-chrome.desktop
|
||||||
|
x-scheme-handler/https=google-chrome.desktop
|
||||||
|
x-scheme-handler/about=google-chrome.desktop
|
||||||
|
x-scheme-handler/unknown=google-chrome.desktop
|
||||||
|
application/pdf=google-chrome.desktop
|
||||||
|
application/xhtml+xml=google-chrome.desktop
|
||||||
|
application/xml=google-chrome.desktop
|
||||||
|
EOF
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/skel/.config"
|
||||||
|
cp "$INCLUDE_DIR/etc/xdg/mimeapps.list" "$INCLUDE_DIR/etc/skel/.config/mimeapps.list"
|
||||||
|
|
||||||
|
# ── Portal backend configuration for niri ─────────────────────────────────
|
||||||
|
# Without this, xdg-desktop-portal doesn't know which backend to use for
|
||||||
|
# XDG_CURRENT_DESKTOP=niri, causing file-picker / portal calls to fail.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/xdg/xdg-desktop-portal"
|
||||||
|
cat > "$INCLUDE_DIR/etc/xdg/xdg-desktop-portal/niri-portals.conf" <<'EOF'
|
||||||
|
[preferred]
|
||||||
|
default=gtk
|
||||||
|
org.freedesktop.impl.portal.FileChooser=gtk
|
||||||
|
org.freedesktop.impl.portal.AppChooser=gtk
|
||||||
|
org.freedesktop.impl.portal.OpenURI=gtk
|
||||||
|
org.freedesktop.impl.portal.Print=gtk
|
||||||
|
org.freedesktop.impl.portal.Screenshot=gtk
|
||||||
|
org.freedesktop.impl.portal.Inhibit=gtk
|
||||||
|
org.freedesktop.impl.portal.Notification=gtk
|
||||||
|
org.freedesktop.impl.portal.Settings=gtk
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# ── Sound device udev rules ────────────────────────────────────────
|
||||||
|
# PCM/control nodes are created root:root at early boot before the audio
|
||||||
|
# group is provisioned; this rule ensures correct ownership on every boot.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/udev/rules.d"
|
||||||
|
cat > "$INCLUDE_DIR/etc/udev/rules.d/70-sound-perms.rules" <<'EOF'
|
||||||
|
# Allow the audio group to access ALSA PCM and control devices.
|
||||||
|
SUBSYSTEM=="sound", GROUP="audio", MODE="0660"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# ── Timezone ──────────────────────────────────────────────────────────
|
||||||
|
# Create the /etc/localtime symlink and rc.conf TIMEZONE setting so the live
|
||||||
|
# session starts in the correct timezone without requiring a user step.
|
||||||
|
ln -sf /usr/share/zoneinfo/Europe/Zurich "$INCLUDE_DIR/etc/localtime"
|
||||||
|
cat > "$INCLUDE_DIR/etc/rc.conf" <<'RCEOF'
|
||||||
|
KEYMAP="ch"
|
||||||
|
HARDWARECLOCK="UTC"
|
||||||
|
TIMEZONE="Europe/Zurich"
|
||||||
|
RCEOF
|
||||||
|
|
||||||
|
# ── NVIDIA PRIME overlay ────────────────────────────────────────────────
|
||||||
|
echo ">>> staging NVIDIA PRIME overlay"
|
||||||
|
|
||||||
|
# Blacklist nouveau — prevents the open-source driver from grabbing the GPU
|
||||||
|
# before the proprietary nvidia driver.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/modprobe.d"
|
||||||
|
cat > "$INCLUDE_DIR/etc/modprobe.d/blacklist-nouveau.conf" <<'EOF'
|
||||||
|
blacklist nouveau
|
||||||
|
options nouveau modeset=0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Intel BT on this platform suffers firmware download failures when USB
|
||||||
|
# autosuspend is active for the btusb adapter.
|
||||||
|
cat > "$INCLUDE_DIR/etc/modprobe.d/btusb-quirks.conf" <<'EOF'
|
||||||
|
options btusb enable_autosuspend=0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Load nvidia modules early so the DRM device node exists before niri starts.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/modules-load.d"
|
||||||
|
cat > "$INCLUDE_DIR/etc/modules-load.d/nvidia.conf" <<'EOF'
|
||||||
|
nvidia
|
||||||
|
nvidia_modeset
|
||||||
|
nvidia_uvm
|
||||||
|
nvidia_drm
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# dracut: include nvidia modules in initramfs; omit nouveau.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/dracut.conf.d"
|
||||||
|
cat > "$INCLUDE_DIR/etc/dracut.conf.d/10-nvidia.conf" <<'EOF'
|
||||||
|
add_drivers+=" nvidia nvidia_modeset nvidia_uvm nvidia_drm "
|
||||||
|
omit_drivers+=" nouveau "
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Xorg output-class configs: intel=modesetting (primary), nvidia=PRIME offload.
|
||||||
|
# Needed by xwayland-satellite for X11 clients running under niri.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc/X11/xorg.conf.d"
|
||||||
|
cat > "$INCLUDE_DIR/etc/X11/xorg.conf.d/10-intel.conf" <<'EOF'
|
||||||
|
Section "OutputClass"
|
||||||
|
Identifier "intel"
|
||||||
|
MatchDriver "i915"
|
||||||
|
Driver "modesetting"
|
||||||
|
EndSection
|
||||||
|
EOF
|
||||||
|
cat > "$INCLUDE_DIR/etc/X11/xorg.conf.d/20-nvidia.conf" <<'EOF'
|
||||||
|
Section "OutputClass"
|
||||||
|
Identifier "nvidia"
|
||||||
|
MatchDriver "nvidia-drm"
|
||||||
|
Driver "nvidia"
|
||||||
|
Option "AllowEmptyInitialConfiguration"
|
||||||
|
Option "PrimaryGPU" "no"
|
||||||
|
ModulePath "/usr/lib/nvidia/xorg"
|
||||||
|
ModulePath "/usr/lib/xorg/modules"
|
||||||
|
EndSection
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# prime-run: launch any app on the NVIDIA dGPU via PRIME render-offload.
|
||||||
|
cat > "$INCLUDE_DIR/usr/local/bin/prime-run" <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
# Run a program on the NVIDIA dGPU via PRIME render offload.
|
||||||
|
exec env __NV_PRIME_RENDER_OFFLOAD=1 \
|
||||||
|
__VK_LAYER_NV_optimus=NVIDIA_only \
|
||||||
|
__GLX_VENDOR_LIBRARY_NAME=nvidia \
|
||||||
|
"$@"
|
||||||
|
EOF
|
||||||
|
chmod 0755 "$INCLUDE_DIR/usr/local/bin/prime-run"
|
||||||
|
|
||||||
|
# ── 3g2) niri-session wrapper ─────────────────────────────────────────────
|
||||||
|
# greetd/tuigreet starts niri-session (not niri --session directly) so that
|
||||||
|
# /etc/profile is sourced first, ensuring /etc/profile.d/* scripts run and
|
||||||
|
# XDG_DATA_DIRS gets ~/.nix-profile/share prepended for the compositor and
|
||||||
|
# all apps it spawns (noctalia-shell, fuzzel, etc.).
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/usr/local/bin"
|
||||||
|
cat > "$INCLUDE_DIR/usr/local/bin/niri-session" <<'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
# niri-session — wrapper started by greetd/tuigreet.
|
||||||
|
# Sources /etc/profile so that all /etc/profile.d/* scripts run
|
||||||
|
# (nix paths, wayland env, XDG_DATA_DIRS with ~/.nix-profile/share, etc.)
|
||||||
|
# before handing off to the compositor.
|
||||||
|
[ -f /etc/profile ] && . /etc/profile
|
||||||
|
exec niri --session "$@"
|
||||||
|
EOF
|
||||||
|
chmod 0755 "$INCLUDE_DIR/usr/local/bin/niri-session"
|
||||||
|
|
||||||
|
# ── 3h) .bash_profile: source .bashrc + launch niri on tty1 ───────────
|
||||||
|
# agetty autologin on tty1 runs a login shell; .bash_profile execs niri
|
||||||
|
# via dbus-run-session so it gets a D-Bus session bus.
|
||||||
|
cat > "$INCLUDE_DIR/etc/skel/.bash_profile" <<'EOF'
|
||||||
|
[[ -f ~/.bashrc ]] && . ~/.bashrc
|
||||||
|
if [[ "$(tty)" == /dev/tty1 ]] && [[ -z "$WAYLAND_DISPLAY" ]] && [[ -z "$NIRI_SOCKET" ]]; then
|
||||||
|
# Wrap niri startup: start GNOME Keyring daemon first (inside the D-Bus session)
|
||||||
|
# so Chrome/VSCode/apps can store secrets via org.freedesktop.secrets.
|
||||||
|
exec dbus-run-session -- sh -c '
|
||||||
|
if command -v gnome-keyring-daemon >/dev/null 2>&1; then
|
||||||
|
eval "$(gnome-keyring-daemon --start --components=secrets,pkcs11 2>/dev/null)" || true
|
||||||
|
export GNOME_KEYRING_CONTROL GNOME_KEYRING_PID SSH_AUTH_SOCK
|
||||||
|
fi
|
||||||
|
exec niri --session
|
||||||
|
'
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# ── 3i) Void Linux installer baked in ───────────────────────────────────
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/usr/local/lib/void-installer/lib"
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/usr/local/share/installer"
|
||||||
|
install -m 0755 "$PROJECT_DIR/installer/install.sh" \
|
||||||
|
"$INCLUDE_DIR/usr/local/lib/void-installer/install.sh"
|
||||||
|
for f in "$PROJECT_DIR/installer/lib/"*.sh; do
|
||||||
|
install -m 0755 "$f" \
|
||||||
|
"$INCLUDE_DIR/usr/local/lib/void-installer/lib/$(basename "$f")"
|
||||||
|
done
|
||||||
|
install -m 0644 "$PROJECT_DIR/config/install.conf" \
|
||||||
|
"$INCLUDE_DIR/usr/local/share/installer/install.conf"
|
||||||
|
install -m 0644 "$PROJECT_DIR/config/profiles/mainline-niri/packages.list" \
|
||||||
|
"$INCLUDE_DIR/usr/local/share/installer/packages.list"
|
||||||
|
if [[ -d "$PROJECT_DIR/config/profiles" ]]; then
|
||||||
|
cp -r "$PROJECT_DIR/config/profiles" \
|
||||||
|
"$INCLUDE_DIR/usr/local/share/installer/profiles"
|
||||||
|
fi
|
||||||
|
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/usr/local/bin"
|
||||||
|
cat > "$INCLUDE_DIR/usr/local/bin/void-install" <<'WRAPEOF'
|
||||||
|
#!/bin/sh
|
||||||
|
exec /usr/local/lib/void-installer/install.sh "$@"
|
||||||
|
WRAPEOF
|
||||||
|
chmod 0755 "$INCLUDE_DIR/usr/local/bin/void-install"
|
||||||
|
|
||||||
|
# first-login.sh at /usr/local/libexec: available in the live session and
|
||||||
|
# deployed by _deploy_first_login() to the installed system via the overlay.
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/usr/local/libexec"
|
||||||
|
install -m 0755 "$PROJECT_DIR/installer/first-login.sh" \
|
||||||
|
"$INCLUDE_DIR/usr/local/libexec/first-login.sh"
|
||||||
|
|
||||||
|
# nix-packages.list: tells first-login.sh which nix packages to install.
|
||||||
|
# In the live session these are already prebaked; in the installed system the
|
||||||
|
# first-boot-nix runit service handles them, so this is informational only.
|
||||||
|
{
|
||||||
|
printf '# Nix user packages\n'
|
||||||
|
printf '%s\n' "${NIX_USER_PACKAGES[@]}"
|
||||||
|
} > "$INCLUDE_DIR/usr/local/libexec/nix-packages.list"
|
||||||
|
|
||||||
|
_SECRETS_SRC="${SECRETS_ENV:-$PROJECT_DIR/secrets.env}"
|
||||||
|
if [[ -r "$_SECRETS_SRC" ]]; then
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/etc"
|
||||||
|
install -m 0600 "$_SECRETS_SRC" "$INCLUDE_DIR/etc/installer-secrets.env"
|
||||||
|
echo " baked installer secrets from $_SECRETS_SRC"
|
||||||
|
else
|
||||||
|
echo " WARNING: no secrets.env found — installer will prompt at runtime"
|
||||||
|
fi
|
||||||
|
|
||||||
|
install -d -m 0755 "$INCLUDE_DIR/usr/share/applications"
|
||||||
|
cat > "$INCLUDE_DIR/usr/share/applications/void-installer.desktop" <<'DESKEOF'
|
||||||
|
[Desktop Entry]
|
||||||
|
Version=1.0
|
||||||
|
Type=Application
|
||||||
|
Name=Install Void Linux
|
||||||
|
Comment=Install Void Linux to this machine
|
||||||
|
Exec=alacritty --title "Void Linux Installer" -e sudo /usr/local/bin/void-install
|
||||||
|
Icon=system-software-install
|
||||||
|
Terminal=false
|
||||||
|
Categories=System;
|
||||||
|
StartupNotify=true
|
||||||
|
DESKEOF
|
||||||
|
|
||||||
|
# 4) build Docker image (reuse the same image as Cinnamon build)
|
||||||
|
echo ">>> building docker image $DOCKER_IMAGE"
|
||||||
|
if "$DOCKER" buildx version >/dev/null 2>&1; then
|
||||||
|
"$DOCKER" build -t "$DOCKER_IMAGE" "$PROJECT_DIR/iso"
|
||||||
|
else
|
||||||
|
DOCKER_BUILDKIT=0 "$DOCKER" build -t "$DOCKER_IMAGE" "$PROJECT_DIR/iso"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5) packages + output filename
|
||||||
|
ISO_PKGS=$(grep -vE '^\s*(#|$)' \
|
||||||
|
"$PROJECT_DIR/config/profiles/mainline-niri/packages.live-desktop.list" \
|
||||||
|
| tr '\n' ' ')
|
||||||
|
TS="$(date -u +%Y%m%d)"
|
||||||
|
OUT_ISO="${OUTPUT_ISO:-$OUT_DIR/void-live-niri-${TS}.iso}"
|
||||||
|
|
||||||
|
# BOOT_CMDLINE notes (kernel audio, GPU, Bluetooth, etc.):
|
||||||
|
# • NO forced audio kernel parameters: Removed snd-intel-dspcfg.dsp_driver=1 and snd_hda_intel.dmic_detect=0
|
||||||
|
# because they forced legacy HDA mode, blocking SOF/SoundWire on hardware that needs it (e.g., XPS 9700).
|
||||||
|
# The kernel auto-selects the correct driver (0=auto, 3=SOF, 4=AVS) based on hardware IDs.
|
||||||
|
# Users can override at boot with "snd-intel-dspcfg.dsp_driver=3" if needed.
|
||||||
|
# See docs/KERNEL7_AUDIO_XPS9700.md for diagnostics.
|
||||||
|
# • nvidia-drm.modeset=1: Required for nvidia GPU to use atomic mode-setting on Wayland (Niri).
|
||||||
|
# • blacklist nouveau: nvidia GPU needs proprietary driver, not nouveau.
|
||||||
|
# • btusb.enable_autosuspend=0: Prevent Bluetooth headset dropouts when idle.
|
||||||
|
BOOT_CMDLINE="${BOOT_CMDLINE:-live.user=${LIVE_USER} console=tty0 console=ttyS0,115200 nvidia-drm.modeset=1 rd.driver.blacklist=nouveau modprobe.blacklist=nouveau btusb.enable_autosuspend=0}"
|
||||||
|
|
||||||
|
echo ">>> running mklive.sh inside docker — output: $OUT_ISO"
|
||||||
|
"$DOCKER" run --rm --privileged \
|
||||||
|
-v "$PROJECT_DIR:/work:rw" \
|
||||||
|
-v "$CACHE_DIR:/cache:rw" \
|
||||||
|
-e ARCH="${ARCH:-x86_64}" \
|
||||||
|
-e REPO_URL="${REPO_URL:-https://repo-default.voidlinux.org/current}" \
|
||||||
|
-e KEYMAP="${KEYMAP:-us}" \
|
||||||
|
-e LOCALE="${LOCALE:-en_US.UTF-8}" \
|
||||||
|
-e ISO_PKGS="$ISO_PKGS" \
|
||||||
|
-e ISO_TITLE="Void Live (niri / noctalia-shell)" \
|
||||||
|
-e OUT_ISO_REL="${OUT_ISO#$PROJECT_DIR/}" \
|
||||||
|
-e BOOT_CMDLINE="${BOOT_CMDLINE:-}" \
|
||||||
|
-e INCLUDE_DIR_REL="${INCLUDE_DIR#$PROJECT_DIR/}" \
|
||||||
|
-e NIX_PACKAGES_PREBAKE="${NIX_USER_PACKAGES[*]}" \
|
||||||
|
-e HOST_UID="$(id -u)" \
|
||||||
|
-e HOST_GID="$(id -g)" \
|
||||||
|
"$DOCKER_IMAGE" \
|
||||||
|
bash /work/iso/_inner-build-niri-live.sh
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo ">>> Niri live ISO built: $OUT_ISO"
|
||||||
|
sha256sum "$OUT_ISO" | tee "${OUT_ISO}.sha256" || true
|
||||||
1025
iso/build.sh
Executable file
1025
iso/build.sh
Executable file
File diff suppressed because it is too large
Load Diff
161
iso/patches/0003-dual-kernel-simplified-menu.patch
Normal file
161
iso/patches/0003-dual-kernel-simplified-menu.patch
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
--- a/mklive.sh 2026-04-25 21:08:53.137743383 +0200
|
||||||
|
+++ b/mklive.sh 2026-04-25 21:25:02.321939679 +0200
|
||||||
|
@@ -211,7 +211,7 @@
|
||||||
|
copy_include_directories() {
|
||||||
|
for includedir in "${INCLUDE_DIRS[@]}"; do
|
||||||
|
info_msg "=> copying include directory '$includedir' ..."
|
||||||
|
- find "$includedir" -mindepth 1 -maxdepth 1 -exec cp -rfpPv {} "$ROOTFS"/ \;
|
||||||
|
+ rsync -aHX "$includedir"/ "$ROOTFS"/
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -229,6 +229,41 @@
|
||||||
|
i686*|x86_64*) cp "$ROOTFS/boot/vmlinuz-$KERNELVERSION" "$BOOT_DIR"/vmlinuz ;;
|
||||||
|
aarch64*) cp "$ROOTFS/boot/vmlinux-$KERNELVERSION" "$BOOT_DIR"/vmlinux ;;
|
||||||
|
esac
|
||||||
|
+
|
||||||
|
+ # Generate boot files for secondary kernels installed alongside KERNELVERSION.
|
||||||
|
+ SECONDARY_BOOT_KERNELS=()
|
||||||
|
+ for _kdir in "$ROOTFS/usr/lib/modules"/*/; do
|
||||||
|
+ [[ -d "${_kdir}/kernel" ]] || continue
|
||||||
|
+ # Strip trailing slash before extracting basename (glob */ appends /)
|
||||||
|
+ _kver="${_kdir%/}"; _kver="${_kver##*/}"
|
||||||
|
+ [[ "$_kver" == "$KERNELVERSION" ]] && continue
|
||||||
|
+ info_msg "Secondary kernel ${_kver}: generating live initramfs..."
|
||||||
|
+ chroot "$ROOTFS" env -i /usr/bin/dracut -N --"${INITRAMFS_COMPRESSION}" \
|
||||||
|
+ --add-drivers "ahci" --force-add "vmklive autoinstaller" --omit systemd \
|
||||||
|
+ "/boot/initrd-${_kver}" "${_kver}" || {
|
||||||
|
+ echo "WARNING: dracut failed for secondary kernel ${_kver} — skipping"
|
||||||
|
+ continue
|
||||||
|
+ }
|
||||||
|
+ mv "$ROOTFS/boot/initrd-${_kver}" "$BOOT_DIR/initrd-${_kver}"
|
||||||
|
+ case "$TARGET_ARCH" in
|
||||||
|
+ i686*|x86_64*)
|
||||||
|
+ if [[ -f "$ROOTFS/boot/vmlinuz-${_kver}" ]]; then
|
||||||
|
+ cp "$ROOTFS/boot/vmlinuz-${_kver}" "$BOOT_DIR/vmlinuz-${_kver}"
|
||||||
|
+ else
|
||||||
|
+ echo "WARNING: vmlinuz-${_kver} not found — skipping secondary kernel"
|
||||||
|
+ rm -f "$BOOT_DIR/initrd-${_kver}"; continue
|
||||||
|
+ fi ;;
|
||||||
|
+ aarch64*)
|
||||||
|
+ if [[ -f "$ROOTFS/boot/vmlinux-${_kver}" ]]; then
|
||||||
|
+ cp "$ROOTFS/boot/vmlinux-${_kver}" "$BOOT_DIR/vmlinux-${_kver}"
|
||||||
|
+ else
|
||||||
|
+ echo "WARNING: vmlinux-${_kver} not found — skipping secondary kernel"
|
||||||
|
+ rm -f "$BOOT_DIR/initrd-${_kver}"; continue
|
||||||
|
+ fi ;;
|
||||||
|
+ esac
|
||||||
|
+ SECONDARY_BOOT_KERNELS+=("${_kver}")
|
||||||
|
+ info_msg "Secondary kernel ${_kver}: boot files staged"
|
||||||
|
+ done
|
||||||
|
}
|
||||||
|
|
||||||
|
array_contains() {
|
||||||
|
@@ -273,6 +308,17 @@
|
||||||
|
-e "s|@@BOOT_CMDLINE@@|${BOOT_CMDLINE}|" \
|
||||||
|
"$ISOLINUX_DIR"/isolinux.cfg
|
||||||
|
|
||||||
|
+ # Append entries for secondary kernels (standard boot only).
|
||||||
|
+ for _skver in "${SECONDARY_BOOT_KERNELS[@]+"${SECONDARY_BOOT_KERNELS[@]}"}"; do
|
||||||
|
+ cat >> "$ISOLINUX_DIR"/isolinux.cfg << SEOF
|
||||||
|
+
|
||||||
|
+LABEL linux-${_skver%%_*}
|
||||||
|
+MENU LABEL ${BOOT_TITLE} ${_skver} ${TARGET_ARCH}
|
||||||
|
+KERNEL /boot/vmlinuz-${_skver}
|
||||||
|
+APPEND initrd=/boot/initrd-${_skver} root=live:CDLABEL=VOID_LIVE init=/sbin/init ro rd.luks=0 rd.md=0 rd.dm=0 loglevel=4 vconsole.unicode=1 vconsole.keymap=${KEYMAP} locale.LANG=${LOCALE} ${BOOT_CMDLINE}
|
||||||
|
+SEOF
|
||||||
|
+ done
|
||||||
|
+
|
||||||
|
# include memtest86+
|
||||||
|
if [ -e "$VOIDTARGETDIR"/boot/memtest86+/memtest.bin ]; then
|
||||||
|
cp "$VOIDTARGETDIR"/boot/memtest86+/memtest.bin "$BOOT_DIR"
|
||||||
|
@@ -290,15 +336,16 @@
|
||||||
|
esac
|
||||||
|
|
||||||
|
write_entry() {
|
||||||
|
- local entrytitle="$1" id="$2" cmdline="$3" dtb="$4" hotkey="$5"
|
||||||
|
+ local entrytitle="$1" id="$2" cmdline="$3" dtb="$4" hotkey="$5" \
|
||||||
|
+ kimg="${6:-${KERNEL_IMG}}" kidrd="${7:-initrd}"
|
||||||
|
cat << EOF >> "$GRUB_DIR"/grub_void.cfg
|
||||||
|
menuentry "${entrytitle}" --id "${id}" ${hotkey:+--hotkey $hotkey} {
|
||||||
|
set gfxpayload="keep"
|
||||||
|
- linux (\${voidlive})/boot/${KERNEL_IMG} \\
|
||||||
|
+ linux (\${voidlive})/boot/${kimg} \\
|
||||||
|
root=live:CDLABEL=VOID_LIVE ro init=/sbin/init \\
|
||||||
|
rd.luks=0 rd.md=0 rd.dm=0 loglevel=4 gpt add_efi_memmap \\
|
||||||
|
vconsole.unicode=1 vconsole.keymap=${KEYMAP} locale.LANG=${LOCALE} ${cmdline}
|
||||||
|
- initrd (\${voidlive})/boot/initrd
|
||||||
|
+ initrd (\${voidlive})/boot/${kidrd}
|
||||||
|
EOF
|
||||||
|
if [ -n "${dtb}" ]; then
|
||||||
|
printf ' devicetree (${voidlive})/boot/dtbs/%s\n' "${dtb}" >> "$GRUB_DIR"/grub_void.cfg
|
||||||
|
@@ -311,23 +358,25 @@
|
||||||
|
|
||||||
|
ENTRY_TITLE="${BOOT_TITLE} ${KERNELVERSION} ${title_sfx}(${TARGET_ARCH})"
|
||||||
|
|
||||||
|
+ # Standard boot only — failsafe/RAM/speech variants removed.
|
||||||
|
write_entry "${ENTRY_TITLE}" "linux${id_sfx}" \
|
||||||
|
"$BOOT_CMDLINE $cmdline" "$dtb"
|
||||||
|
- write_entry "${ENTRY_TITLE} (RAM)" "linuxram${id_sfx}" \
|
||||||
|
- "rd.live.ram $BOOT_CMDLINE $cmdline" "$dtb"
|
||||||
|
- write_entry "${ENTRY_TITLE} (graphics disabled)" "linuxnogfx${id_sfx}" \
|
||||||
|
- "nomodeset $BOOT_CMDLINE $cmdline" "$dtb"
|
||||||
|
- write_entry "${ENTRY_TITLE} with speech" "linuxa11y${id_sfx}" \
|
||||||
|
- "live.accessibility live.autologin $BOOT_CMDLINE $cmdline" "$dtb" 's'
|
||||||
|
- write_entry "${ENTRY_TITLE} with speech (RAM)" "linuxa11yram${id_sfx}" \
|
||||||
|
- "live.accessibility live.autologin rd.live.ram $BOOT_CMDLINE $cmdline" "$dtb" 'r'
|
||||||
|
- write_entry "${ENTRY_TITLE} with speech (graphics disabled)" "linuxa11ynogfx${id_sfx}" \
|
||||||
|
- "live.accessibility live.autologin nomodeset $BOOT_CMDLINE $cmdline" "$dtb" 'g'
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
write_entries
|
||||||
|
|
||||||
|
+ # Secondary kernel entries (standard boot only).
|
||||||
|
+ for _skver in "${SECONDARY_BOOT_KERNELS[@]+"${SECONDARY_BOOT_KERNELS[@]}"}";
|
||||||
|
+ do
|
||||||
|
+ case "$TARGET_ARCH" in
|
||||||
|
+ i686*|x86_64*) _skimg="vmlinuz-${_skver}" ;;
|
||||||
|
+ aarch64*) _skimg="vmlinux-${_skver}" ;;
|
||||||
|
+ esac
|
||||||
|
+ write_entry "${BOOT_TITLE} ${_skver} (${TARGET_ARCH})" \
|
||||||
|
+ "linux-${_skver%%_*}" "$BOOT_CMDLINE" "" "" "${_skimg}" "initrd-${_skver}"
|
||||||
|
+ done
|
||||||
|
+
|
||||||
|
for platform in "${PLATFORMS[@]}"; do
|
||||||
|
(
|
||||||
|
. "platforms/${platform}.sh"
|
||||||
|
--- a/isolinux/isolinux.cfg.in 2026-04-25 21:08:53.137743383 +0200
|
||||||
|
+++ b/isolinux/isolinux.cfg.in 2026-04-25 21:13:05.897818309 +0200
|
||||||
|
@@ -25,31 +25,6 @@
|
||||||
|
KERNEL /boot/vmlinuz
|
||||||
|
APPEND initrd=/boot/initrd root=live:CDLABEL=VOID_LIVE init=/sbin/init ro rd.luks=0 rd.md=0 rd.dm=0 loglevel=4 vconsole.unicode=1 vconsole.keymap=@@KEYMAP@@ locale.LANG=@@LOCALE@@ @@BOOT_CMDLINE@@
|
||||||
|
|
||||||
|
-LABEL linuxram
|
||||||
|
-MENU LABEL @@BOOT_TITLE@@ @@KERNVER@@ @@ARCH@@ (RAM)
|
||||||
|
-KERNEL /boot/vmlinuz
|
||||||
|
-APPEND initrd=/boot/initrd root=live:CDLABEL=VOID_LIVE init=/sbin/init ro rd.luks=0 rd.md=0 rd.dm=0 loglevel=4 vconsole.unicode=1 vconsole.keymap=@@KEYMAP@@ locale.LANG=@@LOCALE@@ @@BOOT_CMDLINE@@ rd.live.ram
|
||||||
|
-
|
||||||
|
-LABEL linuxnogfx
|
||||||
|
-MENU LABEL @@BOOT_TITLE@@ @@KERNVER@@ @@ARCH@@ (graphics disabled)
|
||||||
|
-KERNEL /boot/vmlinuz
|
||||||
|
-APPEND initrd=/boot/initrd root=live:CDLABEL=VOID_LIVE init=/sbin/init ro rd.luks=0 rd.md=0 rd.dm=0 loglevel=4 vconsole.unicode=1 vconsole.keymap=@@KEYMAP@@ locale.LANG=@@LOCALE@@ @@BOOT_CMDLINE@@ nomodeset
|
||||||
|
-
|
||||||
|
-LABEL linuxa11y
|
||||||
|
-MENU LABEL @@BOOT_TITLE@@ @@KERNVER@@ @@ARCH@@ with ^speech
|
||||||
|
-KERNEL /boot/vmlinuz
|
||||||
|
-APPEND initrd=/boot/initrd root=live:CDLABEL=VOID_LIVE init=/sbin/init ro rd.luks=0 rd.md=0 rd.dm=0 loglevel=4 vconsole.unicode=1 vconsole.keymap=@@KEYMAP@@ locale.LANG=@@LOCALE@@ @@BOOT_CMDLINE@@ live.accessibility live.autologin
|
||||||
|
-
|
||||||
|
-LABEL linuxa11yram
|
||||||
|
-MENU LABEL @@BOOT_TITLE@@ @@KERNVER@@ @@ARCH@@ with speech (^RAM)
|
||||||
|
-KERNEL /boot/vmlinuz
|
||||||
|
-APPEND initrd=/boot/initrd root=live:CDLABEL=VOID_LIVE init=/sbin/init ro rd.luks=0 rd.md=0 rd.dm=0 loglevel=4 vconsole.unicode=1 vconsole.keymap=@@KEYMAP@@ locale.LANG=@@LOCALE@@ @@BOOT_CMDLINE@@ live.accessibility live.autologin rd.live.ram
|
||||||
|
-
|
||||||
|
-LABEL linuxa11ynogfx
|
||||||
|
-MENU LABEL @@BOOT_TITLE@@ @@KERNVER@@ @@ARCH@@ with speech (^graphics disabled)
|
||||||
|
-KERNEL /boot/vmlinuz
|
||||||
|
-APPEND initrd=/boot/initrd root=live:CDLABEL=VOID_LIVE init=/sbin/init ro rd.luks=0 rd.md=0 rd.dm=0 loglevel=4 vconsole.unicode=1 vconsole.keymap=@@KEYMAP@@ locale.LANG=@@LOCALE@@ @@BOOT_CMDLINE@@ live.accessibility live.autologin nomodeset
|
||||||
|
-
|
||||||
|
LABEL c
|
||||||
|
MENU LABEL Boot first HD found by BIOS
|
||||||
|
COM32 chain.c32
|
||||||
82
iso/postsetup-nvidia.sh
Executable file
82
iso/postsetup-nvidia.sh
Executable file
@@ -0,0 +1,82 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# void-mklive postsetup hook (-x flag).
|
||||||
|
#
|
||||||
|
# Runs AFTER copy_include_directories (overlay applied) but BEFORE
|
||||||
|
# generate_initramfs (boot initramfs). The xbps initramfs-regenerate trigger
|
||||||
|
# fires during install_packages — BEFORE the overlay — so the squashfs rootfs's
|
||||||
|
# own /boot/initramfs-KVER.img is missing our etc/dracut.conf.d/10-nvidia.conf.
|
||||||
|
#
|
||||||
|
# This script re-runs dracut inside the rootfs chroot for every installed kernel
|
||||||
|
# so the squashfs initramfs:
|
||||||
|
# • includes nvidia.ko (add_drivers from 10-nvidia.conf)
|
||||||
|
# • excludes nouveau.ko (omit_drivers from 10-nvidia.conf)
|
||||||
|
#
|
||||||
|
# $1 = absolute path to the rootfs directory being built.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOTFS="$1"
|
||||||
|
|
||||||
|
if [[ ! -d "$ROOTFS/usr/lib/modules" ]]; then
|
||||||
|
echo "[postsetup-nvidia] no modules dir — skipping"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -x "$ROOTFS/usr/bin/dracut" ]]; then
|
||||||
|
echo "[postsetup-nvidia] dracut not in rootfs — skipping"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$ROOTFS/etc/dracut.conf.d/10-nvidia.conf" ]]; then
|
||||||
|
echo "[postsetup-nvidia] WARNING: 10-nvidia.conf not found in rootfs overlay — skipping"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Mount pseudo-filesystems needed by dracut inside the chroot.
|
||||||
|
_umount_pseudo() {
|
||||||
|
for f in dev proc sys; do
|
||||||
|
[[ -d "$ROOTFS/$f" ]] && \
|
||||||
|
{ umount -R -f "$ROOTFS/$f" 2>/dev/null || umount -R -l "$ROOTFS/$f" 2>/dev/null || true; }
|
||||||
|
done
|
||||||
|
}
|
||||||
|
trap _umount_pseudo EXIT
|
||||||
|
|
||||||
|
for f in dev proc sys; do
|
||||||
|
mkdir -p "$ROOTFS/$f"
|
||||||
|
mount --rbind "/$f" "$ROOTFS/$f"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "[postsetup-nvidia] regenerating initramfs with nvidia config"
|
||||||
|
echo "[postsetup-nvidia] 10-nvidia.conf:"
|
||||||
|
sed 's/^/ /' "$ROOTFS/etc/dracut.conf.d/10-nvidia.conf"
|
||||||
|
|
||||||
|
found=0
|
||||||
|
for kdir in "$ROOTFS/usr/lib/modules"/*/; do
|
||||||
|
[[ -d "${kdir}/kernel" ]] || continue
|
||||||
|
# Strip trailing slash before extracting basename (glob */ appends /)
|
||||||
|
kver="${kdir%/}"; kver="${kver##*/}"
|
||||||
|
found=1
|
||||||
|
|
||||||
|
# Verify nvidia.ko is present for this kernel version.
|
||||||
|
nv_ko=$(find "$ROOTFS/usr/lib/modules/$kver" -name 'nvidia.ko' -o -name 'nvidia.ko.zst' 2>/dev/null | head -1)
|
||||||
|
if [[ -z "$nv_ko" ]]; then
|
||||||
|
echo "[postsetup-nvidia] WARNING: nvidia.ko not found for kernel $kver — initramfs regeneration skipped"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo "[postsetup-nvidia] kernel $kver: nvidia.ko at ${nv_ko#"$ROOTFS"}"
|
||||||
|
|
||||||
|
echo "[postsetup-nvidia] running dracut --force for $kver ..."
|
||||||
|
chroot "$ROOTFS" env -i PATH=/usr/sbin:/usr/bin:/sbin:/bin \
|
||||||
|
/usr/bin/dracut --force \
|
||||||
|
"/boot/initramfs-${kver}.img" \
|
||||||
|
"$kver" 2>&1 | grep -v '^$' | tail -5 || {
|
||||||
|
echo "[postsetup-nvidia] WARNING: dracut failed for $kver — continuing"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
sz=$(ls -lh "$ROOTFS/boot/initramfs-${kver}.img" 2>/dev/null | awk '{print $5}')
|
||||||
|
echo "[postsetup-nvidia] done: /boot/initramfs-${kver}.img ($sz)"
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ "$found" -eq 1 ]] || echo "[postsetup-nvidia] WARNING: no kernels found in rootfs"
|
||||||
|
echo "[postsetup-nvidia] complete"
|
||||||
39
tests/debug-qemu.sh
Executable file
39
tests/debug-qemu.sh
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Like interactive-qemu.sh but logs serial console to /tmp/qemu-serial.log
|
||||||
|
# for post-boot log inspection. Uses the niri ISO by default.
|
||||||
|
set -Eeuo pipefail
|
||||||
|
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
OUT_DIR="$PROJECT_DIR/out"
|
||||||
|
ISO="${ISO:-$(ls -t "$OUT_DIR"/void-live-niri-*.iso 2>/dev/null | head -1 || true)}"
|
||||||
|
DISK="${DISK:-$OUT_DIR/test-disk.img}"
|
||||||
|
RAM_MB="${RAM_MB:-6144}"
|
||||||
|
SMP="${SMP:-4}"
|
||||||
|
|
||||||
|
OVMF_CODE="${OVMF_CODE:-/usr/share/OVMF/OVMF_CODE.fd}"
|
||||||
|
OVMF_VARS_TPL="${OVMF_VARS_TPL:-/usr/share/OVMF/OVMF_VARS.fd}"
|
||||||
|
[[ -r "$OVMF_CODE" ]] || { echo "no OVMF — install ovmf"; exit 1; }
|
||||||
|
[[ -r "$ISO" ]] || { echo "no ISO at $ISO"; exit 1; }
|
||||||
|
|
||||||
|
if [[ ! -f "$DISK" ]]; then
|
||||||
|
"$PROJECT_DIR/tests/make-test-disk.sh" "$DISK"
|
||||||
|
fi
|
||||||
|
VARS="$OUT_DIR/OVMF_VARS.debug.fd"
|
||||||
|
[[ -f "$VARS" ]] || cp "$OVMF_VARS_TPL" "$VARS"
|
||||||
|
|
||||||
|
SERIAL_PORT="${SERIAL_PORT:-4444}"
|
||||||
|
echo ">>> serial console → TCP port $SERIAL_PORT (connect: socat -,raw,echo=0 TCP:127.0.0.1:$SERIAL_PORT)"
|
||||||
|
echo ">>> ISO: $ISO"
|
||||||
|
|
||||||
|
exec qemu-system-x86_64 \
|
||||||
|
-name void-niri-debug \
|
||||||
|
-machine q35,accel=kvm:tcg -cpu max \
|
||||||
|
-m "$RAM_MB" -smp "$SMP" \
|
||||||
|
-drive "if=pflash,format=raw,readonly=on,file=$OVMF_CODE" \
|
||||||
|
-drive "if=pflash,format=raw,file=$VARS" \
|
||||||
|
-drive "if=virtio,file=$DISK,format=raw,cache=none" \
|
||||||
|
-cdrom "$ISO" \
|
||||||
|
-boot menu=on \
|
||||||
|
-netdev user,id=n0,hostfwd=tcp:127.0.0.1:2222-:22 \
|
||||||
|
-device virtio-net-pci,netdev=n0 \
|
||||||
|
-serial "tcp::${SERIAL_PORT},server,nowait" \
|
||||||
|
-device virtio-gpu-gl -display gtk,gl=on
|
||||||
@@ -67,15 +67,17 @@ export TEST_PUBKEY
|
|||||||
# ---------- 2) build TEST ISO ----------
|
# ---------- 2) build TEST ISO ----------
|
||||||
TEST_ISO="$OUT_DIR/void-install-TEST.iso"
|
TEST_ISO="$OUT_DIR/void-install-TEST.iso"
|
||||||
TEST_OVERLAY_DIR="$OUT_DIR/test-overlay"
|
TEST_OVERLAY_DIR="$OUT_DIR/test-overlay"
|
||||||
"$PROJECT_DIR/tests/lib/make-test-overlay.sh" "$TEST_OVERLAY_DIR"
|
TEST_PROFILE="${PROFILE:-stable-cinnamon}" \
|
||||||
|
"$PROJECT_DIR/tests/lib/make-test-overlay.sh" "$TEST_OVERLAY_DIR"
|
||||||
|
|
||||||
if [[ ! -f "$TEST_ISO" || -n "${REBUILD_ISO:-}" ]]; then
|
if [[ ! -f "$TEST_ISO" || -n "${REBUILD_ISO:-}" ]]; then
|
||||||
blue "building test ISO -> $TEST_ISO"
|
blue "building test ISO -> $TEST_ISO (profile: ${PROFILE:-stable-cinnamon})"
|
||||||
EXTRA_INCLUDE_DIR="$TEST_OVERLAY_DIR" \
|
EXTRA_INCLUDE_DIR="$TEST_OVERLAY_DIR" \
|
||||||
OUTPUT_ISO="$TEST_ISO" \
|
OUTPUT_ISO="$TEST_ISO" \
|
||||||
INSTALL_REPO_URL="http://10.0.2.2:3142/current" \
|
INSTALL_REPO_URL="http://10.0.2.2:3142/current" \
|
||||||
BOOT_CMDLINE="console=tty0 console=ttyS0,115200" \
|
BOOT_CMDLINE="console=tty0 console=ttyS0,115200" \
|
||||||
"$PROJECT_DIR/iso/build-iso.sh"
|
PROFILE="${PROFILE:-stable-cinnamon}" \
|
||||||
|
"$PROJECT_DIR/iso/build.sh" --profile "${PROFILE:-stable-cinnamon}" --type installer
|
||||||
else
|
else
|
||||||
blue "reusing cached test ISO $TEST_ISO (set REBUILD_ISO=1 to rebuild)"
|
blue "reusing cached test ISO $TEST_ISO (set REBUILD_ISO=1 to rebuild)"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user