Building and testing
Requirements
Section titled “Requirements”- A Debian 13 (trixie) host. Other distros’
live-buildversions differ and may produce broken images. On another OS, use a trixie VM or container. - Root access (
sudo). live-build useschrootandmount. - ~15 GB free disk and an internet connection. Packages download from
deb.debian.org.
Install the tools once:
sudo apt install live-build debhelper dpkg-dev devscripts reprepro wget \ qemu-system-x86 qemu-utils ovmf xorriso \ meson pkgconf gettext libgtk-3-dev \ libgtk-layer-shell-dev libjson-c-dev libwayland-dev wayland-protocols| Tool | Used for |
|---|---|
live-build |
Building the ISO (lb command) |
debhelper, dpkg-dev |
Building .deb packages |
devscripts |
dch for editing debian/changelog |
reprepro |
Managing the apt repository |
wget |
Required by live-build’s firmware step |
qemu-system-x86, qemu-utils, ovmf |
Testing in a VM (qemu-img for disks, OVMF for UEFI) |
xorriso |
Extracting the kernel from the ISO for the headless boot test |
meson, pkgconf, gettext, lib…-dev, wayland-protocols |
Compiling sfwbar, the only FlickOS package with C code (its Build-Depends) |
For KVM acceleration (much faster VMs), add yourself to the kvm group once:
sudo adduser $USER kvm, then log out and back in.
The three scripts
Section titled “The three scripts”| Script | Does |
|---|---|
tools/build-iso.sh |
Clean → build FlickOS packages → lb config → lb build → SHA256SUMS |
tools/boot-test.py |
Boots the ISO headless, logs in over the serial console, runs checks |
tools/test-iso.sh |
Opens the ISO or a test install in a QEMU window for hands-on testing |
A normal development loop:
tools/build-iso.sh && tools/boot-test.py && tools/test-iso.shBuilding: tools/build-iso.sh
Section titled “Building: tools/build-iso.sh”tools/build-iso.sh # normal build; keeps the package download cachetools/build-iso.sh --purge # also deletes the cache (releases, or when builds act strangely)Run it as your normal user. It asks for your sudo password once at the start. When run as root (in CI), it skips sudo.
Output in the repository root:
| File | What it is |
|---|---|
FlickOS-64bit-v2.0.iso |
The bootable image |
SHA256SUMS |
Checksum of the ISO |
build.log |
Full output of the package build, lb config and lb build. Check it when something fails |
flickos-amd64.packages |
Every package and version in the image |
flickos-amd64.contents |
Every file in the image |
live-build writes flickos-amd64.hybrid.iso (from --image-name flickos in
auto/config). The script then renames it to FlickOS-64bit-vVERSION.iso, the
naming used on SourceForge since FlickOS 1.x, with VERSION taken from
packages/flickos-branding/usr/lib/flickos-release
(06 – The version number).
Before building, the script checks the installer’s branding.desc shows the same
version, and stops with Version mismatch if not. When cleaning, it deletes
older FlickOS-64bit-v*.iso files, since each is over 2 GB.
What the script does, step by step
Section titled “What the script does, step by step”You can run these by hand if you need to debug a single step:
sudo lb clean # 1. (add --purge to also drop cache/)sh packages/build.sh # 2.lb config # 3.sudo lb build # 4.sudo lb cleanrunsauto/clean. It removeschroot/,binary/, the stage files in.build/and the config fileslb configgenerated. It keepscache/(downloaded.debfiles) unless you pass--purge. Without cleaning,lb buildskips stages it thinks are already done, and your changes don’t make it into the image.packages/build.shbuilds everypackages/*/source package withdpkg-buildpackagein a scratch copy (packages/.build/), then copies the.debfiles intoconfig/packages.chroot/. live-build turns that folder into a temporary local apt repo during the build, soflickos-desktopcan be installed by name.lb configrunsauto/config, which callslb config noautowith all of FlickOS’s options. This writesconfig/common,config/bootstrap,config/chroot,config/binaryandconfig/source.sudo lb buildruns three stages:- bootstrap:
debootstrapcreates a minimal Debian system inchroot/. - chroot: adds apt sources, installs everything in
config/package-lists/, runsconfig/hooks/, then removes the build-only apt sources. - binary: compresses
chroot/into a squashfs, adds kernel, initrd and bootloaders, and writes the ISO.
- bootstrap:
Automated testing: tools/boot-test.py
Section titled “Automated testing: tools/boot-test.py”tools/boot-test.py # test the newest FlickOS-64bit-v*.isotools/boot-test.py --verbose # also print the serial console livetools/boot-test.py --iso some.iso # test a specific ISOtools/boot-test.py --strict # fail if any systemd unit failedtools/boot-test.py --timeout 900 # wait longer for the login prompttools/boot-test.py --max-used-mb 900 # also fail if the idle desktop uses more memoryIt needs no window and no interaction. The same script runs in CI.
How it works
Section titled “How it works”- Extracts the boot files from the ISO with
xorriso: the kernel, the initrd and the kernel command line from the first entry of/isolinux/live.cfg(or/boot/grub/grub.cfg). - Boots them directly with QEMU, skipping the bootloader. The live boot
menus wait for a keypress, so they can’t be automated. The command line is the
ISO’s own, minus
quiet splash, plusconsole=tty0 console=ttyS0,115200, so kernel and systemd messages and a login prompt appear on the serial port. The ISO is still attached as a CD, which is where live-boot finds the system. - Logs in on the serial console as
user/live. The graphical session on tty1 (autologin + labwc) starts independently, just as on real hardware. - Waits for systemd (
systemctl is-system-running --wait).degraded(some unit failed) is a warning, or a failure with--strict. The failed units are printed. - Runs the checks from the
CHECKSlist at the top of the script. Each one is a shell command that must exit 0. Some retry for a while, because the desktop starts in the background. - Takes a screenshot of the virtual screen through QEMU’s QMP socket.
- Reports memory use:
MemTotal − MemAvailablefrom/proc/meminfo(memory the system can’t give back without swapping), plus the 15 largest processes. With--max-used-mb Nit also fails when more than N MB are in use.
The bootloaders themselves (syslinux, GRUB) are not covered. Test those by
hand with tools/test-iso.sh, at least before each release.
Results
Section titled “Results”Everything is printed as PASS/WARN/FAIL lines. Files in boot-test/:
| File | Contents |
|---|---|
serial.log |
Everything the guest printed on the serial console: kernel log, systemd messages, command output |
screen.png |
Screenshot of the desktop at the end. It should show labwc with waybar |
memory.txt |
Memory in use with the desktop idle, and the largest processes |
Reading the memory number: it’s measured in the live session, which runs
from RAM (changed files live in a RAM overlay), with nothing opened. An installed
system uses somewhat less. Compare releases against each other rather than
against other distributions. When the number grows noticeably, memory.txt
shows which process caused it. Once you’ve seen a few builds, set
--max-used-mb in the CI workflow a little above the usual value to catch regressions.
Exit codes: 0 all passed, 1 a check failed, 2 setup problem (missing
tool, no ISO), 3 never reached a login prompt, or login failed.
Timeouts: 300 s to reach the login prompt with KVM, 1200 s without. Check retry times are multiplied by 4 without KVM.
Adding a check
Section titled “Adding a check”Edit CHECKS in tools/boot-test.py:
CHECKS = [ ... ("bluetooth active", "systemctl is-active --quiet bluetooth", 30), ("firefox installed", "command -v firefox-esr", 0),]Each entry is (description, shell command, seconds to keep retrying).
Commands run as user in a bash login shell. sudo -n works without a password
in the live session. Use 0 for things that are already true at login, and a
retry time for services or desktop programs that start in the background.
Manual testing: tools/test-iso.sh
Section titled “Manual testing: tools/test-iso.sh”Opens a QEMU window. Always check a new ISO by hand before a release, on both firmware types, because they use different bootloaders (syslinux vs GRUB).
tools/test-iso.sh # live session, UEFItools/test-iso.sh --bios # live session, BIOStools/test-iso.sh --install # live session + persistent 20 G test disk (UEFI) → run the installertools/test-iso.sh --install --bios # same, BIOStools/test-iso.sh --disk # boot the installed test disk, no ISOtools/test-iso.sh --reset --install # throw away the old test disk and start overOptions: --iso FILE (default: newest FlickOS-64bit-v*.iso), --mem 8G
(default 4G), --size 40G (disk size when created, default 20G).
The test disk (disk.qcow2), its UEFI variables (OVMF_VARS.fd, which store
the boot entry Calamares creates) and the firmware used for installing are kept
in .test-vm/. --disk automatically uses the firmware the disk was installed
with. For plain live sessions, UEFI uses throwaway variables, so they never mess
up the test install.
With --install, the VM boots the ISO once. When Calamares finishes and
you choose restart, the VM boots from the installed disk.
What to check in the live session
Section titled “What to check in the live session”- FlickOS boot menu appears (logo, Start FlickOS), boots by itself after 10 s
- FlickOS boot splash (logo + spinner) instead of text, then labwc automatically
- waybar is visible, nm-applet shows, network works (
curl -I https://deb.debian.org) -
Super+Returnopens foot,Super+Dopens fuzzel,Super+Eopens pcmanfm - Right-click desktop shows the root menu
- Audio:
wpctl statuslists a sink -
apt updatesucceeds, which means the FlickOS repo is reachable and correctly signed -
apt policy flickos-desktopshows the FlickOS repo as a source - Keybindings:
Alt+Tab,Super+Arrows(snap), volume keys,Print(screenshot notification) - Right-click menu shows Install FlickOS; the installer opens with FlickOS branding and working links on its welcome page
- Office → Writer opens LibreOffice; a video file opens in VLC; play/pause key controls VLC
- Settings → Desktop Layout & Style opens the chooser in Arc-Dark with three previews; applying Cupertino, then Redmond, changes the panel and window buttons, and the network icon comes back
- Applying Light recolors GTK apps, icons, panel, window borders, the root menu, fuzzel, notifications (
notify-send Hi) and new foot windows; Dark switches back - Settings → Appearance opens nwg-look; a GTK theme chosen there (e.g. Adwaita) is kept when switching to Light and back
What to check on the installed system
Section titled “What to check on the installed system”- The graphical login screen appears (Arc-Dark, FlickOS wallpaper, clock), no autologin unless it was chosen in the installer
- The keyboard layout chosen in the installer works in the password field
- Logging in starts labwc; a wrong password shows an error and asks again
- Ctrl+Alt+F1 shows a text login prompt, and logging in there also starts labwc
- A second install with Log in automatically checked boots straight to the desktop (
getent group autologinlists the user) - The first login opens Desktop Layout & Style; choosing Cupertino and Light applies right away. After logging out and in, the chooser doesn’t open again and the choice is kept
-
sudo apt update && sudo apt upgradeworks -
cat /etc/apt/sources.list.d/flickos.sourcesshowsURIs: https://dvbondoy.github.io/flickos-apt -
dpkg -l 'live-*' flickos-installer calamaresshows they’re gone (Calamares removed them) - Right-click menu has no Install FlickOS entry
- The keyboard layout chosen in the installer works in foot
- Leaving the VM idle for 5 minutes locks the screen
- Boot shows the FlickOS splash; tty2 (Ctrl+Alt+F2) shows
FlickOS 2.0 (Debian 13)above the login prompt -
sudo ufw statusshowsStatus: active
Without the script
Section titled “Without the script”The equivalent raw QEMU commands, if you ever need to tweak something:
# BIOSqemu-system-x86_64 -enable-kvm -cpu host -m 4G -smp 2 -device virtio-vga \ -cdrom FlickOS-64bit-v2.0.iso
# UEFI with persistent variables and a test diskqemu-img create -f qcow2 disk.qcow2 20Gcp /usr/share/OVMF/OVMF_VARS_4M.fd vars.fdqemu-system-x86_64 -enable-kvm -cpu host -m 4G -smp 2 -device virtio-vga \ -drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE_4M.fd \ -drive if=pflash,format=raw,file=vars.fd \ -drive file=disk.qcow2,if=virtio \ -cdrom FlickOS-64bit-v2.0.iso -boot once=dWriting to a USB stick
Section titled “Writing to a USB stick”lsblk # find the USB device, e.g. /dev/sdXsudo dd if=FlickOS-64bit-v2.0.iso of=/dev/sdX bs=4M status=progress oflag=syncdd overwrites the target without asking. Check the device name twice.