mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 19:01:39 -04:00
All three build targets move from Debian 12/bookworm to Debian 13/trixie for fresh installs; existing Debian 12 systems remain supported in place. Docker: api/help on python:3.13-trixie, controller on 3.13-slim-trixie, app on node:20-trixie (matches trixie's nodejs 20), samba/zim on debian:13. Full backend suite passes on Python 3.13 in the api container. debian-live-config: --distribution trixie; postgres teardown for the SQLite cutover (pg_dropcluster hook block removed, wrolpi-bootstrap.sh no longer creates a cluster or calls the deleted initialize_api_db.sh — the API creates wrolpi.db itself on first start). README documents the SQLite layout and drops Etcher recommendations. pi-gen: upstream has no trixie branch — the arm64 branch now defaults to RELEASE=trixie; KEYBOARD_KEYMAP=en_US is rejected by trixie's console-setup (ckbcomp validates), use 'us'; stop stamping a Postgres .pgpass into /etc/skel. Package lists (both targets): postgresql-15/postgresql-doc/libpq-dev deleted; libtiff5-dev renamed to libtiff-dev; software-properties-common and cpufrequtils removed from trixie (Controller CPU throttle falls back to sysfs, dead cpufreq-set sudoers rule removed); locales and gnupg added (no longer arrive transitively under --apt-recommends false); sqlite3 CLI added for reset_tags.sh. help.sh: replace the Postgres service/port/socket/cluster/psql checks (all false FAILEDs after the SQLite cutover) with SQLite checks: wrolpi.db exists, PRAGMA quick_check, file_group table + row count, run as the wrolpi user so root never creates the -shm sidecar. Both build scripts take a WROLPI_BUILD_DIR override so development builds can run beside the release pipeline's build trees; the sudo re-exec passes it through explicitly (a plain sudo would drop it). test_common.py: the truncate tests hard-coded sys.getsizeof results from the 3.11 object layout (str/list shrank in 3.12); assert the contract (fits budget, prefix, monotonic in budget) so they pass on 3.11 and 3.13. Verified: trixie ISO (3.7G) and pi-gen desktop image (4.3G) both built from scratch and passed their sanity checks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
186 lines
7.5 KiB
Bash
Executable file
186 lines
7.5 KiB
Bash
Executable file
#!/bin/bash
|
|
# Build the WROLPi Debian Live + installer ISO.
|
|
#
|
|
# Output: an iso-hybrid image that boots into a full WROLPi system on any
|
|
# x86 PC. Users can run WROLPi directly off the USB (persistence partition
|
|
# created on first boot) or install to disk via the Calamares launcher on
|
|
# the desktop. Calamares wiring lands in phase 2; phase 1 ships the
|
|
# live-only flow.
|
|
#
|
|
# https://live-team.pages.debian.net/live-manual/html/live-manual/index.en.html
|
|
|
|
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
|
# Overridable so a development build can run beside the release pipeline's
|
|
# build tree without colliding with it.
|
|
BUILD_DIR="${WROLPI_BUILD_DIR:-/var/tmp/wrolpi-build-debian}"
|
|
|
|
Help() {
|
|
echo "Build WROLPi Debian Live ISO image."
|
|
echo
|
|
echo "Syntax: build.sh [-h] [-b BRANCH]"
|
|
echo "options:"
|
|
echo "h Print this help."
|
|
echo "b Build from this git BRANCH (default: 'release')."
|
|
echo
|
|
echo "Set WROLPI_BUILD_DIR to build somewhere other than the default"
|
|
echo "(${BUILD_DIR}), e.g. beside the release pipeline's tree."
|
|
echo
|
|
}
|
|
|
|
BRANCH="release"
|
|
while getopts ":hb:" option; do
|
|
case $option in
|
|
h) Help; exit ;;
|
|
b) BRANCH="${OPTARG}" ;;
|
|
*) echo "Error: Invalid option"; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
# Get version from the target git branch (not local checkout) so output
|
|
# filename matches actual content. Strip whitespace so stray newlines or
|
|
# spaces in version.txt do not corrupt the lb config metadata strings.
|
|
VERSION=$(curl -sL "https://raw.githubusercontent.com/lrnselfreliance/wrolpi/${BRANCH}/wrolpi/version.txt" | tr -d '[:space:]')
|
|
if [ -z "${VERSION}" ]; then
|
|
echo "ERROR: Could not fetch version from branch '${BRANCH}'"
|
|
exit 1
|
|
fi
|
|
echo "Building WROLPi version: ${VERSION} from branch: ${BRANCH}"
|
|
|
|
# Re-execute this script if it wasn't called with sudo. Pass BUILD_DIR
|
|
# through explicitly — a plain `sudo "$0"` drops WROLPI_BUILD_DIR from the
|
|
# environment and the build would silently land on the default path.
|
|
if [ $EUID != 0 ]; then
|
|
sudo WROLPI_BUILD_DIR="${BUILD_DIR}" "$0" "$@"
|
|
exit $?
|
|
fi
|
|
|
|
# Clear out old builds. Strip immutable flag from blob files first — the
|
|
# chroot hook applies chattr +i to /opt/wrolpi-blobs/*; without removing
|
|
# that here, rm -rf leaves them behind and the next lb build's
|
|
# chroot_includes_after_packages rsync fails with "Operation not permitted"
|
|
# trying to overwrite them.
|
|
if [ -d "${BUILD_DIR}" ]; then
|
|
find "${BUILD_DIR}" -path '*/opt/wrolpi-blobs/*' -type f -exec chattr -i {} + 2>/dev/null || true
|
|
rm -rf "${BUILD_DIR}"
|
|
fi
|
|
mkdir -p "${BUILD_DIR}"
|
|
cd "${BUILD_DIR}" || (echo "Work directory must exist" && exit 1)
|
|
set -e
|
|
|
|
# Live + Debian Installer. The installer is the stock Debian d-i with
|
|
# `--debian-installer live`, which copies the running squashfs onto the
|
|
# target disk (much faster than a network-based install) and presents the
|
|
# usual graphical/text installer flow. GRUB gets "Install" + "Graphical
|
|
# install" + "Live" entries. noswap prevents the live system from
|
|
# activating swap partitions found on the host machine's internal disks.
|
|
lb config \
|
|
--binary-images iso-hybrid \
|
|
--mode debian \
|
|
--architectures amd64 \
|
|
--linux-flavours amd64 \
|
|
--distribution trixie \
|
|
--debian-installer live \
|
|
--debian-installer-gui true \
|
|
--archive-areas "main contrib non-free non-free-firmware" \
|
|
--updates true \
|
|
--security true \
|
|
--apt-recommends false \
|
|
--firmware-binary true \
|
|
--firmware-chroot true \
|
|
--win32-loader false \
|
|
--checksums sha512 \
|
|
--clean \
|
|
--color \
|
|
--linux-packages "linux-image linux-headers" \
|
|
--memtest memtest86+ \
|
|
--bootappend-live "boot=live components quiet splash noswap persistence persistence-storage=filesystem persistence-media=removable persistence-label=persistence live-config.username=wrolpi live-config.user-fullname=WROLPi live-config.hostname=wrolpi" \
|
|
--iso-volume "WROLPi v${VERSION}" \
|
|
--iso-application "WROLPi v${VERSION}" \
|
|
--iso-preparer WROLPi \
|
|
--iso-publisher https://wrolpi.org
|
|
|
|
rsync -a "${SCRIPT_DIR}/config" "${BUILD_DIR}/"
|
|
|
|
# Write branch config for hook script.
|
|
mkdir -p "${BUILD_DIR}/config/includes.chroot/opt/wrolpi-blobs"
|
|
echo "${BRANCH}" > "${BUILD_DIR}/config/includes.chroot/opt/wrolpi-branch"
|
|
|
|
# Cache directory for downloaded blobs (persists across builds).
|
|
BLOB_CACHE="${SCRIPT_DIR}/files"
|
|
mkdir -p "${BLOB_CACHE}"
|
|
|
|
# Download map fonts (skip if cached).
|
|
if [ ! -f "${BLOB_CACHE}/map-fonts.tar.gz" ]; then
|
|
echo "Downloading map fonts..."
|
|
mkdir -p /tmp/map-fonts-dl
|
|
curl -fsSL https://github.com/protomaps/basemaps-assets/archive/refs/heads/main.tar.gz \
|
|
| tar -xz --strip-components=1 -C /tmp/map-fonts-dl basemaps-assets-main/fonts
|
|
tar -czf "${BLOB_CACHE}/map-fonts.tar.gz" -C /tmp/map-fonts-dl fonts
|
|
rm -rf /tmp/map-fonts-dl
|
|
fi
|
|
[[ -f "${BLOB_CACHE}/map-fonts.tar.gz" && -s "${BLOB_CACHE}/map-fonts.tar.gz" ]] || \
|
|
(echo "ERROR: Failed to download map fonts!" && exit 1)
|
|
|
|
# Download map overview (skip if cached).
|
|
if [ ! -f "${BLOB_CACHE}/map-overview.pmtiles" ]; then
|
|
echo "Downloading map overview..."
|
|
curl -fsSL https://wrolpi.nyc3.cdn.digitaloceanspaces.com/maps/map-overview.pmtiles \
|
|
-o "${BLOB_CACHE}/map-overview.pmtiles"
|
|
fi
|
|
[[ -f "${BLOB_CACHE}/map-overview.pmtiles" && -s "${BLOB_CACHE}/map-overview.pmtiles" ]] || \
|
|
(echo "ERROR: Failed to download map overview!" && exit 1)
|
|
|
|
# Copy cached blobs into the live image.
|
|
cp "${BLOB_CACHE}/map-fonts.tar.gz" "${BUILD_DIR}/config/includes.chroot/opt/wrolpi-blobs/"
|
|
cp "${BLOB_CACHE}/map-overview.pmtiles" "${BUILD_DIR}/config/includes.chroot/opt/wrolpi-blobs/"
|
|
|
|
# pipefail so an lb build failure isn't masked by tee's success exit code.
|
|
set -o pipefail
|
|
time nice -n 18 lb build 2>&1 | tee "${SCRIPT_DIR}/build.log"
|
|
set +o pipefail
|
|
|
|
grep "9999-wrolpi.hook.chroot completed" "${SCRIPT_DIR}/build.log" >/dev/null 2>&1 || (echo "build hook failed!" && exit 1)
|
|
|
|
# Copy the freshly built ISO directly to its final name. Take the single ISO
|
|
# out of BUILD_DIR (which is wiped each build, so it holds exactly one) rather
|
|
# than globbing SCRIPT_DIR -- a leftover ISO from a previous build would
|
|
# otherwise make a `*.iso` glob match multiple files and break the move.
|
|
DEST="${SCRIPT_DIR}/WROLPi-v${VERSION}-amd64.iso"
|
|
shopt -s nullglob
|
|
BUILT_ISOS=("${BUILD_DIR}"/*.iso)
|
|
shopt -u nullglob
|
|
if [ "${#BUILT_ISOS[@]}" -eq 0 ]; then
|
|
echo "Build failed. No ISOs were found!"
|
|
exit 1
|
|
fi
|
|
rm -f "${DEST}"
|
|
cp "${BUILT_ISOS[0]}" "${DEST}"
|
|
chmod 644 "${DEST}"
|
|
chown "${SUDO_UID:-1000}:${SUDO_GID:-1000}" "${DEST}"
|
|
|
|
# Sanity-check the resulting ISO before declaring success, so a truncated or
|
|
# corrupt build never ships.
|
|
MIN_ISO_BYTES=$((1024 * 1024 * 1024)) # 1 GiB floor; a real ISO is ~3 GiB.
|
|
ISO_BYTES=$(stat -c%s "${DEST}")
|
|
if [ "${ISO_BYTES}" -lt "${MIN_ISO_BYTES}" ]; then
|
|
echo "ERROR: ISO is only ${ISO_BYTES} bytes (< ${MIN_ISO_BYTES}); build likely truncated." >&2
|
|
exit 1
|
|
fi
|
|
# The ISO 9660 primary volume descriptor carries the "CD001" magic at byte
|
|
# offset 32769. It is present even in iso-hybrid images, where `file` reports
|
|
# the leading MBR instead.
|
|
if [ "$(dd if="${DEST}" bs=1 skip=32769 count=5 2>/dev/null)" != "CD001" ]; then
|
|
echo "ERROR: ${DEST} is not a valid ISO 9660 image (missing CD001 magic)." >&2
|
|
exit 1
|
|
fi
|
|
# Cross-check with blkid when available.
|
|
if command -v blkid >/dev/null 2>&1; then
|
|
ISO_FSTYPE=$(blkid -o value -s TYPE "${DEST}" 2>/dev/null || true)
|
|
if [ -n "${ISO_FSTYPE}" ] && [ "${ISO_FSTYPE}" != "iso9660" ]; then
|
|
echo "ERROR: blkid reports filesystem '${ISO_FSTYPE}', expected iso9660." >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
echo "ISO sanity checks passed ($(numfmt --to=iec "${ISO_BYTES}" 2>/dev/null || echo "${ISO_BYTES} bytes"), iso9660)."
|
|
|
|
echo "Build has completed. ISO output ${DEST}"
|