Files
narOS/mkimage/build-rootfs.sh
T

111 lines
4.4 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# narOS rootfs builder (NAROS.md §2.2): mmdebstrap against the pinned Debian snapshot,
# plus (optionally) the local Nucleic package pool. Produces a rootfs tar that CI turns
# into an OCI image (naros-base/…) or the VM payload tarball.
#
# build-rootfs.sh <tier> <arch> [--pool DIR] [--out DIR] [--channel edge|stable]
#
# Needs mmdebstrap and either root or an unshare-capable user. The snapshot mirror serves
# stale Release files by design, hence Check-Valid-Until off (standard snapshot practice).
set -euo pipefail
OS_DIR="$(cd "$(dirname "$0")/.." && pwd)"
TIER="${1:?usage: build-rootfs.sh <tier> <arch> [--pool DIR] [--out DIR] [--channel C]}"
ARCH="${2:?missing arch (arm64|amd64)}"
shift 2
POOL="" OUT="$OS_DIR/dist" CHANNEL="${NAROS_CHANNEL:-edge}"
while [ $# -gt 0 ]; do
case "$1" in
--pool) POOL="$(cd "$2" && pwd)"; shift 2 ;;
--out) OUT="$2"; shift 2 ;;
--channel) CHANNEL="$2"; shift 2 ;;
*) echo "unknown arg: $1" >&2; exit 2 ;;
esac
done
VERSION="$(cat "$OS_DIR/VERSION")"
SNAPSHOT="$(cat "$OS_DIR/SNAPSHOT")"
SUITE="trixie"
MIRROR="https://snapshot.debian.org/archive/debian/${SNAPSHOT}/"
PROFILE="$OS_DIR/mkimage/profiles/$TIER.pkgs"
[ -f "$PROFILE" ] || { echo "no profile for tier '$TIER' ($PROFILE)" >&2; exit 2; }
pkg_list() { grep -vE '^\s*(#|$)' "$1" | tr '\n' ',' | sed 's/,$//'; }
INCLUDE="$(pkg_list "$PROFILE")"
SOURCES=("deb [check-valid-until=no] $MIRROR $SUITE main")
if [ -n "$POOL" ]; then
# Flat file:// repo over the pool; trusted because it is CI's own just-built artifact —
# end-user trust comes from the signed hosted repo (repo/publish.sh), not this path.
if [ ! -f "$POOL/Packages" ] || [ -n "$(find "$POOL" -name '*.deb' -newer "$POOL/Packages" 2>/dev/null)" ]; then
(cd "$POOL" && dpkg-scanpackages --multiversion . > Packages)
fi
# Late packages (profiles/<tier>.late-pkgs) install via a finish hook AFTER every
# Debian package is configured — mandatory for nash-default-shell: apt's configure
# order is not deterministic, so a mid-transaction divert would run the remaining
# Debian postinsts under nash (observed: ca-certificates' UTF-8 filenames mangled).
# The divert must be the image's final configure step.
LATE_DEBS=()
LPROFILE="$OS_DIR/mkimage/profiles/$TIER.late-pkgs"
if [ -f "$LPROFILE" ]; then
while IFS= read -r pkg; do
deb="$(ls "$POOL/${pkg}_"*.deb 2>/dev/null | head -1)"
if [ -n "$deb" ]; then
LATE_DEBS+=("$deb")
elif [ "${NAROS_STRICT:-0}" = "1" ]; then
echo "ERROR: late package $pkg absent from pool" >&2; exit 1
else
echo "WARNING: late package $pkg absent from pool — building WITHOUT it" >&2
fi
done < <(grep -vE '^\s*(#|$)' "$LPROFILE")
fi
NPROFILE="$OS_DIR/mkimage/profiles/$TIER.naros-pkgs"
if [ -f "$NPROFILE" ]; then
# Only request packages the pool actually carries: local builds legitimately lack
# some (e.g. naros-keyring without the signing key). Loud per-package warning;
# NAROS_STRICT=1 (CI) turns any gap into a hard failure.
while IFS= read -r pkg; do
if grep -qx "Package: $pkg" "$POOL/Packages"; then
INCLUDE="$INCLUDE,$pkg"
elif [ "${NAROS_STRICT:-0}" = "1" ]; then
echo "ERROR: $pkg requested by $TIER tier but absent from pool" >&2; exit 1
else
echo "WARNING: $pkg absent from pool — building WITHOUT it" >&2
fi
done < <(grep -vE '^\s*(#|$)' "$NPROFILE")
fi
SOURCES+=("deb [trusted=yes] copy://$POOL ./")
fi
mkdir -p "$OUT"
TAR="$OUT/naros-$TIER-$VERSION-$ARCH.tar"
export NAROS_TIER="$TIER" NAROS_VERSION="$VERSION" NAROS_ARCH="$ARCH" \
NAROS_CHANNEL="$CHANNEL" NAROS_SNAPSHOT="$SNAPSHOT" NAROS_SUITE="$SUITE"
HOOKS=()
if [ "${#LATE_DEBS[@]}" -gt 0 ]; then
LATE_ARGS=""
for deb in "${LATE_DEBS[@]}"; do
b="$(basename "$deb")"
HOOKS+=(--customize-hook="copy-in $deb /tmp")
LATE_ARGS="$LATE_ARGS /tmp/$b"
done
HOOKS+=(--customize-hook="chroot \"\$1\" dpkg -i$LATE_ARGS")
HOOKS+=(--customize-hook="rm -f$(printf ' "$1"%s' $LATE_ARGS)")
fi
HOOKS+=(--customize-hook="$OS_DIR/mkimage/hooks/00-identity.sh"' "$1"')
echo "narOS $VERSION/$CHANNEL: tier=$TIER arch=$ARCH snapshot=$SNAPSHOT pool=${POOL:-none}"
mmdebstrap \
--architectures="$ARCH" \
--variant=apt \
--include="$INCLUDE" \
--aptopt='Acquire::Check-Valid-Until "false"' \
"${HOOKS[@]}" \
"$SUITE" "$TAR" "${SOURCES[@]}"
echo "built $TAR"