feat: add live desktop ISO build (stable-cinnamon Cinnamon live session)

This commit is contained in:
mozempk
2026-04-23 00:02:21 +02:00
parent a16ac37d20
commit 6269f2f877
4 changed files with 555 additions and 1 deletions

View File

@@ -2,6 +2,7 @@
#
# Targets:
# make iso build the auto-installing ISO (uses docker)
# make live build the full Cinnamon live desktop ISO
# make test-disk create a fresh QEMU test disk that mimics XPS 17 layout
# make test full automated QEMU smoke test
# make test-iso rebuild only the TEST ISO variant
@@ -14,7 +15,7 @@ PROJECT_DIR := $(CURDIR)
OUT := $(PROJECT_DIR)/out
SECRETS := $(PROJECT_DIR)/secrets.env
.PHONY: all iso test test-disk test-iso qemu shellcheck clean distclean check-secrets check-docker
.PHONY: all iso live test test-disk test-iso qemu shellcheck clean distclean check-secrets check-docker
all: iso
@@ -28,6 +29,9 @@ check-docker:
iso: check-secrets check-docker
$(PROJECT_DIR)/iso/build-iso.sh
live: check-secrets check-docker
$(PROJECT_DIR)/iso/build-live-iso.sh
test-iso: check-secrets check-docker
REBUILD_ISO=1 $(PROJECT_DIR)/tests/run-qemu-test.sh
@@ -48,6 +52,8 @@ shellcheck:
$(PROJECT_DIR)/installer/lib/*.sh \
$(PROJECT_DIR)/iso/build-iso.sh \
$(PROJECT_DIR)/iso/_inner-build.sh \
$(PROJECT_DIR)/iso/_inner-build-live.sh \
$(PROJECT_DIR)/iso/build-live-iso.sh \
$(PROJECT_DIR)/tests/*.sh \
$(PROJECT_DIR)/tests/lib/*.sh

View File

@@ -0,0 +1,146 @@
# Packages included in the LIVE desktop ISO squashfs.
# This is the full stable-cinnamon desktop environment — the live session
# boots directly into Cinnamon so you can test on real hardware.
# (Separate from packages.list which is the target-install list.)
# --- base / boot ---
base-system
linux
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
# --- networking ---
NetworkManager
NetworkManager-openvpn
openssh
iwd
wpa_supplicant
chrony
# --- audio ---
pipewire
wireplumber
alsa-pipewire
pavucontrol
alsa-utils
# --- 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
# --- terminal ---
alacritty
# --- gtk theming deps ---
sassc
gnome-themes-extra
gtk-engine-murrine
dconf
dconf-editor
# --- 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
# --- bluetooth ---
bluez-alsa
# --- live session utils ---
dialog
ncurses
util-linux

65
iso/_inner-build-live.sh Executable file
View File

@@ -0,0 +1,65 @@
#!/bin/bash
# Runs INSIDE the docker container (as root). Invoked by iso/build-live-iso.sh.
# Expects the project bind-mounted at /work and the cache at /cache.
#
# Required env (set by build-live-iso.sh):
# ARCH, REPO_URL, KEYMAP, LOCALE, ISO_PKGS, ISO_TITLE, OUT_ISO_REL,
# INCLUDE_DIR_REL
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"
INCLUDE_DIR="$PROJECT_DIR/$INCLUDE_DIR_REL"
OUT_ISO="$PROJECT_DIR/$OUT_ISO_REL"
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")"
# Compile dconf system-db inside the include dir so it ships compiled.
if command -v dconf >/dev/null 2>&1 && [[ -d "$INCLUDE_DIR/etc/dconf/db/local.d" ]]; then
DCONF_PROFILE_PATH="$INCLUDE_DIR/etc/dconf/profile" \
DCONF_SYSTEM_DB_PATH="$INCLUDE_DIR/etc/dconf/db" \
dconf update "$INCLUDE_DIR/etc/dconf/db" 2>/dev/null || true
fi
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
./mklive.sh \
-a "$ARCH" \
-r "$REPO_URL" \
-c "$CACHE_DIR/xbps-live-pkgs" \
-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"
chown "$(stat -c '%u:%g' "$PROJECT_DIR")" "$OUT_ISO" "${OUT_ISO}".* 2>/dev/null || true

337
iso/build-live-iso.sh Executable file
View File

@@ -0,0 +1,337 @@
#!/bin/bash
# Build a full Cinnamon LIVE desktop ISO for testing on real hardware.
#
# Boots directly into a Cinnamon session as user 'live' (no password).
# All themes, icons, cursor, wallpapers, dotfiles and VS Code config are
# pre-applied from the same overlay used by the installer.
#
# Requires (host): bash, git, curl, docker, and Bibata-Modern-Ice cursor
# installed at /usr/share/icons/Bibata-Modern-Ice.
#
# Usage:
# iso/build-live-iso.sh
# OUTPUT_ISO=/path/to/output.iso iso/build-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/live-includes"
MKLIVE_DIR="$CACHE_DIR/void-mklive"
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 profile defaults (GTK_THEME, CURSOR_THEME, ICON_THEME etc.)
# shellcheck disable=SC1091
source "$PROJECT_DIR/config/profiles/stable-cinnamon/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
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) build includes overlay
echo ">>> staging live includes overlay at $INCLUDE_DIR"
rm -rf "$INCLUDE_DIR"
mkdir -p "$INCLUDE_DIR"
# ── 3a) live user account ───────────────────────────────────────────────
# Create user 'live' with no password in the live image.
# mklive populates /etc/passwd at install time — we drop a post-install hook
# via the live init that calls useradd. We use an install.conf.d override
# that mklive will source, plus an rc.local-style runit oneshot.
install -d -m 0755 "$INCLUDE_DIR/etc"
cat > "$INCLUDE_DIR/etc/passwd-live" <<EOF
# placeholder replaced at build time by _inner-build-live.sh
EOF
# rc.local equivalent: runit oneshot that creates the live user on first boot.
install -d -m 0755 "$INCLUDE_DIR/etc/runit/runsvdir/default"
install -d -m 0755 "$INCLUDE_DIR/etc/sv/live-user-setup"
cat > "$INCLUDE_DIR/etc/sv/live-user-setup/run" <<'SV_EOF'
#!/bin/sh
# Create the 'live' user (no password) and set up home directory.
# Runs once; removes itself from default runsvdir on completion.
set -e
if ! id live >/dev/null 2>&1; then
useradd -m -s /bin/bash -G wheel,audio,video,plugdev,input,network,docker live
passwd -d live
install -d -m 0700 /home/live/.ssh
# Apply skel dotfiles
if [ -d /etc/skel ]; then
cp -a /etc/skel/. /home/live/ 2>/dev/null || true
fi
chown -R live:live /home/live
fi
# Enable sudoers entry for live
if ! grep -q '^live ' /etc/sudoers 2>/dev/null; then
echo 'live ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers
fi
# Remove self from runsvdir so it doesn't restart
rm -f /etc/runit/runsvdir/default/live-user-setup
sv stop live-user-setup 2>/dev/null || true
SV_EOF
chmod 0755 "$INCLUDE_DIR/etc/sv/live-user-setup/run"
ln -sf /etc/sv/live-user-setup "$INCLUDE_DIR/etc/runit/runsvdir/default/live-user-setup"
# ── 3b) LightDM autologin ───────────────────────────────────────────────
install -d -m 0755 "$INCLUDE_DIR/etc/lightdm"
cat > "$INCLUDE_DIR/etc/lightdm/lightdm.conf" <<EOF
[Seat:*]
autologin-user=${LIVE_USER}
autologin-user-timeout=0
user-session=cinnamon
greeter-session=lightdm-gtk-greeter
EOF
install -d -m 0755 "$INCLUDE_DIR/etc/runit/runsvdir/default"
# Enable NetworkManager, lightdm, pipewire and dbus for the live session.
for svc in dbus NetworkManager lightdm; do
ln -sf "/etc/sv/$svc" "$INCLUDE_DIR/etc/runit/runsvdir/default/$svc" 2>/dev/null || true
done
# ── 3c) Themes / icons / wallpapers (same as installer) ─────────────────
echo ">>> staging customizations overlay"
OVERLAY="$INCLUDE_DIR/etc/installer-overlay"
install -d -m 0755 "$OVERLAY" "$OVERLAY/wallpapers" \
"$OVERLAY/themes" "$OVERLAY/icons" \
"$OVERLAY/skel" "$OVERLAY/vscode-user"
# 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" | wc -l) file(s)"
# Gruvbox GTK theme
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
# Dotfiles
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
# VS Code user config
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
if command -v code >/dev/null 2>&1; then
code --list-extensions > "$OVERLAY/vscode-extensions.txt" 2>/dev/null || true
fi
# Claude config
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"
# first-login.sh
[[ -r "$PROJECT_DIR/installer/first-login.sh" ]] && \
install -m 0755 "$PROJECT_DIR/installer/first-login.sh" "$OVERLAY/first-login.sh"
# ── 3d) Pre-apply themes/dconf to the live user's home via /etc/skel ────
# We pre-write the dconf system-db so it takes effect without a user build step.
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")
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', 'ch+fr')]
[org/cinnamon/desktop/keybindings/custom-keybindings/custom0]
name='Open Terminal'
command='${DEFAULT_TERMINAL:-alacritty}'
binding=['<Primary><Alt>t']
EOF
# ── 3e) Copy themes/icons/wallpapers directly into usr/share ────────────
# (dconf compile happens inside the Docker container — see _inner-build-live.sh)
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
# ── 3f) first-login autostart + profile.d for the live user ─────────────
install -d -m 0755 "$INCLUDE_DIR/etc/xdg/autostart"
if [[ -r "$OVERLAY/first-login.sh" ]]; then
install -d -m 0755 "$INCLUDE_DIR/usr/local/libexec"
install -m 0755 "$OVERLAY/first-login.sh" "$INCLUDE_DIR/usr/local/libexec/first-login.sh"
cat > "$INCLUDE_DIR/etc/xdg/autostart/void-live-first-login.desktop" <<EOF
[Desktop Entry]
Type=Application
Name=Void Live First-Login Setup
Exec=/usr/local/libexec/first-login.sh
NoDisplay=true
X-GNOME-Autostart-enabled=true
OnlyShowIn=X-Cinnamon;
EOF
fi
install -d -m 0755 "$INCLUDE_DIR/etc/profile.d"
cat > "$INCLUDE_DIR/etc/profile.d/local-bin.sh" <<'EOF'
case ":$PATH:" in
*":$HOME/.local/bin:"*) ;;
*) export PATH="$HOME/.local/bin:$PATH" ;;
esac
EOF
# ── 3g) Live-session skel: pre-wire .bash_profile for first-login ────────
install -d -m 0755 "$INCLUDE_DIR/etc/skel"
cat > "$INCLUDE_DIR/etc/skel/.bash_profile" <<'EOF'
# Source .bashrc for interactive login shells.
[[ -f ~/.bashrc ]] && . ~/.bashrc
# Auto-run user environment setup on first interactive login.
if [[ -z "$_FIRST_LOGIN_RAN" && -x /usr/local/libexec/first-login.sh \
&& ! -f "$HOME/.first-login-done" ]]; then
export _FIRST_LOGIN_RAN=1
/usr/local/libexec/first-login.sh 2>&1 | tee -a "$HOME/.first-login.log"
fi
EOF
# 4) 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
# 5) packages + output filename
ISO_PKGS=$(grep -vE '^\s*(#|$)' \
"$PROJECT_DIR/config/profiles/stable-cinnamon/packages.live-desktop.list" \
| tr '\n' ' ')
TS="$(date -u +%Y%m%d)"
OUT_ISO="${OUTPUT_ISO:-$OUT_DIR/void-live-stable-${TS}.iso}"
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:-ch-fr_nodeadkeys}" \
-e LOCALE="${LOCALE:-en_US.UTF-8}" \
-e ISO_PKGS="$ISO_PKGS" \
-e ISO_TITLE="Void Live (${GTK_THEME} / Cinnamon)" \
-e OUT_ISO_REL="${OUT_ISO#$PROJECT_DIR/}" \
-e BOOT_CMDLINE="${BOOT_CMDLINE:-}" \
-e INCLUDE_DIR_REL="${INCLUDE_DIR#$PROJECT_DIR/}" \
-e HOST_UID="$(id -u)" \
-e HOST_GID="$(id -g)" \
"$DOCKER_IMAGE" \
bash /work/iso/_inner-build-live.sh
echo
echo ">>> Live ISO built: $OUT_ISO"
sha256sum "$OUT_ISO" | tee "${OUT_ISO}.sha256"