Add 4 configurable profiles (stable-cinnamon, stable-niri, mainline-cinnamon, mainline-niri) with a single unified build entry point. - iso/build.sh: replaces build-iso.sh / build-live-iso.sh / build-niri-live-iso.sh; accepts --profile and --type flags - iso/_inner-build-unified.sh: replaces the three _inner-build-*.sh scripts; branches on BUILD_TYPE / DESKTOP / KERNEL_PKG env vars - config/profiles/stable-niri/: new — linux (k6) + niri/Wayland/noctalia - config/profiles/mainline-cinnamon/: new — linux-mainline (k7) + Cinnamon/X11 - config/profiles/mainline-niri/packages.live.list: symlink added - config/profiles/stable-cinnamon/packages.live.list: symlink added - Makefile: PROFILE variable (default stable-cinnamon), shellcheck updated - installer/install.sh: respects DEFAULT_PROFILE env (set by live ISO) - tests/run-qemu-test.sh: passes PROFILE through to build and overlay Live ISOs embed the installer pre-configured for the same profile they were built with (DEFAULT_PROFILE in /etc/profile.d/).
1026 lines
39 KiB
Bash
Executable File
1026 lines
39 KiB
Bash
Executable File
#!/bin/bash
|
|
# Unified ISO build script.
|
|
#
|
|
# Usage:
|
|
# iso/build.sh [--profile PROFILE] [--type installer|live]
|
|
# iso/build.sh -p PROFILE -t TYPE
|
|
#
|
|
# PROFILE: stable-cinnamon | stable-niri | mainline-cinnamon | mainline-niri
|
|
# TYPE: installer — small auto-installing ISO (~600 MB), boots directly to
|
|
# the installer; used for unattended / scripted deploys.
|
|
# live — full desktop ISO with the installer also embedded;
|
|
# boots to the selected DE so you can test before installing.
|
|
#
|
|
# The live ISO pre-configures the embedded installer to default to the SAME
|
|
# PROFILE it was built with, so running 'void-install' from the live session
|
|
# will install the exact same configuration you are running.
|
|
#
|
|
# Requires (host): bash, git, curl, docker.
|
|
|
|
set -Eeuo pipefail
|
|
|
|
# ── argument parsing ──────────────────────────────────────────────────────
|
|
PROFILE="${PROFILE:-stable-cinnamon}"
|
|
BUILD_TYPE="${BUILD_TYPE:-live}"
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--profile|-p) PROFILE="$2"; shift 2 ;;
|
|
--type|-t) BUILD_TYPE="$2"; shift 2 ;;
|
|
*) echo "Unknown argument: $1"; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
case "$PROFILE" in
|
|
stable-cinnamon|stable-niri|mainline-cinnamon|mainline-niri) ;;
|
|
*)
|
|
echo "Unknown profile: '$PROFILE'"
|
|
echo "Valid values: stable-cinnamon stable-niri mainline-cinnamon mainline-niri"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
case "$BUILD_TYPE" in
|
|
installer|live) ;;
|
|
*)
|
|
echo "Unknown build type: '$BUILD_TYPE'"
|
|
echo "Valid values: installer live"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# ── paths ─────────────────────────────────────────────────────────────────
|
|
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}"
|
|
PATCH_DIR="$PROJECT_DIR/iso/patches"
|
|
DOCKER_IMAGE="${DOCKER_IMAGE:-void-installer-builder:latest}"
|
|
DOCKER="${DOCKER:-docker}"
|
|
LIVE_USER="${LIVE_USER:-live}"
|
|
|
|
# Niri profiles use a separate mklive clone directory to avoid races when
|
|
# building cinnamon and niri ISOs in parallel on the same host.
|
|
case "$PROFILE" in
|
|
*-niri) MKLIVE_DIR="$CACHE_DIR/void-mklive-niri" ;;
|
|
*) MKLIVE_DIR="$CACHE_DIR/void-mklive" ;;
|
|
esac
|
|
MKLIVE_REPO="${MKLIVE_REPO:-https://github.com/void-linux/void-mklive.git}"
|
|
MKLIVE_REF="${MKLIVE_REF:-master}"
|
|
|
|
# Per-profile, per-type build directory — parallel builds don't clobber each other.
|
|
INCLUDE_DIR="$BUILD_DIR/${PROFILE}-${BUILD_TYPE}-includes"
|
|
|
|
# ── load configuration ────────────────────────────────────────────────────
|
|
PROFILE_DIR="$PROJECT_DIR/config/profiles/$PROFILE"
|
|
[[ -d "$PROFILE_DIR" ]] || { echo "Profile directory not found: $PROFILE_DIR"; exit 1; }
|
|
|
|
# shellcheck disable=SC1091
|
|
source "$PROJECT_DIR/config/install.conf"
|
|
# shellcheck disable=SC1090
|
|
source "$PROFILE_DIR/profile.conf"
|
|
|
|
SECRETS_FILE="${SECRETS_FILE:-$PROJECT_DIR/secrets.env}"
|
|
[[ -r "$SECRETS_FILE" ]] || { echo "missing $SECRETS_FILE — copy from template"; exit 1; }
|
|
# shellcheck disable=SC1090
|
|
source "$SECRETS_FILE"
|
|
: "${USER_PASSWORD:?}"; : "${ROOT_PASSWORD:?}"
|
|
|
|
SSH_SRC_DIR="${SSH_SRC_DIR:-$HOME/.ssh}"
|
|
[[ -d "$SSH_SRC_DIR" ]] || { echo "no SSH dir at $SSH_SRC_DIR"; exit 1; }
|
|
|
|
# ── validate docker ────────────────────────────────────────────────────────
|
|
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"
|
|
|
|
# ═════════════════════════════════════════════════════════════════════════════
|
|
# HELPER FUNCTIONS
|
|
# (all defined here so main execution at the bottom can call them)
|
|
# ═════════════════════════════════════════════════════════════════════════════
|
|
|
|
_stage_installer_overlay() {
|
|
# Installer ISO: auto-login root on tty1, run install-void, drop to shell.
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/sv/installer"
|
|
cat > "$INCLUDE_DIR/etc/sv/installer/run" <<'SV_EOF'
|
|
#!/bin/sh
|
|
exec /sbin/agetty --autologin root --noclear tty1 linux
|
|
SV_EOF
|
|
chmod 0755 "$INCLUDE_DIR/etc/sv/installer/run"
|
|
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/sv/agetty-tty1"
|
|
: > "$INCLUDE_DIR/etc/sv/agetty-tty1/down"
|
|
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/runit/runsvdir/default"
|
|
ln -sf /etc/sv/installer "$INCLUDE_DIR/etc/runit/runsvdir/default/installer"
|
|
|
|
install -d -m 0700 "$INCLUDE_DIR/root"
|
|
cat > "$INCLUDE_DIR/root/.bash_profile" <<'PROFILE_EOF'
|
|
case "$(tty)" in
|
|
/dev/tty1)
|
|
if [ ! -f /tmp/.installer-done ]; then
|
|
touch /tmp/.installer-done
|
|
clear
|
|
echo
|
|
echo " Void Linux Installer"
|
|
echo " Press ENTER to start, or Ctrl-C within 5s for a shell."
|
|
sleep 5 || true
|
|
/usr/local/sbin/install-void || {
|
|
echo "Installer exited with $?. Dropping to shell."
|
|
exec /bin/bash
|
|
}
|
|
echo "Install complete. Type 'reboot' or 'poweroff'."
|
|
exec /bin/bash
|
|
fi
|
|
;;
|
|
esac
|
|
PROFILE_EOF
|
|
chmod 0644 "$INCLUDE_DIR/root/.bash_profile"
|
|
|
|
# shellcheck disable=SC2154 # PROFILE and HOSTNAME are from sourced config
|
|
cat > "$INCLUDE_DIR/etc/motd" <<MOTD_EOF
|
|
|
|
Void Linux Installer — profile: ${PROFILE}
|
|
Run: install-void
|
|
Logs: /var/log/void-installer.log
|
|
|
|
MOTD_EOF
|
|
}
|
|
|
|
_stage_live_overlay() {
|
|
_stage_live_common
|
|
case "$DESKTOP" in
|
|
cinnamon) _stage_live_cinnamon ;;
|
|
niri) _stage_live_niri ;;
|
|
*) echo "WARNING: unknown DESKTOP '${DESKTOP}' — skipping DE-specific overlay" ;;
|
|
esac
|
|
}
|
|
|
|
_stage_live_common() {
|
|
# xbps repo config (xbps.d will be appended by niri variant if needed)
|
|
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
|
|
|
|
# runit stage-2 override: runs live-setup.sh then hands off to runsvdir
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/runit"
|
|
cat > "$INCLUDE_DIR/etc/runit/2" <<'SV_EOF'
|
|
#!/bin/sh
|
|
PATH=/usr/bin:/usr/sbin
|
|
|
|
[ -x /etc/runit/live-setup.sh ] && /etc/runit/live-setup.sh
|
|
|
|
runlevel=default
|
|
for arg in $(cat /proc/cmdline); do
|
|
[ -d /etc/runit/runsvdir/"$arg" ] && runlevel="$arg"
|
|
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"
|
|
|
|
# /etc/environment (XDG_DATA_DIRS includes nix profile share for app menus)
|
|
cat > "$INCLUDE_DIR/etc/environment" <<'ENVEOF'
|
|
XDG_DATA_DIRS=/home/live/.nix-profile/share:/usr/local/share:/usr/share
|
|
ENVEOF
|
|
|
|
# Timezone and rc.conf
|
|
# shellcheck disable=SC2154
|
|
ln -sf "/usr/share/zoneinfo/${TIMEZONE:-Europe/Zurich}" "$INCLUDE_DIR/etc/localtime"
|
|
cat > "$INCLUDE_DIR/etc/rc.conf" <<RCEOF
|
|
KEYMAP="${KEYMAP:-us}"
|
|
HARDWARECLOCK="UTC"
|
|
TIMEZONE="${TIMEZONE:-Europe/Zurich}"
|
|
RCEOF
|
|
|
|
# Sound device udev rules
|
|
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, prime-run wrapper, dracut config)
|
|
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"
|
|
|
|
# nix prebake profile.d
|
|
cat > "$INCLUDE_DIR/etc/profile.d/nix-prebaked.sh" <<'NIXEOF'
|
|
if [[ -d "${HOME:-}/.nix-profile/bin" ]]; then
|
|
case ":$PATH:" in
|
|
*":$HOME/.nix-profile/bin:"*) ;;
|
|
*) export PATH="$HOME/.nix-profile/bin:$PATH" ;;
|
|
esac
|
|
fi
|
|
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
|
|
export NIX_REMOTE=local
|
|
nix() { command nix "$@" --impure; }
|
|
export -f nix
|
|
NIXEOF
|
|
chmod 0644 "$INCLUDE_DIR/etc/profile.d/nix-prebaked.sh"
|
|
|
|
# nix daemon config
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/nix"
|
|
# shellcheck disable=SC2154
|
|
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
|
|
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/skel/.config/nixpkgs"
|
|
echo '{ allowUnfree = true; }' > "$INCLUDE_DIR/etc/skel/.config/nixpkgs/config.nix"
|
|
|
|
# git askpass (works without 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
|
|
|
|
# skel .bash_profile
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/skel"
|
|
cat > "$INCLUDE_DIR/etc/skel/.bash_profile" <<'EOF'
|
|
[[ -f ~/.bashrc ]] && . ~/.bashrc
|
|
EOF
|
|
|
|
# themes / icons / wallpapers in usr/share
|
|
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
|
|
|
|
# first-login.sh available for manual use from live session
|
|
install -d -m 0755 "$INCLUDE_DIR/usr/local/libexec"
|
|
if [[ -r "$OVERLAY/first-login.sh" ]]; then
|
|
install -m 0755 "$OVERLAY/first-login.sh" "$INCLUDE_DIR/usr/local/libexec/first-login.sh"
|
|
fi
|
|
|
|
# installer desktop entry (double-click to launch in a terminal)
|
|
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/sbin/install-void
|
|
Icon=system-software-install
|
|
Terminal=false
|
|
Categories=System;
|
|
StartupNotify=true
|
|
DESKEOF
|
|
}
|
|
|
|
_stage_live_cinnamon() {
|
|
# live-setup.sh: extra groups, sudo, nix, DNS, timezone, Xorg GPU detection
|
|
cat > "$INCLUDE_DIR/etc/runit/live-setup.sh" <<'SV_EOF'
|
|
#!/bin/sh
|
|
LIVE_USER="${USERNAME:-live}"
|
|
[ -f /etc/default/live.conf ] && . /etc/default/live.conf
|
|
LIVE_USER="${LIVE_USER:-live}"
|
|
|
|
for g in plugdev input network docker 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
|
|
|
|
if [ -x /usr/bin/nix ]; then
|
|
install -d -m 0755 /etc/nix
|
|
cat > /etc/nix/nix.conf <<NIXCONF
|
|
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
|
|
NIXCONF
|
|
cat > /etc/profile.d/nix-live.sh <<'NIXSH'
|
|
if [ -d "$HOME/.nix-profile/bin" ]; then export PATH="$HOME/.nix-profile/bin:$PATH"; fi
|
|
NIXSH
|
|
chmod 0644 /etc/profile.d/nix-live.sh
|
|
fi
|
|
|
|
[ -f /etc/nsswitch.conf ] && sed -i '/^hosts:/s/mdns[^ ]* *//g' /etc/nsswitch.conf
|
|
|
|
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
|
|
|
|
ln -sf /usr/share/zoneinfo/Europe/Zurich /etc/localtime 2>/dev/null || true
|
|
|
|
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
|
|
|
|
mkdir -p /etc/X11/xorg.conf.d
|
|
HAS_NVIDIA=0; IS_VIRT=0
|
|
if command -v lspci >/dev/null 2>&1; then
|
|
lspci_out=$(lspci 2>/dev/null)
|
|
echo "$lspci_out" | grep -qi 'NVIDIA' && HAS_NVIDIA=1
|
|
echo "$lspci_out" | grep -qiE 'virtio|VMware|QEMU|VirtualBox|bochs' && IS_VIRT=1
|
|
fi
|
|
|
|
if [ $IS_VIRT -eq 1 ]; then
|
|
printf 'Section "Device"\n Identifier "GPU"\n Driver "modesetting"\n Option "AccelMethod" "none"\nEndSection\n' \
|
|
> /etc/X11/xorg.conf.d/20-gpu.conf
|
|
echo 'export LIBGL_ALWAYS_SOFTWARE=1' > /etc/profile.d/live-env.sh
|
|
chmod 0644 /etc/profile.d/live-env.sh
|
|
elif [ $HAS_NVIDIA -eq 1 ] && [ -e /usr/lib/xorg/modules/drivers/nvidia_drv.so ]; then
|
|
rm -f /etc/profile.d/live-env.sh
|
|
INTEL_BUSID=$(lspci | grep -iE 'VGA.*Intel|Intel.*VGA' | head -1 | \
|
|
awk '{print $1}' | awk -F'[.:]' '{printf "PCI:%d:%d:%d", strtonum("0x"$1), strtonum("0x"$2), strtonum("0x"$3)}')
|
|
NVIDIA_BUSID=$(lspci | grep -i NVIDIA | head -1 | \
|
|
awk '{print $1}' | awk -F'[.:]' '{printf "PCI:%d:%d:%d", strtonum("0x"$1), strtonum("0x"$2), strtonum("0x"$3)}')
|
|
cat > /etc/X11/xorg.conf.d/20-gpu.conf <<EOF
|
|
Section "ServerLayout"
|
|
Identifier "layout"
|
|
Option "AllowNVIDIAGPUScreens"
|
|
EndSection
|
|
Section "Device"
|
|
Identifier "Intel"
|
|
Driver "modesetting"
|
|
BusID "${INTEL_BUSID:-PCI:0:2:0}"
|
|
EndSection
|
|
Section "Device"
|
|
Identifier "NVIDIA"
|
|
Driver "nvidia"
|
|
BusID "${NVIDIA_BUSID:-PCI:1:0:0}"
|
|
Option "AllowEmptyInitialConfiguration"
|
|
EndSection
|
|
EOF
|
|
else
|
|
rm -f /etc/profile.d/live-env.sh
|
|
printf 'Section "Device"\n Identifier "GPU"\n Driver "modesetting"\nEndSection\n' \
|
|
> /etc/X11/xorg.conf.d/20-gpu.conf
|
|
fi
|
|
|
|
echo "live-setup (cinnamon): done"
|
|
SV_EOF
|
|
chmod 0755 "$INCLUDE_DIR/etc/runit/live-setup.sh"
|
|
|
|
# LightDM autologin — session file read by vmklive dracut hook
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/lightdm"
|
|
echo 'cinnamon' > "$INCLUDE_DIR/etc/lightdm/.session"
|
|
# Autologin lines commented so display-manager-autologin.sh hook uncomments them
|
|
cat > "$INCLUDE_DIR/etc/lightdm/lightdm.conf" <<'EOF'
|
|
[Seat:*]
|
|
#autologin-user=
|
|
#autologin-user-timeout=0
|
|
#autologin-session=
|
|
#user-session=
|
|
session-wrapper=/etc/lightdm/Xsession
|
|
greeter-session=lightdm-gtk-greeter
|
|
EOF
|
|
# NOTE: session-wrapper=/etc/lightdm/Xsession required on Void — 'lightdm-session'
|
|
# binary is NOT packaged; Xsession sources /etc/profile so profile.d/ vars reach
|
|
# the Cinnamon session (LIBGL_ALWAYS_SOFTWARE=1 from live-setup.sh, etc.)
|
|
|
|
# runit services
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/runit/runsvdir/default"
|
|
for svc in dbus NetworkManager lightdm bluetoothd nix-daemon; do
|
|
ln -sf "/etc/sv/$svc" "$INCLUDE_DIR/etc/runit/runsvdir/default/$svc" 2>/dev/null || true
|
|
done
|
|
|
|
# dconf keyfile for Cinnamon theme / keyboard
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/dconf/db/local.d" \
|
|
"$INCLUDE_DIR/etc/dconf/profile"
|
|
cat > "$INCLUDE_DIR/etc/dconf/profile/user" <<'EOF'
|
|
user-db:user
|
|
system-db:local
|
|
EOF
|
|
|
|
WALLPAPER_FILE=$(ls "$OVERLAY/wallpapers/"*.jpg 2>/dev/null | head -1 | \
|
|
xargs basename 2>/dev/null || echo "pxfuel.jpg")
|
|
# shellcheck disable=SC2154
|
|
cat > "$INCLUDE_DIR/etc/dconf/db/local.d/00-cinnamon" <<EOF
|
|
[org/cinnamon/desktop/interface]
|
|
gtk-theme='${GTK_THEME}'
|
|
icon-theme='${ICON_THEME}'
|
|
cursor-theme='${CURSOR_THEME}'
|
|
|
|
[org/cinnamon/desktop/wm/preferences]
|
|
theme='${GTK_THEME}'
|
|
|
|
[org/cinnamon/theme]
|
|
name='${GTK_THEME}'
|
|
|
|
[org/cinnamon/desktop/background]
|
|
picture-uri='file:///usr/share/backgrounds/void-installer/${WALLPAPER_FILE}'
|
|
picture-options='zoom'
|
|
|
|
[org/gnome/desktop/background]
|
|
picture-uri='file:///usr/share/backgrounds/void-installer/${WALLPAPER_FILE}'
|
|
picture-options='zoom'
|
|
|
|
[org/gnome/desktop/input-sources]
|
|
sources=[('xkb', '${KEYMAP//-/+}')]
|
|
|
|
[org/gnome/desktop/interface]
|
|
color-scheme='prefer-dark'
|
|
|
|
[org/cinnamon/desktop/default-applications/terminal]
|
|
exec='alacritty'
|
|
exec-arg='-e'
|
|
|
|
[org/gnome/desktop/default-applications/terminal]
|
|
exec='alacritty'
|
|
exec-arg='-e'
|
|
|
|
[org/cinnamon/desktop/keybindings/custom-keybindings/custom0]
|
|
name='Open Terminal'
|
|
command='${DEFAULT_TERMINAL:-alacritty}'
|
|
binding=['<Primary><Alt>t']
|
|
EOF
|
|
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/dconf/db/local.d/locks"
|
|
cat > "$INCLUDE_DIR/etc/dconf/db/local.d/locks/keyboard" <<'EOF'
|
|
/org/gnome/desktop/input-sources/sources
|
|
/org/cinnamon/desktop/default-applications/terminal/exec
|
|
/org/cinnamon/desktop/default-applications/terminal/exec-arg
|
|
/org/gnome/desktop/default-applications/terminal/exec
|
|
/org/gnome/desktop/default-applications/terminal/exec-arg
|
|
EOF
|
|
|
|
# Nemo: "Open in VS Code" action
|
|
install -d -m 0755 "$INCLUDE_DIR/usr/share/nemo/actions"
|
|
install -d -m 0755 "$INCLUDE_DIR/usr/local/bin"
|
|
cat > "$INCLUDE_DIR/usr/local/bin/code-open" <<'EOF'
|
|
#!/bin/sh
|
|
for d in "/home/live/.nix-profile/bin" /nix/var/nix/profiles/per-user/live/profile/bin \
|
|
/usr/local/bin /usr/bin; do
|
|
if [ -x "$d/code" ]; then exec "$d/code" "$@"; fi
|
|
done
|
|
exec code "$@"
|
|
EOF
|
|
chmod 0755 "$INCLUDE_DIR/usr/local/bin/code-open"
|
|
cat > "$INCLUDE_DIR/usr/share/nemo/actions/open-in-vscode.nemo_action" <<'EOF'
|
|
[Nemo Action]
|
|
Name=Open in VS _Code
|
|
Comment=Open in Visual Studio Code
|
|
Exec=/usr/local/bin/code-open %F
|
|
Icon-Name=code
|
|
Selection=Any
|
|
Extensions=any;
|
|
Dependencies=/usr/local/bin/code-open;
|
|
EOF
|
|
|
|
# apply-live-settings.sh: runs once at first Cinnamon login
|
|
install -d -m 0755 "$INCLUDE_DIR/usr/local/libexec" \
|
|
"$INCLUDE_DIR/etc/xdg/autostart"
|
|
# shellcheck disable=SC2154
|
|
cat > "$INCLUDE_DIR/usr/local/libexec/apply-live-settings.sh" <<APPLYEOF
|
|
#!/bin/bash
|
|
DONE="\$HOME/.void-live-settings-done"
|
|
[[ -f "\$DONE" ]] && exit 0
|
|
for _i in \$(seq 15); do
|
|
[[ -n "\${DBUS_SESSION_BUS_ADDRESS:-}" ]] && break
|
|
eval "\$(dbus-launch --sh-syntax 2>/dev/null)" || true; sleep 0.3
|
|
done
|
|
gsettings set org.cinnamon.desktop.interface gtk-theme '${GTK_THEME}'
|
|
gsettings set org.cinnamon.desktop.interface icon-theme '${ICON_THEME}'
|
|
gsettings set org.gnome.desktop.interface cursor-theme '${CURSOR_THEME}'
|
|
gsettings set org.cinnamon.theme name '${GTK_THEME}'
|
|
_WP=\$(ls /usr/share/backgrounds/void-installer/*.jpg 2>/dev/null | head -1 || true)
|
|
[[ -n "\$_WP" ]] && gsettings set org.cinnamon.desktop.background picture-uri "file://\$_WP"
|
|
[[ -n "\$_WP" ]] && gsettings set org.gnome.desktop.background picture-uri "file://\$_WP"
|
|
gsettings set org.cinnamon.desktop.default-applications.terminal exec '${DEFAULT_TERMINAL:-alacritty}'
|
|
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-arg '-e'
|
|
gsettings set org.gnome.desktop.input-sources sources "[('xkb', '${KEYMAP//-/+}')]"
|
|
touch "\$DONE"
|
|
APPLYEOF
|
|
chmod 0755 "$INCLUDE_DIR/usr/local/libexec/apply-live-settings.sh"
|
|
cat > "$INCLUDE_DIR/etc/xdg/autostart/void-live-settings.desktop" <<'DESK'
|
|
[Desktop Entry]
|
|
Type=Application
|
|
Name=Void Live Apply Settings
|
|
Exec=/usr/local/libexec/apply-live-settings.sh
|
|
NoDisplay=true
|
|
X-GNOME-Autostart-enabled=true
|
|
OnlyShowIn=X-Cinnamon;
|
|
DESK
|
|
}
|
|
|
|
_stage_live_niri() {
|
|
# live-setup.sh: groups, sudo, DNS, sound, XDG_RUNTIME_DIR
|
|
cat > "$INCLUDE_DIR/etc/runit/live-setup.sh" <<SV_EOF
|
|
#!/bin/sh
|
|
LIVE_USER="\${USERNAME:-live}"
|
|
[ -f /etc/default/live.conf ] && . /etc/default/live.conf
|
|
LIVE_USER="\${LIVE_USER:-live}"
|
|
|
|
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
|
|
|
|
[ -f /etc/nsswitch.conf ] && sed -i '/^hosts:/s/mdns[^ ]* *//g' /etc/nsswitch.conf
|
|
|
|
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
|
|
|
|
_UID=\$(id -u "\$LIVE_USER" 2>/dev/null || echo 1000)
|
|
XDG_RUN="/run/user/\$_UID"
|
|
install -d -m 0700 "\$XDG_RUN" 2>/dev/null || true
|
|
chown "\$LIVE_USER" "\$XDG_RUN" 2>/dev/null || true
|
|
|
|
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
|
|
|
|
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"
|
|
|
|
# greetd config (tty2 TUI fallback greeter)
|
|
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
|
|
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
|
|
|
|
# noctalia xbps repo appended to the common repos file
|
|
cat >> "$INCLUDE_DIR/etc/xbps.d/00-void-repos.conf" <<'EOF'
|
|
repository=https://universalrepo.r1xelelo.workers.dev/void
|
|
EOF
|
|
|
|
# Wayland environment
|
|
cat > "$INCLUDE_DIR/etc/profile.d/wayland.sh" <<'EOF'
|
|
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 LIBSEAT_BACKEND=logind
|
|
export GTK_USE_PORTAL=1
|
|
export ELECTRON_OZONE_PLATFORM_HINT=auto
|
|
EOF
|
|
chmod 0644 "$INCLUDE_DIR/etc/profile.d/wayland.sh"
|
|
|
|
# elogind custom sv (waits for dbus socket, avoids restart spam)
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/sv/elogind"
|
|
cat > "$INCLUDE_DIR/etc/sv/elogind/run" <<'EOF'
|
|
#!/bin/sh
|
|
exec 2>&1
|
|
_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
|
|
}
|
|
_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_alive || _login1_on_dbus; then
|
|
echo "elogind-sv: already running — yielding"
|
|
exec tail -f /dev/null
|
|
fi
|
|
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"
|
|
cat > "$INCLUDE_DIR/etc/sv/elogind/finish" <<'EOF'
|
|
#!/bin/sh
|
|
if [ "$1" != "0" ] && [ "$2" = "-1" ]; then sleep 10; else sleep 3; fi
|
|
EOF
|
|
chmod 0755 "$INCLUDE_DIR/etc/sv/elogind/finish"
|
|
|
|
# runit services
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/runit/runsvdir/default"
|
|
for svc in dbus elogind NetworkManager bluetoothd sshd; do
|
|
ln -sf "/etc/sv/$svc" "$INCLUDE_DIR/etc/runit/runsvdir/default/$svc"
|
|
done
|
|
|
|
# niri skel config (dracut copies skel → /home/live at boot)
|
|
local KEYMAP_XKB_LAYOUT="${KEYMAP%%-*}"
|
|
local KEYMAP_XKB_VARIANT="${KEYMAP#*-}"
|
|
KEYMAP_XKB_VARIANT="${KEYMAP_XKB_VARIANT//_nodeadkeys/}"
|
|
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/skel/.config/niri"
|
|
# shellcheck disable=SC2154
|
|
cat > "$INCLUDE_DIR/etc/skel/.config/niri/config.kdl" <<EOF
|
|
// niri config — generated by void-installer (${PROFILE} 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
|
|
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; }
|
|
spawn-at-startup "pipewire"
|
|
spawn-at-startup "pipewire-pulse"
|
|
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"
|
|
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"
|
|
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"
|
|
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
|
|
|
|
# dconf dark theme (GTK apps under niri still read dconf)
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/dconf/db/local.d" \
|
|
"$INCLUDE_DIR/etc/dconf/profile"
|
|
cat > "$INCLUDE_DIR/etc/dconf/profile/user" <<'EOF'
|
|
user-db:user
|
|
system-db:local
|
|
EOF
|
|
cat > "$INCLUDE_DIR/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
|
|
|
|
# noctalia defaults in skel
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/skel/.config/noctalia"
|
|
cat > "$INCLUDE_DIR/etc/skel/.config/noctalia/settings.json" <<'NOCEOF'
|
|
{
|
|
"colorSchemes": { "darkMode": true, "predefinedScheme": "Gruvbox" },
|
|
"wallpaper": {
|
|
"enabled": true,
|
|
"directory": "/usr/share/backgrounds/void-installer",
|
|
"fillMode": "crop"
|
|
}
|
|
}
|
|
NOCEOF
|
|
}
|
|
|
|
# ═════════════════════════════════════════════════════════════════════════════
|
|
# MAIN EXECUTION
|
|
# ═════════════════════════════════════════════════════════════════════════════
|
|
|
|
echo ">>> building ${BUILD_TYPE} ISO"
|
|
echo " profile : ${PROFILE} — ${PROFILE_DESC:-}"
|
|
echo " kernel : ${KERNEL_PKG}"
|
|
echo " desktop : ${DESKTOP} (${DISPLAY_SERVER})"
|
|
|
|
# 1) clone + patch mklive
|
|
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
|
|
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) stage overlay
|
|
echo ">>> staging includes overlay at $INCLUDE_DIR"
|
|
chmod -R u+rwX "$INCLUDE_DIR" 2>/dev/null || true
|
|
rm -rf "$INCLUDE_DIR"
|
|
mkdir -p "$INCLUDE_DIR"
|
|
|
|
# 3a) Installer scripts + profiles (always present in both ISO types)
|
|
install -d -m 0755 "$INCLUDE_DIR/usr/local/share/installer/lib"
|
|
install -m 0644 "$PROJECT_DIR/config/install.conf" \
|
|
"$INCLUDE_DIR/usr/local/share/installer/install.conf"
|
|
install -m 0644 "$PROJECT_DIR/config/profiles/stable-cinnamon/packages.list" \
|
|
"$INCLUDE_DIR/usr/local/share/installer/packages.list"
|
|
install -m 0755 "$PROJECT_DIR/installer/install.sh" \
|
|
"$INCLUDE_DIR/usr/local/share/installer/install.sh"
|
|
for f in "$PROJECT_DIR"/installer/lib/*.sh; do
|
|
install -m 0755 "$f" "$INCLUDE_DIR/usr/local/share/installer/lib/$(basename "$f")"
|
|
done
|
|
install -d -m 0755 "$INCLUDE_DIR/usr/local/share/installer/profiles"
|
|
cp -a "$PROJECT_DIR/config/profiles/." "$INCLUDE_DIR/usr/local/share/installer/profiles/"
|
|
|
|
install -d -m 0755 "$INCLUDE_DIR/usr/local/sbin"
|
|
ln -sf /usr/local/share/installer/install.sh "$INCLUDE_DIR/usr/local/sbin/install-void"
|
|
|
|
# 3b) DEFAULT_PROFILE env marker — the embedded installer defaults to this profile
|
|
install -d -m 0755 "$INCLUDE_DIR/etc/profile.d"
|
|
cat > "$INCLUDE_DIR/etc/profile.d/00-void-installer.sh" <<PROFEOF
|
|
# Default installer profile — set at ISO build time to match this live session.
|
|
export DEFAULT_PROFILE="${PROFILE}"
|
|
PROFEOF
|
|
chmod 0644 "$INCLUDE_DIR/etc/profile.d/00-void-installer.sh"
|
|
|
|
# 3c) Secrets + SSH keys
|
|
install -d -m 0700 "$INCLUDE_DIR/etc"
|
|
{
|
|
printf "USER_PASSWORD=%q\n" "$USER_PASSWORD"
|
|
printf "ROOT_PASSWORD=%q\n" "$ROOT_PASSWORD"
|
|
} > "$INCLUDE_DIR/etc/installer-secrets.env"
|
|
chmod 0600 "$INCLUDE_DIR/etc/installer-secrets.env"
|
|
|
|
install -d -m 0700 "$INCLUDE_DIR/etc/installer-ssh"
|
|
cp -a "$SSH_SRC_DIR"/. "$INCLUDE_DIR/etc/installer-ssh/"
|
|
find "$INCLUDE_DIR/etc/installer-ssh" -type f -exec chmod 0600 {} +
|
|
find "$INCLUDE_DIR/etc/installer-ssh" -type d -exec chmod 0700 {} +
|
|
|
|
# 3d) Customizations overlay (themes / icons / wallpapers / dotfiles / vscode)
|
|
OVERLAY="$INCLUDE_DIR/etc/installer-overlay"
|
|
install -d -m 0755 "$OVERLAY" "$OVERLAY/wallpapers" "$OVERLAY/themes" \
|
|
"$OVERLAY/icons" "$OVERLAY/skel" "$OVERLAY/vscode-user"
|
|
|
|
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)"
|
|
|
|
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" || echo " (warning: could not clone theme repo)"
|
|
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
|
|
' || echo " (warning: theme build failed)"
|
|
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
|
|
|
|
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" || echo " (warning: could not clone icon repo)"
|
|
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_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"
|
|
else
|
|
echo " (warning: $BIBATA_SRC missing — cursor theme skipped)"
|
|
fi
|
|
|
|
DOTFILES_SRC="${DOTFILES_SRC:-$HOME}"
|
|
for f in .bashrc .bash_aliases .gitconfig; do
|
|
[[ -r "$DOTFILES_SRC/$f" ]] && install -m 0644 "$DOTFILES_SRC/$f" "$OVERLAY/skel/$f"
|
|
done
|
|
|
|
VSCODE_SRC="${VSCODE_USER_SRC:-$HOME/.config/Code/User}"
|
|
if [[ -d "$VSCODE_SRC" ]]; then
|
|
for f in settings.json keybindings.json mcp.json tasks.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"
|
|
[[ -d "$VSCODE_SRC/globalStorage" ]] && cp -a "$VSCODE_SRC/globalStorage" "$OVERLAY/vscode-user/globalStorage"
|
|
fi
|
|
command -v code >/dev/null 2>&1 && \
|
|
code --list-extensions > "$OVERLAY/vscode-extensions.txt" 2>/dev/null || true
|
|
|
|
CLAUDE_SRC="${CLAUDE_SRC:-$HOME/.claude}"
|
|
[[ -d "$CLAUDE_SRC" ]] && cp -a "$CLAUDE_SRC" "$OVERLAY/claude"
|
|
[[ -r "${HOME}/.claude.json" ]] && install -m 0600 "${HOME}/.claude.json" "$OVERLAY/claude.json"
|
|
|
|
[[ -r "$PROJECT_DIR/installer/first-login.sh" ]] && \
|
|
install -m 0755 "$PROJECT_DIR/installer/first-login.sh" "$OVERLAY/first-login.sh"
|
|
|
|
install -d -m 0755 "$INCLUDE_DIR/usr/local/libexec"
|
|
{
|
|
printf '# Nix user packages\n'
|
|
printf '%s\n' "${NIX_USER_PACKAGES[@]}"
|
|
} > "$INCLUDE_DIR/usr/local/libexec/nix-packages.list"
|
|
|
|
# 3e) Type-specific + DE-specific overlay (uses functions defined above)
|
|
if [[ "$BUILD_TYPE" == "installer" ]]; then
|
|
_stage_installer_overlay
|
|
else
|
|
_stage_live_overlay
|
|
fi
|
|
|
|
# 4) package list for ISO
|
|
if [[ "$BUILD_TYPE" == "installer" ]]; then
|
|
ISO_PKGS=$(grep -vE '^\s*(#|$)' "$PROJECT_DIR/config/packages.live.list" | tr '\n' ' ')
|
|
else
|
|
# Prefer new canonical name, fall back to old name for existing profiles
|
|
_PKG_LIST="$PROFILE_DIR/packages.live.list"
|
|
[[ -f "$_PKG_LIST" ]] || _PKG_LIST="$PROFILE_DIR/packages.live-desktop.list"
|
|
[[ -f "$_PKG_LIST" ]] || { echo "ERROR: no packages.live.list found in $PROFILE_DIR"; exit 1; }
|
|
ISO_PKGS=$(grep -vE '^\s*(#|$)' "$_PKG_LIST" | tr '\n' ' ')
|
|
fi
|
|
|
|
# 5) output filename
|
|
TS="$(date -u +%Y%m%d)"
|
|
case "$BUILD_TYPE" in
|
|
installer) OUT_ISO="${OUTPUT_ISO:-$OUT_DIR/void-install-${PROFILE}-${TS}.iso}" ;;
|
|
live) OUT_ISO="${OUTPUT_ISO:-$OUT_DIR/void-live-${PROFILE}-${TS}.iso}" ;;
|
|
esac
|
|
|
|
# 6) boot cmdline
|
|
_BOOT_BASE="nvidia-drm.modeset=1 rd.driver.blacklist=nouveau modprobe.blacklist=nouveau btusb.enable_autosuspend=0"
|
|
if [[ "$BUILD_TYPE" == "live" ]]; then
|
|
BOOT_CMDLINE="${BOOT_CMDLINE:-live.user=${LIVE_USER} console=tty0 console=ttyS0,115200 ${_BOOT_BASE}}"
|
|
else
|
|
BOOT_CMDLINE="${BOOT_CMDLINE:-${_BOOT_BASE}}"
|
|
fi
|
|
|
|
# 7) ISO title
|
|
case "${BUILD_TYPE}-${DESKTOP}" in
|
|
installer-*) ISO_TITLE="Void Installer (${PROFILE})" ;;
|
|
live-cinnamon) ISO_TITLE="Void Live — Cinnamon (${KERNEL_PKG})" ;;
|
|
live-niri) ISO_TITLE="Void Live — niri / noctalia-shell (${KERNEL_PKG})" ;;
|
|
*) ISO_TITLE="Void Linux (${PROFILE})" ;;
|
|
esac
|
|
|
|
# 8) build docker image
|
|
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
|
|
|
|
# 9) noctalia repo (niri profiles only)
|
|
NOCTALIA_REPO=""
|
|
[[ "$DESKTOP" == "niri" ]] && \
|
|
NOCTALIA_REPO="${NOCTALIA_REPO:-https://universalrepo.r1xelelo.workers.dev/void}"
|
|
|
|
# 10) nix prebake packages (live ISOs only)
|
|
NIX_PREBAKE_PKGS=""
|
|
[[ "$BUILD_TYPE" == "live" ]] && NIX_PREBAKE_PKGS="${NIX_USER_PACKAGES[*]}"
|
|
|
|
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="$ISO_TITLE" \
|
|
-e OUT_ISO_REL="${OUT_ISO#$PROJECT_DIR/}" \
|
|
-e INCLUDE_DIR_REL="${INCLUDE_DIR#$PROJECT_DIR/}" \
|
|
-e BUILD_TYPE="$BUILD_TYPE" \
|
|
-e DESKTOP="$DESKTOP" \
|
|
-e KERNEL_PKG="${KERNEL_PKG:-linux}" \
|
|
-e NOCTALIA_REPO="$NOCTALIA_REPO" \
|
|
-e NIX_PACKAGES_PREBAKE="$NIX_PREBAKE_PKGS" \
|
|
-e BOOT_CMDLINE="${BOOT_CMDLINE:-}" \
|
|
-e HOST_UID="$(id -u)" \
|
|
-e HOST_GID="$(id -g)" \
|
|
"$DOCKER_IMAGE" \
|
|
bash /work/iso/_inner-build-unified.sh
|
|
|
|
echo
|
|
echo ">>> ISO built: $OUT_ISO"
|
|
sha256sum "$OUT_ISO" | tee "${OUT_ISO}.sha256" || true
|