All checks were successful
CI / lint (pull_request) Successful in 30s
CI / validate-json (pull_request) Successful in 24s
CI / markdown-links (pull_request) Successful in 16s
CI / test (pull_request) Successful in 1m47s
CI / lint (push) Successful in 28s
CI / test (push) Successful in 1m56s
CI / validate-json (push) Successful in 24s
CI / markdown-links (push) Successful in 21s
Deploy site / deploy (push) Successful in 5s
Build ISO / build-iso (push) Successful in 20m27s
The logo vote on furtka.org closed with M 29 · R 13 (42 votes). - website/tools/brand-assets.py generates every brand file from the logo-assets.py geometry: favicons (small-size tier, accent with a dark-mode variant) for website / webinstaller / on-box UI, 180 px apple-touch-icon, 1200x630 default share card, 640x480 syslinux splash, and docs/brand/ (mark, small mark, lockups, 20-column console art) - website: header mark, favicon, touch icon, default og:image; /logo/ now shows the final result (static counts, winner highlighted, no voting UI or poll.js); homepage link reads 'meet our new logo' - webinstaller: M in the header + tab icon - on-box UI: .brand mark via CSS mask in brand red (not the UI's green), favicon on every page, brand line on the login page - console: M art above the text of /etc/issue on the installed box (furtka-welcome) and the live ISO (furtka-update-issue) - ISO: build.sh swaps releng's Arch splash for the Furtka one - README shows the lockup Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wq1hzUp4ZmCKHDuLKCnu73
131 lines
6.3 KiB
Bash
Executable file
131 lines
6.3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Build a Furtka live ISO.
|
|
#
|
|
# From the repo root or from iso/ on any host with Docker:
|
|
# ./iso/build.sh
|
|
#
|
|
# The build runs inside a privileged `archlinux:latest` container because
|
|
# mkarchiso needs root + loop mounts + an Arch package manager, which
|
|
# Ubuntu doesn't provide natively. Output ISO goes to iso/out/.
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
OUT_DIR="$SCRIPT_DIR/out"
|
|
|
|
if [[ "${FURTKA_ISO_INNER:-0}" != "1" ]]; then
|
|
mkdir -p "$OUT_DIR"
|
|
echo "==> Launching build container"
|
|
exec docker run --rm --privileged \
|
|
-v "$REPO_ROOT:/work" \
|
|
-w /work \
|
|
-e FURTKA_ISO_INNER=1 \
|
|
archlinux:latest \
|
|
bash /work/iso/build.sh
|
|
fi
|
|
|
|
# ---- inside the container from here on ----
|
|
|
|
echo "==> Syncing pacman, installing archiso"
|
|
pacman -Syu --noconfirm --needed archiso
|
|
|
|
PROFILE_SRC="/usr/share/archiso/configs/releng"
|
|
PROFILE_WORK="/tmp/furtka-profile"
|
|
BUILD_WORK="/tmp/furtka-build"
|
|
OUT_IN_CONTAINER="/work/iso/out"
|
|
|
|
rm -rf "$PROFILE_WORK" "$BUILD_WORK"
|
|
cp -a "$PROFILE_SRC" "$PROFILE_WORK"
|
|
|
|
echo "==> Overlaying Furtka customizations"
|
|
|
|
cat "$SCRIPT_DIR/overlay/packages.extra" >> "$PROFILE_WORK/packages.x86_64"
|
|
|
|
cat "$SCRIPT_DIR/overlay/profiledef.sh" >> "$PROFILE_WORK/profiledef.sh"
|
|
|
|
cp -a "$SCRIPT_DIR/overlay/airootfs/." "$PROFILE_WORK/airootfs/"
|
|
|
|
# releng auto-logs root in on tty1. That turns our /etc/issue banner into a
|
|
# one-shot snapshot: once agetty has handed tty1 to a shell, `agetty --reload`
|
|
# from furtka-update-issue has nothing left to redraw, so the IP fallback only
|
|
# shows if DHCP happened to beat getty. Drop the drop-in: tty1 stays at the
|
|
# login prompt with a live-refreshed banner (furtka-issue.timer), and a shell
|
|
# is one `root` + Enter away (releng's root has no password) — the banner says
|
|
# so.
|
|
rm -rf "$PROFILE_WORK/airootfs/etc/systemd/system/getty@tty1.service.d"
|
|
|
|
echo "==> Rebranding boot menu (GRUB + syslinux + systemd-boot)"
|
|
# BIOS boot menu background: Furtka lockup instead of the Arch logo
|
|
# (generated by website/tools/brand-assets.py, 640x480 as syslinux wants).
|
|
cp "$SCRIPT_DIR/overlay/splash.png" "$PROFILE_WORK/syslinux/splash.png"
|
|
# releng ships menu entries labelled "Arch Linux install medium" across three
|
|
# bootloader configs (BIOS syslinux, GRUB, systemd-boot for UEFI). Rewrite to
|
|
# our brand. Done with sed (not a static overlay) so upstream archiso file
|
|
# moves don't silently leave stale Arch labels behind.
|
|
#
|
|
# Also rebrands the syslinux menu header ("MENU TITLE Arch Linux") and the
|
|
# per-entry HELP text shown at the bottom of the BIOS screen. GRUB/efiboot
|
|
# don't ship equivalent long descriptions, so menu-entry rename is enough there.
|
|
find "$PROFILE_WORK/grub" "$PROFILE_WORK/syslinux" "$PROFILE_WORK/efiboot" \
|
|
-type f \( -name "*.cfg" -o -name "*.conf" \) -print0 \
|
|
| xargs -0 sed -i \
|
|
-e 's/Arch Linux install medium/Furtka Live Installer/g' \
|
|
-e 's/Arch Linux live medium/Furtka Live Installer/g' \
|
|
-e 's/install Arch Linux or perform system maintenance/install Furtka or perform system maintenance/g' \
|
|
-e 's/^MENU TITLE Arch Linux$/MENU TITLE Furtka/'
|
|
|
|
# Mark the default entry as (Recommended) so first-time users know which to
|
|
# pick. Targets the main entry only — speech/accessibility variants stay
|
|
# unlabeled to avoid suggesting they're the normal choice.
|
|
sed -i 's/^title Furtka Live Installer (%ARCH%, UEFI)$/title (Recommended) Furtka Live Installer (%ARCH%, UEFI)/' \
|
|
"$PROFILE_WORK/efiboot/loader/entries/01-archiso-linux.conf"
|
|
sed -i 's/^MENU LABEL Furtka Live Installer (%ARCH%, BIOS)$/MENU LABEL (Recommended) Furtka Live Installer (%ARCH%, BIOS)/' \
|
|
"$PROFILE_WORK/syslinux/archiso_sys-linux.cfg"
|
|
sed -i "/--id 'archlinux'/s/menuentry \"Furtka Live Installer/menuentry \"(Recommended) Furtka Live Installer/" \
|
|
"$PROFILE_WORK/grub/grub.cfg" "$PROFILE_WORK/grub/loopback.cfg"
|
|
|
|
mkdir -p "$PROFILE_WORK/airootfs/opt/furtka"
|
|
cp -a "$REPO_ROOT/webinstaller/." "$PROFILE_WORK/airootfs/opt/furtka/"
|
|
# Ship the post-install asset tree (HTML, CSS, systemd units, scripts, …)
|
|
# next to webinstaller/app.py so _resolve_assets_dir() finds it at runtime.
|
|
cp -a "$REPO_ROOT/assets" "$PROFILE_WORK/airootfs/opt/furtka/assets"
|
|
rm -rf "$PROFILE_WORK/airootfs/opt/furtka/__pycache__"
|
|
# VERSION next to the webinstaller so the wizard footer can render the
|
|
# release string at runtime instead of carrying a hardcoded one. Matches
|
|
# what the resource-manager payload ships in its own VERSION file below.
|
|
ISO_VERSION=$(grep -E '^version = ' "$REPO_ROOT/pyproject.toml" | head -1 | sed 's/.*= "\(.*\)"/\1/')
|
|
echo "$ISO_VERSION" > "$PROFILE_WORK/airootfs/opt/furtka/VERSION"
|
|
|
|
# Pack the resource manager (furtka/ Python package + bundled apps/) as a
|
|
# tarball that webinstaller hands to archinstall via custom_commands. Lives at
|
|
# a fixed path in the live ISO; the installed system reads it back, untars
|
|
# into /opt/furtka/versions/<VERSION>/, and gets a working `furtka` CLI + the
|
|
# fileshare app. Same tarball shape as Phase-2 self-update releases, so an
|
|
# ISO-installed box and an updated box converge on the same layout.
|
|
echo "==> Bundling resource manager payload"
|
|
PAYLOAD_STAGE="$(mktemp -d)"
|
|
cp -a "$REPO_ROOT/furtka" "$PAYLOAD_STAGE/"
|
|
cp -a "$REPO_ROOT/apps" "$PAYLOAD_STAGE/"
|
|
# assets/ ships at the tarball root (not inside the Python package) because
|
|
# Caddy, systemd, and the updater all expect it at /opt/furtka/current/assets/.
|
|
cp -a "$REPO_ROOT/assets" "$PAYLOAD_STAGE/"
|
|
find "$PAYLOAD_STAGE" -type d -name __pycache__ -exec rm -rf {} +
|
|
# VERSION at tarball root: the installer reads it to choose the versions/<ver>/
|
|
# directory name and /opt/furtka/current/VERSION reports it at runtime. Same
|
|
# value we wrote into /opt/furtka/VERSION for the live wizard footer above.
|
|
echo "$ISO_VERSION" > "$PAYLOAD_STAGE/VERSION"
|
|
tar -czf "$PROFILE_WORK/airootfs/opt/furtka-resource-manager.tar.gz" \
|
|
-C "$PAYLOAD_STAGE" .
|
|
rm -rf "$PAYLOAD_STAGE"
|
|
|
|
mkdir -p "$PROFILE_WORK/airootfs/etc/systemd/system/avahi-daemon.service.d"
|
|
ln -sf /usr/lib/systemd/system/avahi-daemon.service \
|
|
"$PROFILE_WORK/airootfs/etc/systemd/system/multi-user.target.wants/avahi-daemon.service"
|
|
|
|
echo "==> Building ISO (mkarchiso)"
|
|
mkdir -p "$OUT_IN_CONTAINER"
|
|
mkarchiso -v -w "$BUILD_WORK" -o "$OUT_IN_CONTAINER" "$PROFILE_WORK"
|
|
|
|
echo
|
|
echo "==> Done. ISO(s) in $OUT_IN_CONTAINER (on host: iso/out/):"
|
|
ls -lh "$OUT_IN_CONTAINER"
|