|
| 1 | +#!/usr/bin/env bash |
| 2 | +# build-asahi-package.sh — Build the SourceOS Apple Silicon OS package consumed |
| 3 | +# by the official Asahi installer (referenced from asahi/installer_data.json). |
| 4 | +# |
| 5 | +# Produces, in OUTDIR: |
| 6 | +# sourceos-<version>-asahi-arm64.zip — the installer package, containing: |
| 7 | +# esp/ EFI system partition tree (m1n1 stage2, GRUB, dtbs) |
| 8 | +# boot.img ext4 /boot image |
| 9 | +# root.img ext4 / image (the SourceOS aarch64 system) |
| 10 | +# <zip>.sha256 |
| 11 | +# |
| 12 | +# Runs on aarch64-linux (CI self-hosted aarch64 runner). Uses the |
| 13 | +# nixos-apple-silicon flake for the Apple Silicon firmware/bootloader bits, so |
| 14 | +# m1n1 + U-Boot come from upstream Asahi — we do NOT hand-build them here. |
| 15 | +# |
| 16 | +# Usage: bash scripts/build-asahi-package.sh OUTDIR [VERSION] |
| 17 | +# |
| 18 | +# STATUS: scaffolding — the toplevel build + image assembly are wired, but the |
| 19 | +# exact nixos-apple-silicon installer-package attribute and the esp/ layout must |
| 20 | +# be validated on a real aarch64 builder before the seamless path is advertised. |
| 21 | +set -euo pipefail |
| 22 | + |
| 23 | +OUTDIR="${1:?usage: build-asahi-package.sh OUTDIR [VERSION]}" |
| 24 | +VERSION="${2:-26.11}" |
| 25 | +HOST="${HOST:-builder-aarch64}" |
| 26 | +FLAKE="${FLAKE:-.}" |
| 27 | +mkdir -p "$OUTDIR" |
| 28 | +WORK="$(mktemp -d)"; trap 'rm -rf "$WORK"' EXIT |
| 29 | +log() { printf '[asahi-package] %s\n' "$*"; } |
| 30 | + |
| 31 | +command -v nix >/dev/null 2>&1 || { log "FATAL: nix required"; exit 1; } |
| 32 | +[ "$(uname -m)" = "aarch64" ] || log "WARN: not aarch64 — image build will need emulation/remote builder" |
| 33 | + |
| 34 | +# 1. Build the SourceOS aarch64 system closure. |
| 35 | +log "Building toplevel for $HOST ..." |
| 36 | +TOP=$(nix build --no-link --print-out-paths --impure \ |
| 37 | + "${FLAKE}#nixosConfigurations.${HOST}.config.system.build.toplevel") |
| 38 | +log "toplevel: $TOP" |
| 39 | + |
| 40 | +# 2. Obtain Apple Silicon firmware/bootloader via nixos-apple-silicon. |
| 41 | +# (uboot-asahi assembles m1n1 + U-Boot; firmware comes from the target's |
| 42 | +# own extraction during install — the installer copies it.) |
| 43 | +NAS="github:tpwrules/nixos-apple-silicon" |
| 44 | +log "Building uboot-asahi (m1n1 + U-Boot) ..." |
| 45 | +UBOOT=$(nix build --no-link --print-out-paths "$NAS#uboot-asahi" 2>/dev/null || true) |
| 46 | +[ -n "$UBOOT" ] && log "uboot-asahi: $UBOOT" || log "WARN: uboot-asahi build failed — esp/ will be incomplete" |
| 47 | + |
| 48 | +# 3. Assemble the installer package layout. |
| 49 | +PKGROOT="$WORK/pkg" |
| 50 | +mkdir -p "$PKGROOT/esp/m1n1" "$PKGROOT/esp/EFI/BOOT" |
| 51 | + |
| 52 | +# m1n1 stage2 (boot.bin) + GRUB into the ESP tree. |
| 53 | +if [ -n "$UBOOT" ]; then |
| 54 | + find "$UBOOT" \( -name 'u-boot*.bin' -o -name 'm1n1*.bin' -o -name 'boot.bin' \) \ |
| 55 | + -size +500k -exec cp {} "$PKGROOT/esp/m1n1/boot.bin" \; 2>/dev/null || true |
| 56 | +fi |
| 57 | +if command -v grub-mkimage >/dev/null 2>&1 || command -v grub2-mkimage >/dev/null 2>&1; then |
| 58 | + GM="$(command -v grub-mkimage || command -v grub2-mkimage)" |
| 59 | + "$GM" -O arm64-efi -o "$PKGROOT/esp/EFI/BOOT/BOOTAA64.EFI" -p /EFI/BOOT \ |
| 60 | + normal linux iso9660 part_gpt fat ext2 search search_label configfile echo all_video |
| 61 | +fi |
| 62 | + |
| 63 | +# 4. Build boot.img + root.img ext4 images sized to the closure. |
| 64 | +# root.img holds the Nix store + the system; boot.img holds the kernel/initrd. |
| 65 | +ROOT_MNT="$WORK/root"; mkdir -p "$ROOT_MNT" |
| 66 | +log "Populating root image from closure (nix copy --to) ..." |
| 67 | +ROOT_BYTES=$(du -sb "$TOP" | awk '{print $1}') |
| 68 | +ROOT_MB=$(( (ROOT_BYTES / 1024 / 1024) * 13 / 10 + 1024 )) # +30% headroom + 1G |
| 69 | +truncate -s "${ROOT_MB}M" "$PKGROOT/root.img" |
| 70 | +mkfs.ext4 -q -L nixos "$PKGROOT/root.img" |
| 71 | +truncate -s 1024M "$PKGROOT/boot.img" |
| 72 | +mkfs.ext4 -q -L boot "$PKGROOT/boot.img" |
| 73 | +log "root.img ${ROOT_MB}M, boot.img 1024M created." |
| 74 | +log "NOTE: populating root.img with the closure + bootloader install requires a" |
| 75 | +log " loop mount + nixos-install --root (privileged); wired in CI on the" |
| 76 | +log " aarch64 runner. See release-images.yml asahi-package job." |
| 77 | + |
| 78 | +# 5. Zip the package. |
| 79 | +ZIP="$OUTDIR/sourceos-${VERSION}-asahi-arm64.zip" |
| 80 | +( cd "$PKGROOT" && zip -r -q "$ZIP" esp boot.img root.img ) |
| 81 | +( cd "$OUTDIR" && sha256sum "$(basename "$ZIP")" > "$(basename "$ZIP").sha256" 2>/dev/null || \ |
| 82 | + shasum -a 256 "$(basename "$ZIP")" > "$(basename "$ZIP").sha256" ) |
| 83 | +log "Package: $ZIP" |
| 84 | +ls -lh "$OUTDIR" |
0 commit comments