Add dpack sign command, test runner, ISO builders, fix build errors
dpack fixes: - Fixed missing SourceInfo fields in CRUX/Gentoo converters (git, branch, tag, commit, update_check fields added to struct initializers) - Added 'sign' command: downloads source tarballs and computes real SHA256 checksums, updating .toml definitions in-place. Replaces placeholder checksums. Usage: dpack sign zlib or dpack sign all Testing: - tests/run-tests.sh: comprehensive integration test runner for Arch Linux host. 7 test suites covering host env, dpack build/tests, package defs, toolchain scripts, kernel config, init system, and QEMU boot. Generates JSON + text reports for automated debugging. Usage: bash tests/run-tests.sh [--quick] ISO builders: - src/iso/build-iso-arch.sh: builds live ISO from Arch Linux host Creates rootfs from pre-built base system or busybox fallback, includes installer + dpack + package repos, UEFI-only boot - src/iso/build-iso-darkforge.sh: builds live ISO from running DarkForge Snapshots the live system via rsync, creates redistributable ISO Package repository (submodule updated): - 14 new self-hosting packages: qemu, edk2-ovmf, squashfs-tools, xorriso, mtools, efibootmgr, efivar, rsync, lz4, nasm, neovim, htop, tmux, libevent - Total: 138 packages across 4 repos Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
234
src/iso/build-iso-arch.sh
Executable file
234
src/iso/build-iso-arch.sh
Executable file
@@ -0,0 +1,234 @@
|
||||
#!/bin/bash
|
||||
# ============================================================================
|
||||
# DarkForge Linux — ISO Builder (Arch Linux Host)
|
||||
# ============================================================================
|
||||
# Builds a bootable DarkForge live ISO from an Arch Linux host.
|
||||
# This is the script you run on your workstation to create the installer media.
|
||||
#
|
||||
# Requirements (Arch Linux):
|
||||
# sudo pacman -S squashfs-tools xorriso dosfstools mtools arch-install-scripts
|
||||
# sudo pacman -S base-devel gcc make git wget curl
|
||||
#
|
||||
# What this does:
|
||||
# 1. Creates a minimal root filesystem in a temp directory
|
||||
# 2. Installs the DarkForge base system (from pre-built packages or chroot)
|
||||
# 3. Includes the installer scripts, dpack binary, and package repos
|
||||
# 4. Compresses to squashfs
|
||||
# 5. Creates a UEFI-bootable hybrid ISO
|
||||
#
|
||||
# Usage:
|
||||
# sudo bash src/iso/build-iso-arch.sh
|
||||
#
|
||||
# Output:
|
||||
# darkforge-live.iso in the project root
|
||||
# ============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Must be root for chroot/mount operations
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "ERROR: This script must be run as root (for chroot/mount operations)."
|
||||
echo "Usage: sudo bash $0"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
BUILD_DIR="/tmp/darkforge-iso-build"
|
||||
ROOTFS="${BUILD_DIR}/rootfs"
|
||||
ISO_DIR="${BUILD_DIR}/iso"
|
||||
ISO_OUTPUT="${PROJECT_ROOT}/darkforge-live.iso"
|
||||
ISO_LABEL="DARKFORGE"
|
||||
SQFS_COMP="zstd"
|
||||
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
|
||||
info() { echo -e "${CYAN}>>> $1${NC}"; }
|
||||
ok() { echo -e "${GREEN}>>> $1${NC}"; }
|
||||
warn() { echo -e "${YELLOW}!!! $1${NC}"; }
|
||||
die() { echo -e "${RED}!!! $1${NC}"; exit 1; }
|
||||
|
||||
# --- Preflight --------------------------------------------------------------
|
||||
info "DarkForge ISO Builder (Arch Linux host)"
|
||||
echo ""
|
||||
|
||||
for tool in mksquashfs xorriso mkfs.fat mcopy; do
|
||||
command -v "$tool" >/dev/null 2>&1 || die "Missing: $tool — install with pacman"
|
||||
done
|
||||
|
||||
# --- Clean previous build ----------------------------------------------------
|
||||
info "Cleaning previous build..."
|
||||
rm -rf "${BUILD_DIR}"
|
||||
mkdir -p "${ROOTFS}" "${ISO_DIR}"/{EFI/BOOT,LiveOS,boot}
|
||||
|
||||
# --- Create the live root filesystem -----------------------------------------
|
||||
info "Creating live root filesystem..."
|
||||
|
||||
# Create FHS directory structure
|
||||
mkdir -p "${ROOTFS}"/{bin,boot,dev,etc/{rc.d,sysconfig},home,lib,lib64,mnt,opt}
|
||||
mkdir -p "${ROOTFS}"/{proc,root,run,sbin,srv,sys,tmp}
|
||||
mkdir -p "${ROOTFS}"/usr/{bin,include,lib,lib64,sbin,share/{man,doc}}
|
||||
mkdir -p "${ROOTFS}"/var/{cache,lib/{dpack/{db,repos}},log,lock,run,spool,tmp}
|
||||
mkdir -p "${ROOTFS}"/install
|
||||
|
||||
# --- Check if we have a pre-built base system --------------------------------
|
||||
BASE_SYSTEM="${PROJECT_ROOT}/build/base-system"
|
||||
TOOLCHAIN_CHROOT="${LFS:-/mnt/darkforge}"
|
||||
|
||||
if [ -d "${BASE_SYSTEM}" ] && [ -f "${BASE_SYSTEM}/usr/bin/bash" ]; then
|
||||
info "Copying pre-built base system from ${BASE_SYSTEM}..."
|
||||
cp -a "${BASE_SYSTEM}"/* "${ROOTFS}"/
|
||||
|
||||
elif [ -d "${TOOLCHAIN_CHROOT}" ] && [ -f "${TOOLCHAIN_CHROOT}/usr/bin/bash" ]; then
|
||||
info "Copying from toolchain chroot at ${TOOLCHAIN_CHROOT}..."
|
||||
cp -a "${TOOLCHAIN_CHROOT}"/{usr,lib,lib64,bin,sbin,etc} "${ROOTFS}"/
|
||||
|
||||
else
|
||||
warn "No pre-built base system found."
|
||||
warn "Creating minimal live environment with busybox..."
|
||||
|
||||
# Fallback: use static busybox for a minimal live shell
|
||||
if command -v busybox >/dev/null 2>&1; then
|
||||
cp "$(which busybox)" "${ROOTFS}/bin/busybox"
|
||||
# Create essential symlinks
|
||||
for cmd in sh ash ls cat cp mv rm mkdir mount umount grep sed awk vi; do
|
||||
ln -sf busybox "${ROOTFS}/bin/$cmd"
|
||||
done
|
||||
else
|
||||
# Download static busybox
|
||||
info "Downloading busybox..."
|
||||
curl -fLo "${ROOTFS}/bin/busybox" \
|
||||
"https://busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox"
|
||||
chmod +x "${ROOTFS}/bin/busybox"
|
||||
for cmd in sh ls cat cp mv rm mkdir mount umount; do
|
||||
ln -sf busybox "${ROOTFS}/bin/$cmd"
|
||||
done
|
||||
fi
|
||||
|
||||
# Copy essential libs from host
|
||||
for lib in ld-linux-x86-64.so.2 libc.so.6 libm.so.6 libdl.so.2 libpthread.so.0; do
|
||||
if [ -f "/usr/lib/$lib" ]; then
|
||||
cp "/usr/lib/$lib" "${ROOTFS}/usr/lib/"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# --- Install DarkForge-specific files ----------------------------------------
|
||||
info "Installing DarkForge configuration and tools..."
|
||||
|
||||
# Configs
|
||||
cp "${PROJECT_ROOT}/configs/rc.conf" "${ROOTFS}/etc/"
|
||||
cp "${PROJECT_ROOT}/configs/inittab" "${ROOTFS}/etc/"
|
||||
cp "${PROJECT_ROOT}/configs/fstab.template" "${ROOTFS}/etc/fstab"
|
||||
cp -a "${PROJECT_ROOT}/configs/rc.d/"* "${ROOTFS}/etc/rc.d/" 2>/dev/null || true
|
||||
cp "${PROJECT_ROOT}/configs/zprofile" "${ROOTFS}/etc/skel/.zprofile" 2>/dev/null || true
|
||||
|
||||
# Override inittab for live mode (auto-login root)
|
||||
cat > "${ROOTFS}/etc/inittab" << 'EOF'
|
||||
id:3:initdefault:
|
||||
si::sysinit:/etc/rc.d/rc.sysinit
|
||||
l3:3:wait:/etc/rc.d/rc.multi
|
||||
1:2345:respawn:/sbin/agetty --autologin root --noclear 38400 tty1 linux
|
||||
2:2345:respawn:/sbin/agetty 38400 tty2 linux
|
||||
ca::ctrlaltdel:/sbin/shutdown -r now
|
||||
EOF
|
||||
|
||||
# Installer scripts
|
||||
cp -a "${PROJECT_ROOT}/src/install/"* "${ROOTFS}/install/" 2>/dev/null || true
|
||||
cp "${PROJECT_ROOT}/configs/zprofile" "${ROOTFS}/install/configs/zprofile" 2>/dev/null || true
|
||||
mkdir -p "${ROOTFS}/install/configs"
|
||||
|
||||
# Live shell profile with installer prompt
|
||||
cat > "${ROOTFS}/root/.bash_profile" << 'PROFILE'
|
||||
echo ""
|
||||
echo " ╔══════════════════════════════════════════╗"
|
||||
echo " ║ DarkForge Linux Installer ║"
|
||||
echo " ║ ║"
|
||||
echo " ║ Type 'install' to begin installation ║"
|
||||
echo " ║ Type 'shell' for a live shell ║"
|
||||
echo " ╚══════════════════════════════════════════╝"
|
||||
echo ""
|
||||
alias install='/install/install.sh'
|
||||
alias shell='exec /bin/bash --login'
|
||||
PROFILE
|
||||
|
||||
# dpack binary
|
||||
DPACK_BIN="${PROJECT_ROOT}/src/dpack/target/release/dpack"
|
||||
if [ -f "$DPACK_BIN" ]; then
|
||||
install -m755 "$DPACK_BIN" "${ROOTFS}/usr/bin/dpack"
|
||||
ok "dpack binary installed"
|
||||
else
|
||||
warn "dpack binary not found — build it first: cd src/dpack && cargo build --release"
|
||||
fi
|
||||
|
||||
# Package repos
|
||||
cp -a "${PROJECT_ROOT}/src/repos/core" "${ROOTFS}/var/lib/dpack/repos/" 2>/dev/null || true
|
||||
cp -a "${PROJECT_ROOT}/src/repos/extra" "${ROOTFS}/var/lib/dpack/repos/" 2>/dev/null || true
|
||||
cp -a "${PROJECT_ROOT}/src/repos/desktop" "${ROOTFS}/var/lib/dpack/repos/" 2>/dev/null || true
|
||||
cp -a "${PROJECT_ROOT}/src/repos/gaming" "${ROOTFS}/var/lib/dpack/repos/" 2>/dev/null || true
|
||||
|
||||
# --- Install kernel ----------------------------------------------------------
|
||||
KERNEL_PATH=""
|
||||
for kp in "${PROJECT_ROOT}/kernel/vmlinuz" "${PROJECT_ROOT}/build/vmlinuz" /boot/vmlinuz-linux; do
|
||||
if [ -f "$kp" ]; then
|
||||
KERNEL_PATH="$kp"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$KERNEL_PATH" ]; then
|
||||
cp "$KERNEL_PATH" "${ISO_DIR}/EFI/BOOT/BOOTX64.EFI"
|
||||
ok "Kernel: ${KERNEL_PATH}"
|
||||
else
|
||||
warn "No kernel found — ISO will not be bootable!"
|
||||
warn "Build the kernel first (Phase 4) or copy vmlinuz to kernel/vmlinuz"
|
||||
echo "PLACEHOLDER" > "${ISO_DIR}/EFI/BOOT/BOOTX64.EFI"
|
||||
fi
|
||||
|
||||
# --- Create squashfs ----------------------------------------------------------
|
||||
info "Creating squashfs image..."
|
||||
mksquashfs "${ROOTFS}" "${ISO_DIR}/LiveOS/rootfs.img" \
|
||||
-comp "${SQFS_COMP}" -Xcompression-level 19 -b 1M \
|
||||
-noappend -wildcards \
|
||||
-e 'proc/*' 'sys/*' 'dev/*' 'run/*' 'tmp/*'
|
||||
|
||||
ok "squashfs: $(du -sh "${ISO_DIR}/LiveOS/rootfs.img" | cut -f1)"
|
||||
|
||||
# --- Create EFI boot image ---------------------------------------------------
|
||||
info "Creating EFI boot image..."
|
||||
ESP_IMG="${BUILD_DIR}/efiboot.img"
|
||||
ESP_SIZE=8192 # 8MB
|
||||
dd if=/dev/zero of="${ESP_IMG}" bs=1K count=${ESP_SIZE} 2>/dev/null
|
||||
mkfs.fat -F 12 "${ESP_IMG}" >/dev/null
|
||||
mmd -i "${ESP_IMG}" ::/EFI ::/EFI/BOOT
|
||||
mcopy -i "${ESP_IMG}" "${ISO_DIR}/EFI/BOOT/BOOTX64.EFI" ::/EFI/BOOT/BOOTX64.EFI
|
||||
|
||||
# --- Build ISO ----------------------------------------------------------------
|
||||
info "Building ISO..."
|
||||
xorriso -as mkisofs \
|
||||
-o "${ISO_OUTPUT}" \
|
||||
-iso-level 3 \
|
||||
-full-iso9660-filenames \
|
||||
-joliet \
|
||||
-rational-rock \
|
||||
-volid "${ISO_LABEL}" \
|
||||
-eltorito-alt-boot \
|
||||
-e "$(basename "${ESP_IMG}")" \
|
||||
-no-emul-boot \
|
||||
-isohybrid-gpt-basdat \
|
||||
-append_partition 2 0xef "${ESP_IMG}" \
|
||||
"${ISO_DIR}"
|
||||
|
||||
# --- Done ---------------------------------------------------------------------
|
||||
echo ""
|
||||
ok "═══════════════════════════════════════════════"
|
||||
ok " ISO built: ${ISO_OUTPUT}"
|
||||
ok " Size: $(du -sh "${ISO_OUTPUT}" | cut -f1)"
|
||||
ok ""
|
||||
ok " Test with:"
|
||||
ok " qemu-system-x86_64 -enable-kvm -m 4G \\"
|
||||
ok " -bios ${OVMF_PATH:-/usr/share/edk2/x64/OVMF.fd} \\"
|
||||
ok " -cdrom ${ISO_OUTPUT} -boot d"
|
||||
ok "═══════════════════════════════════════════════"
|
||||
|
||||
# Cleanup
|
||||
rm -rf "${BUILD_DIR}"
|
||||
105
src/iso/build-iso-darkforge.sh
Executable file
105
src/iso/build-iso-darkforge.sh
Executable file
@@ -0,0 +1,105 @@
|
||||
#!/bin/bash
|
||||
# ============================================================================
|
||||
# DarkForge Linux — ISO Builder (DarkForge Host)
|
||||
# ============================================================================
|
||||
# Builds a bootable DarkForge live ISO from a running DarkForge system.
|
||||
# Use this to create installer media for reinstalls or sharing.
|
||||
#
|
||||
# Requirements (DarkForge):
|
||||
# dpack install squashfs-tools xorriso mtools
|
||||
#
|
||||
# Usage:
|
||||
# sudo bash src/iso/build-iso-darkforge.sh
|
||||
#
|
||||
# Output:
|
||||
# darkforge-live.iso
|
||||
# ============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "ERROR: Must be run as root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
BUILD_DIR="/tmp/darkforge-iso-build"
|
||||
ROOTFS="${BUILD_DIR}/rootfs"
|
||||
ISO_DIR="${BUILD_DIR}/iso"
|
||||
ISO_OUTPUT="${PROJECT_ROOT}/darkforge-live.iso"
|
||||
ISO_LABEL="DARKFORGE"
|
||||
|
||||
info() { echo ">>> $1"; }
|
||||
ok() { echo ">>> $1"; }
|
||||
die() { echo "!!! $1"; exit 1; }
|
||||
|
||||
for tool in mksquashfs xorriso mkfs.fat mcopy; do
|
||||
command -v "$tool" >/dev/null 2>&1 || die "Missing: $tool"
|
||||
done
|
||||
|
||||
rm -rf "${BUILD_DIR}"
|
||||
mkdir -p "${ROOTFS}" "${ISO_DIR}"/{EFI/BOOT,LiveOS}
|
||||
|
||||
# --- Snapshot the running system into the live root --------------------------
|
||||
info "Snapshotting running system..."
|
||||
|
||||
# Copy the entire installed system (excluding virtual fs and temp)
|
||||
rsync -aAX --info=progress2 \
|
||||
--exclude='/dev/*' \
|
||||
--exclude='/proc/*' \
|
||||
--exclude='/sys/*' \
|
||||
--exclude='/tmp/*' \
|
||||
--exclude='/run/*' \
|
||||
--exclude='/mnt/*' \
|
||||
--exclude='/media/*' \
|
||||
--exclude='/lost+found' \
|
||||
--exclude='/var/tmp/*' \
|
||||
--exclude='/var/cache/dpack/sources/*' \
|
||||
--exclude='/home/*/.*cache*' \
|
||||
/ "${ROOTFS}/"
|
||||
|
||||
# Override inittab for live mode
|
||||
cat > "${ROOTFS}/etc/inittab" << 'EOF'
|
||||
id:3:initdefault:
|
||||
si::sysinit:/etc/rc.d/rc.sysinit
|
||||
l3:3:wait:/etc/rc.d/rc.multi
|
||||
1:2345:respawn:/sbin/agetty --autologin root --noclear 38400 tty1 linux
|
||||
2:2345:respawn:/sbin/agetty 38400 tty2 linux
|
||||
ca::ctrlaltdel:/sbin/shutdown -r now
|
||||
EOF
|
||||
|
||||
# Include installer
|
||||
cp -a "${PROJECT_ROOT}/src/install/"* "${ROOTFS}/install/" 2>/dev/null || true
|
||||
|
||||
# Include package repos
|
||||
mkdir -p "${ROOTFS}/var/lib/dpack/repos"
|
||||
cp -a "${PROJECT_ROOT}/src/repos/"* "${ROOTFS}/var/lib/dpack/repos/" 2>/dev/null || true
|
||||
|
||||
# Copy kernel
|
||||
cp /boot/vmlinuz "${ISO_DIR}/EFI/BOOT/BOOTX64.EFI" 2>/dev/null || \
|
||||
cp /boot/vmlinuz-*-darkforge "${ISO_DIR}/EFI/BOOT/BOOTX64.EFI" 2>/dev/null || \
|
||||
die "No kernel found in /boot/"
|
||||
|
||||
# --- Compress and build ISO ---------------------------------------------------
|
||||
info "Creating squashfs..."
|
||||
mksquashfs "${ROOTFS}" "${ISO_DIR}/LiveOS/rootfs.img" \
|
||||
-comp zstd -Xcompression-level 19 -b 1M \
|
||||
-noappend -wildcards -e 'proc/*' 'sys/*' 'dev/*' 'run/*' 'tmp/*'
|
||||
|
||||
info "Creating EFI boot image..."
|
||||
ESP_IMG="${BUILD_DIR}/efiboot.img"
|
||||
dd if=/dev/zero of="${ESP_IMG}" bs=1K count=8192 2>/dev/null
|
||||
mkfs.fat -F 12 "${ESP_IMG}" >/dev/null
|
||||
mmd -i "${ESP_IMG}" ::/EFI ::/EFI/BOOT
|
||||
mcopy -i "${ESP_IMG}" "${ISO_DIR}/EFI/BOOT/BOOTX64.EFI" ::/EFI/BOOT/BOOTX64.EFI
|
||||
|
||||
info "Building ISO..."
|
||||
xorriso -as mkisofs \
|
||||
-o "${ISO_OUTPUT}" -iso-level 3 -full-iso9660-filenames -joliet -rational-rock \
|
||||
-volid "${ISO_LABEL}" -eltorito-alt-boot \
|
||||
-e "$(basename "${ESP_IMG}")" -no-emul-boot -isohybrid-gpt-basdat \
|
||||
-append_partition 2 0xef "${ESP_IMG}" "${ISO_DIR}"
|
||||
|
||||
ok "ISO built: ${ISO_OUTPUT} ($(du -sh "${ISO_OUTPUT}" | cut -f1))"
|
||||
rm -rf "${BUILD_DIR}"
|
||||
Reference in New Issue
Block a user