#!/usr/bin/env bash # ───────────────────────────────────────────────────────────────────────────── # Arcline OS — disk image builder (qcow2 / raw) # # scripts/build-image.sh [--format qcow2|raw] [--size 4G] [--boot bios|efi] # # Produces a bootable disk image (the cloud edition's real output — and useful # for testing server/workstation locally in a VM): # # 1. ensure the rootfs exists (build it if needed) # 2. create a sparse raw file, attach a loop device # 3. deploy-disk.sh writes the finished system (btrfs layout + GRUB + fstab) # 4. optionally qemu-img convert to qcow2 # 5. artifact → build/artifacts/arcline---. + sha256 # # Requires root (for the loop device + deploy step). # ───────────────────────────────────────────────────────────────────────────── set -euo pipefail source "$(dirname "${BASH_SOURCE[0]}")/common.sh" EDITION="${1:?usage: build-image.sh [--format qcow2|raw] [--size 4G] [--boot bios|efi]}" FORMAT="qcow2" SIZE="4G" BOOT="bios" shift || true while [[ $# -gt 0 ]]; do case "$1" in --format) FORMAT="${2:?}"; shift 2 ;; --size) SIZE="${2:?}"; shift 2 ;; --boot) BOOT="${2:?}"; shift 2 ;; *) die "unknown option '$1'" ;; esac done validate_edition "$EDITION" [[ "$FORMAT" == "qcow2" || "$FORMAT" == "raw" ]] || die "--format must be qcow2|raw" [[ "$BOOT" == "bios" || "$BOOT" == "efi" ]] || die "--boot must be bios|efi" require_root "$0" "$@" command -v qemu-img >/dev/null || die "missing 'qemu-img' (package: qemu-utils)" command -v losetup >/dev/null || die "missing 'losetup' (package: util-linux)" ROOTFS="$ROOTFS_DIR/$EDITION" RAW="$IMAGE_DIR/$EDITION/arcline-$EDITION-$VERSION-$ARCH.raw" EXT="$FORMAT" ARTIFACT="$ARTIFACT_DIR/arcline-$EDITION-$VERSION-$ARCH.$EXT" mkdir -p "$IMAGE_DIR/$EDITION" "$ARTIFACT_DIR" rm -f "$RAW" "$ARTIFACT" "$ARTIFACT.sha256" # ── 1. rootfs ─────────────────────────────────────────────────────────────── if [[ ! -d "$ROOTFS" ]]; then log "rootfs missing — building it first" "$ROOT/scripts/build-rootfs.sh" "$EDITION" fi # ── 2. sparse raw file + loop device ──────────────────────────────────────── log "creating ${SIZE} sparse image (edition $EDITION, $BOOT boot)" truncate -s "$SIZE" "$RAW" LOOP="$(losetup --find --show --partscan "$RAW")" cleanup() { losetup -d "$LOOP" 2>/dev/null || true; } trap cleanup EXIT log "attached loop device: $LOOP" # ── 3. deploy ─────────────────────────────────────────────────────────────── "$ROOT/scripts/deploy-disk.sh" "$LOOP" "$ROOTFS" "$EDITION" --boot "$BOOT" # ── 4. convert ────────────────────────────────────────────────────────────── losetup -d "$LOOP" trap - EXIT if [[ "$FORMAT" == "qcow2" ]]; then log "converting to qcow2" qemu-img convert -f raw -O qcow2 "$RAW" "$ARTIFACT" rm -f "$RAW" else mv "$RAW" "$ARTIFACT" fi log "image artifact: $ARTIFACT" sha256sum "$ARTIFACT" | tee "$ARTIFACT.sha256"