AkurAI Build
Menu

BifrOSt

public

Latest change 2470f865b919f6a226354bc329a8ee630f90cd70 - Fix black-screen boot by normalizing installed /etc permissions by Ólafur Búi Ólafsson

#!/usr/bin/env bash
#
# build-iso.sh - Build the BifrOSt live/install ISO with archiso/mkarchiso.
#
# Runs the full local ISO build pipeline from a repository checkout:
#
#   1. Verify the signed installer package seed is present and valid
#      (prepare-installer-cache.py --require). A verified seed is mandatory
#      before an ISO build.
#   2. Optionally restage installed-system release metadata when a source
#      revision is supplied (generate-release-metadata.py --prepare-installed).
#      The tracked profile already carries staged metadata, so this step is
#      opt-in and only needed when cutting a new revision.
#   3. Validate the profile, sources, and release contract (validate-build.py)
#      unless --skip-validate is given.
#   4. Build the ISO with mkarchiso.
#   5. Print the resulting ISO path, size, and SHA-256.
#
# Builds run on Titan, never on a laptop. mkarchiso requires root, so run this
# script with sudo (or as root). Scratch and output live under the repository's
# .tmp/ per the workspace temporary-work policy. See docs/build-iso.md.
#
set -Eeuo pipefail

REPO_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"

WORK_DIR="$REPO_ROOT/.tmp/iso-work"
OUT_DIR="$REPO_ROOT/.tmp/iso-out"
PROFILE_DIR="$REPO_ROOT/profile"
SKIP_VALIDATE=0
KEEP_WORK=0
SOURCE_REVISION=""
SOURCE_DATE_EPOCH_ARG=""

usage() {
    cat <<'USAGE'
Usage: sudo ./build-iso.sh [options]

Build the BifrOSt live/install ISO from a repository checkout.

Pipeline:
  1. Verify the installer package seed   (prepare-installer-cache.py --require)
  2. Optionally restage release metadata (generate-release-metadata.py)
  3. Validate profile and release contract (validate-build.py)
  4. Build the ISO                       (mkarchiso -v -r)
  5. Report the ISO path, size, and SHA-256

Options:
  -w, --work-dir DIR         Scratch build directory (default: .tmp/iso-work)
  -o, --out-dir DIR          ISO output directory (default: .tmp/iso-out)
  -p, --profile DIR          archiso profile directory (default: profile)
      --source-revision REV  Restage installed release metadata for REV (40/64 hex)
      --source-date-epoch N  Epoch for metadata restaging (default: REV commit time)
      --skip-validate        Skip validate-build.py (not recommended)
      --keep-work            Keep the scratch work directory after building
  -h, --help                 Show this help and exit

mkarchiso requires root; run with sudo. Builds run on Titan, never a laptop.
USAGE
}

die() { printf 'build-iso: %s\n' "$*" >&2; exit 1; }
log() { printf '\n==> %s\n' "$*"; }

while (( $# )); do
    case "$1" in
        -w|--work-dir) [[ $# -ge 2 ]] || die "$1 needs a value"; WORK_DIR="$2"; shift 2 ;;
        -o|--out-dir) [[ $# -ge 2 ]] || die "$1 needs a value"; OUT_DIR="$2"; shift 2 ;;
        -p|--profile) [[ $# -ge 2 ]] || die "$1 needs a value"; PROFILE_DIR="$2"; shift 2 ;;
        --source-revision) [[ $# -ge 2 ]] || die "$1 needs a value"; SOURCE_REVISION="$2"; shift 2 ;;
        --source-date-epoch) [[ $# -ge 2 ]] || die "$1 needs a value"; SOURCE_DATE_EPOCH_ARG="$2"; shift 2 ;;
        --skip-validate) SKIP_VALIDATE=1; shift ;;
        --keep-work) KEEP_WORK=1; shift ;;
        -h|--help) usage; exit 0 ;;
        *) usage >&2; die "unknown argument: $1" ;;
    esac
done

(( EUID == 0 )) || die "must run as root (mkarchiso needs root); use: sudo $0"
command -v mkarchiso >/dev/null || die "mkarchiso not found; install it: pacman -S --needed archiso"
command -v python3 >/dev/null || die "python3 not found"
[[ -f "$PROFILE_DIR/profiledef.sh" ]] || die "not an archiso profile: $PROFILE_DIR"

cd "$REPO_ROOT"

log "Verifying installer package seed"
python3 "$REPO_ROOT/prepare-installer-cache.py" --require \
    || die "installer seed is absent or invalid; run prepare-installer-cache.py to build it"

if [[ -n "$SOURCE_REVISION" ]]; then
    log "Restaging installed release metadata for $SOURCE_REVISION"
    epoch="$SOURCE_DATE_EPOCH_ARG"
    if [[ -z "$epoch" ]]; then
        epoch="$(git -C "$REPO_ROOT" show -s --format=%ct "$SOURCE_REVISION" 2>/dev/null || true)"
    fi
    [[ -n "$epoch" ]] || die "could not determine --source-date-epoch; pass it explicitly"
    python3 "$REPO_ROOT/generate-release-metadata.py" \
        --prepare-installed "$PROFILE_DIR/airootfs/usr/share/bifrost/installed-root/usr/share/bifrost/release.json" \
        --source-revision "$SOURCE_REVISION" \
        --source-date-epoch "$epoch" \
        || die "release metadata staging failed"
fi

if (( SKIP_VALIDATE )); then
    log "Skipping profile validation (--skip-validate)"
else
    log "Validating profile, sources, and release contract"
    python3 "$REPO_ROOT/validate-build.py" "$REPO_ROOT" || die "validate-build.py failed"
fi

log "Building ISO with mkarchiso (work=$WORK_DIR out=$OUT_DIR)"
mkdir -p "$OUT_DIR"
rm -rf -- "$WORK_DIR"
mkarchiso_args=(-v -w "$WORK_DIR" -o "$OUT_DIR")
# mkarchiso -r deletes the working directory when the build finishes.
(( KEEP_WORK )) || mkarchiso_args=(-r "${mkarchiso_args[@]}")
mkarchiso "${mkarchiso_args[@]}" "$PROFILE_DIR"

(( KEEP_WORK )) && log "Kept scratch work directory: $WORK_DIR"

iso="$(ls -t "$OUT_DIR"/*.iso 2>/dev/null | head -n1 || true)"
[[ -n "$iso" ]] || die "build finished but no ISO was found in $OUT_DIR"
log "ISO built: $iso"
printf '    size:   %s\n' "$(du -h "$iso" | cut -f1)"
printf '    sha256: %s\n' "$(sha256sum "$iso" | cut -d' ' -f1)"