particleos-installer/build-iso-bootc-native.sh

763 lines
No EOL
23 KiB
Bash
Executable file

#!/bin/bash
# ParticleOS ISO Builder - True bootc Native Approach
# This script creates a minimal live ISO that contains bootc tools
# and can install the ParticleOS OCI image to the target system
set -euo pipefail
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_NAME="particleos"
VERSION="1.0.0"
BUILD_TIMESTAMP=$(date +%y%m%d-%H%M)
BUILD_DIR="$SCRIPT_DIR/build"
OUTPUT_DIR="$SCRIPT_DIR/output"
LOG_DIR="$SCRIPT_DIR/logs/$(date +%y%m%d%H%M)"
# bootc-specific variables
SYSTEM_IMAGE="particleos-system:latest"
LIVE_IMAGE="particleos-live:latest"
CONTAINER_NAME="particleos-extract"
# apt-cacher-ng configuration
APT_CACHER_NG_HOST="192.168.1.79"
APT_CACHER_NG_PORT="3142"
APT_CACHER_NG_URL="http://$APT_CACHER_NG_HOST:$APT_CACHER_NG_PORT"
CACHER_CONTAINER_BUILD_USED="No"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging setup
mkdir -p "$LOG_DIR"
exec > >(tee -a "$LOG_DIR/build.log") 2>&1
# Utility functions
print_header() {
echo -e "${BLUE}================================${NC}"
echo -e "${BLUE}$1${NC}"
echo -e "${BLUE}================================${NC}"
}
print_status() {
echo -e "${BLUE}[INFO]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
exit 1
}
# Check if apt-cacher-ng is reachable
check_proxy_reachable() {
if command -v nc >/dev/null 2>&1; then
if nc -z "$APT_CACHER_NG_HOST" "$APT_CACHER_NG_PORT" 2>/dev/null; then
return 0
fi
fi
return 1
}
# Check prerequisites
check_prerequisites() {
print_header "Phase 1: Check Prerequisites"
local missing_packages=()
local required_packages=(
"squashfs-tools"
"xorriso"
"grub-pc-bin"
"grub-efi-amd64-signed"
"syslinux-common"
"netcat-openbsd"
"casper"
"podman"
)
for pkg in "${required_packages[@]}"; do
if ! dpkg -l | grep -q "^ii.*$pkg"; then
missing_packages+=("$pkg")
fi
done
if [ ${#missing_packages[@]} -gt 0 ]; then
print_status "Installing missing packages: ${missing_packages[*]}"
sudo apt update
sudo apt install -y "${missing_packages[@]}" || print_error "Failed to install required packages"
fi
# Check for bootc specifically (since it's not in standard repos)
if ! command -v bootc &> /dev/null; then
print_error "bootc is not installed. Please install bootc from your local packages first."
fi
# Check disk space (need at least 10GB) - check root filesystem for podman storage
local available_space=$(df / | awk 'NR==2 {print $4}')
local required_space=$((10 * 1024 * 1024)) # 10GB in KB
if [ "$available_space" -lt "$required_space" ]; then
print_error "Insufficient disk space on root filesystem. Need at least 10GB free, have $((available_space / 1024 / 1024))GB"
fi
# Check network connectivity
if ! ping -c 1 archive.ubuntu.com >/dev/null 2>&1; then
print_error "Cannot reach Ubuntu archives. Check your internet connection."
fi
print_success "All prerequisites satisfied"
}
# Clean build environment
clean_build() {
print_header "Phase 2: Clean Build Environment"
# Safety check: Ensure BUILD_DIR is within SCRIPT_DIR
if [[ "$BUILD_DIR" != "$SCRIPT_DIR"* ]]; then
print_error "BUILD_DIR must be within SCRIPT_DIR for safety"
fi
if [ -d "$BUILD_DIR" ]; then
print_status "Cleaning existing build directory..."
# Force remove any existing containers and images
podman container rm -f "$CONTAINER_NAME" 2>/dev/null || true
podman image rm -f "$SYSTEM_IMAGE" "$LIVE_IMAGE" 2>/dev/null || true
sudo rm -rf "$BUILD_DIR"
fi
mkdir -p "$BUILD_DIR" "$OUTPUT_DIR"
chmod 755 "$OUTPUT_DIR"
print_success "Build environment cleaned"
}
# Create the main ParticleOS system OCI image
create_system_image() {
print_header "Phase 3: Create ParticleOS System Image"
print_status "Creating ParticleOS system OCI image..."
# Try to use apt-cacher-ng if available for container build
local use_proxy=false
if check_proxy_reachable; then
print_status "Container build will use apt-cacher-ng: $APT_CACHER_NG_URL"
CACHER_CONTAINER_BUILD_USED="Yes"
use_proxy=true
else
print_warning "apt-cacher-ng not reachable. Container build will proceed without proxy."
CACHER_CONTAINER_BUILD_USED="No (Fallback to direct)"
use_proxy=false
fi
# Create a Dockerfile for the main system image
cat > "$BUILD_DIR/Dockerfile.system" << 'EOF'
# Start with Ubuntu 24.04 base
FROM ubuntu:24.04
# Set environment
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=UTC
# Configure apt proxy if available
EOF
# Add proxy configuration if available
if [ "$use_proxy" = true ]; then
cat >> "$BUILD_DIR/Dockerfile.system" << EOF
RUN echo 'Acquire::http::Proxy "$APT_CACHER_NG_URL";' > /etc/apt/apt.conf.d/01proxy && \\
echo 'Acquire::https::Proxy "$APT_CACHER_NG_URL";' >> /etc/apt/apt.conf.d/01proxy
EOF
fi
# Continue with the system Dockerfile
cat >> "$BUILD_DIR/Dockerfile.system" << 'EOF'
# Update and install base packages
RUN apt update && apt install -y \
systemd \
systemd-sysv \
dbus \
curl \
ca-certificates \
gnupg \
gpgv \
locales \
resolvconf \
&& rm -rf /var/lib/apt/lists/*
# Configure locales
RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8
# Block snapd installation with APT preferences
RUN echo 'Package: snapd' > /etc/apt/preferences.d/no-snapd && \
echo 'Pin: release *' >> /etc/apt/preferences.d/no-snapd && \
echo 'Pin-Priority: -1' >> /etc/apt/preferences.d/no-snapd && \
echo '' >> /etc/apt/preferences.d/no-snapd && \
echo 'Package: snap' >> /etc/apt/preferences.d/no-snapd && \
echo 'Pin: release *' >> /etc/apt/preferences.d/no-snapd && \
echo 'Pin-Priority: -1' >> /etc/apt/preferences.d/no-snapd && \
echo '' >> /etc/apt/preferences.d/no-snapd && \
echo 'Package: firefox*' >> /etc/apt/preferences.d/no-snapd && \
echo 'Pin: release o=Ubuntu*' >> /etc/apt/preferences.d/no-snapd && \
echo 'Pin-Priority: -1' >> /etc/apt/preferences.d/no-snapd
# Install desktop environment
RUN apt update && apt install -y \
plasma-desktop \
plasma-workspace \
sddm \
kwin-x11 \
flatpak \
network-manager \
plasma-nm \
openssh-server \
curl \
wget \
vim \
nano \
htop \
neofetch \
tree \
pulseaudio \
pulseaudio-utils \
fonts-ubuntu \
fonts-noto \
build-essential \
git \
&& rm -rf /var/lib/apt/lists/*
# Copy and install local packages
COPY pkgs/ /tmp/pkgs/
# Install dependencies first, then our custom packages
RUN apt update && apt install -y \
libarchive13t64 \
libavahi-client3 \
libavahi-common3 \
libavahi-glib1 \
libcurl3t64-gnutls \
libgpgme11t64 \
libglib2.0-0t64 \
podman \
skopeo \
&& rm -rf /var/lib/apt/lists/*
# Install ostree and bootc packages from local files (dynamic version detection)
RUN for pkg in /tmp/pkgs/libostree-1-1_*.deb; do \
if [ -f "$pkg" ]; then dpkg -i "$pkg"; break; fi; \
done
RUN for pkg in /tmp/pkgs/ostree_*.deb; do \
if [ -f "$pkg" ]; then dpkg -i "$pkg"; break; fi; \
done
RUN for pkg in /tmp/pkgs/bootc_*.deb; do \
if [ -f "$pkg" ]; then dpkg -i "$pkg"; break; fi; \
done
# Install apt-ostree from local packages if available
RUN for pkg in /tmp/pkgs/apt-ostree_*.deb; do \
if [ -f "$pkg" ]; then dpkg -i "$pkg"; break; fi; \
done
# Install ostree-boot (recommended by bootc)
RUN for pkg in /tmp/pkgs/ostree-boot_*.deb; do \
if [ -f "$pkg" ]; then dpkg -i "$pkg"; break; fi; \
done
# Remove unwanted packages
RUN apt purge -y ubuntu-advantage-tools || true && \
apt purge -y update-notifier || true && \
apt purge -y update-manager || true && \
apt purge -y unattended-upgrades || true && \
apt autoremove -y && \
apt clean
# Configure system
RUN echo "particleos" > /etc/hostname && \
echo "127.0.0.1 localhost" >> /etc/hosts && \
echo "127.0.1.1 particleos.local particleos" >> /etc/hosts && \
ln -sf /usr/share/zoneinfo/UTC /etc/localtime
# Create user
RUN useradd -m -s /bin/bash particle && \
usermod -aG sudo particle && \
echo 'particle ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/particle && \
chmod 0440 /etc/sudoers.d/particle
# Configure apt-ostree
RUN mkdir -p /etc/apt-ostree && \
echo "ref: particleos/desktop/1.0.0" > /etc/apt-ostree/ref
# Enable services
RUN systemctl enable sddm NetworkManager ssh && \
systemctl disable apt-daily.timer apt-daily-upgrade.timer
# Clean up
RUN rm -rf /tmp/pkgs /var/lib/apt/lists/* /tmp/*
# Set labels for bootc
LABEL org.opencontainers.image.title="ParticleOS Desktop"
LABEL org.opencontainers.image.description="Atomic Ubuntu Desktop with apt-ostree"
LABEL org.opencontainers.image.version="1.0.0"
LABEL org.opencontainers.image.vendor="ParticleOS"
LABEL org.opencontainers.image.source="https://github.com/particleos/particleos-installer"
# Expose ports
EXPOSE 22
# Set default command
CMD ["/lib/systemd/systemd"]
EOF
# Copy packages to build context
if [ -d "$SCRIPT_DIR/pkgs" ]; then
cp -r "$SCRIPT_DIR/pkgs" "$BUILD_DIR/"
fi
# Copy install script to build context
if [ -f "$SCRIPT_DIR/install-particleos" ]; then
cp "$SCRIPT_DIR/install-particleos" "$BUILD_DIR/"
fi
# Build the system image using podman
print_status "Building system image..."
cd "$BUILD_DIR"
podman build -f Dockerfile.system -t "$SYSTEM_IMAGE" . || print_error "Failed to build system image."
print_success "System image built: $SYSTEM_IMAGE"
}
# Create minimal live ISO with bootc tools
create_live_iso() {
print_header "Phase 4: Create Minimal Live ISO with bootc Tools"
print_status "Creating minimal live ISO with bootc installation tools..."
# Create a minimal Dockerfile for the live environment
cat > "$BUILD_DIR/Dockerfile.live" << 'EOF'
# Start with Ubuntu 24.04 base
FROM ubuntu:24.04
# Set environment
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=UTC
# Update and install minimal packages for live environment
RUN apt update && apt install -y \
systemd \
systemd-sysv \
dbus \
curl \
ca-certificates \
gnupg \
gpgv \
locales \
resolvconf \
live-boot \
live-config \
casper \
linux-image-generic \
linux-headers-generic \
grub-pc-bin \
grub-efi-amd64-signed \
xorriso \
squashfs-tools \
&& rm -rf /var/lib/apt/lists/*
# Configure locales
RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8
# Copy and install bootc packages
COPY pkgs/ /tmp/pkgs/
# Install dependencies first, then our custom packages
RUN apt update && apt install -y \
libarchive13t64 \
libavahi-client3 \
libavahi-common3 \
libavahi-glib1 \
libcurl3t64-gnutls \
libgpgme11t64 \
libglib2.0-0t64 \
podman \
skopeo \
&& rm -rf /var/lib/apt/lists/*
# Install ostree and bootc packages from local files (dynamic version detection)
RUN for pkg in /tmp/pkgs/libostree-1-1_*.deb; do \
if [ -f "$pkg" ]; then dpkg -i "$pkg"; break; fi; \
done
RUN for pkg in /tmp/pkgs/ostree_*.deb; do \
if [ -f "$pkg" ]; then dpkg -i "$pkg"; break; fi; \
done
RUN for pkg in /tmp/pkgs/bootc_*.deb; do \
if [ -f "$pkg" ]; then dpkg -i "$pkg"; break; fi; \
done
# Install apt-ostree from local packages if available
RUN for pkg in /tmp/pkgs/apt-ostree_*.deb; do \
if [ -f "$pkg" ]; then dpkg -i "$pkg"; break; fi; \
done
# Install ostree-boot (recommended by bootc)
RUN for pkg in /tmp/pkgs/ostree-boot_*.deb; do \
if [ -f "$pkg" ]; then dpkg -i "$pkg"; break; fi; \
done
# Configure system
RUN echo "particleos-live" > /etc/hostname && \
echo "127.0.0.1 localhost" >> /etc/hosts && \
echo "127.0.1.1 particleos-live.local particleos-live" >> /etc/hosts && \
ln -sf /usr/share/zoneinfo/UTC /etc/localtime
# Create user for live environment
RUN useradd -m -s /bin/bash particle && \
usermod -aG sudo particle && \
echo 'particle ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/particle && \
chmod 0440 /etc/sudoers.d/particle
# Create casper hook for live boot
RUN mkdir -p /etc/casper && \
echo "particleos-live" > /etc/casper/hostname && \
echo "particle" > /etc/casper/username
# Create bootc installation script
COPY install-particleos /usr/local/bin/install-particleos
RUN chmod +x /usr/local/bin/install-particleos
# Regenerate initrd to include live-boot modules
RUN update-initramfs -u -k all
# Clean up
RUN rm -rf /tmp/pkgs /var/lib/apt/lists/* /tmp/*
# Set labels
LABEL org.opencontainers.image.title="ParticleOS Live"
LABEL org.opencontainers.image.description="Minimal live environment for ParticleOS installation"
LABEL org.opencontainers.image.version="1.0.0"
LABEL org.opencontainers.image.vendor="ParticleOS"
# Set default command
CMD ["/lib/systemd/systemd"]
EOF
# Build the live image
print_status "Building live image..."
podman build -f Dockerfile.live -t "$LIVE_IMAGE" . || print_error "Failed to build live image."
# Extract the live filesystem
print_status "Extracting live filesystem..."
podman create --name "$CONTAINER_NAME" "$LIVE_IMAGE" || print_error "Failed to create container."
local extract_dir="$BUILD_DIR/extract"
mkdir -p "$extract_dir"
podman export "$CONTAINER_NAME" | tar -x -C "$extract_dir" || print_error "Failed to extract filesystem."
# Remove the temporary container
podman container rm "$CONTAINER_NAME" || print_warning "Failed to remove container"
# Verify extraction was successful
if [ ! -f "$extract_dir/etc/os-release" ]; then
print_error "Filesystem extraction failed - /etc/os-release not found"
fi
print_success "Live filesystem extracted"
}
# Create the ISO
create_iso() {
print_header "Phase 5: Create ISO"
print_status "Creating ISO from live filesystem..."
local extract_dir="$BUILD_DIR/extract"
local iso_dir="$BUILD_DIR/iso"
# Create ISO directory structure
mkdir -p "$iso_dir"/{casper,boot/grub,EFI/BOOT,isolinux}
# Find kernel and initrd
local kernel_path=$(find "$extract_dir/boot" -maxdepth 1 -name "vmlinuz-*" | sort -V | tail -n 1)
local initrd_path=$(find "$extract_dir/boot" -maxdepth 1 -name "initrd.img-*" | sort -V | tail -n 1)
if [ -z "$kernel_path" ] || [ -z "$initrd_path" ]; then
print_error "Kernel or initrd not found in extracted filesystem"
fi
# Copy kernel and initrd
cp "$kernel_path" "$iso_dir/casper/vmlinuz" || print_error "Failed to copy kernel."
cp "$initrd_path" "$iso_dir/casper/initrd" || print_error "Failed to copy initrd."
# Create squashfs (exclude boot/grub, not entire boot)
print_status "Creating squashfs..."
sudo mksquashfs "$extract_dir" "$iso_dir/casper/filesystem.squashfs" -comp xz -e boot/grub || print_error "Failed to create squashfs."
# Generate filesystem.manifest
print_status "Generating filesystem.manifest..."
sudo chroot "$extract_dir" dpkg-query -W --showformat='${Package} ${Version}\n' > "$iso_dir/casper/filesystem.manifest" || print_error "Failed to generate filesystem.manifest."
# Create filesystem.size
du -sx --block-size=1 "$extract_dir" | cut -f1 > "$iso_dir/casper/filesystem.size"
# Create casper.conf
cat > "$iso_dir/casper/casper.conf" << 'EOF'
# This file is used by casper to configure the live environment
# See casper(7) for more information
# Default options for the live environment
DEFAULT_OPTS="boot=casper quiet splash ---"
# Timeout for the boot menu (in seconds)
TIMEOUT=30
# Default selection in the boot menu
DEFAULT=0
# Enable automatic hardware detection
AUTO_DETECT=true
# Enable automatic network configuration
AUTO_NETWORK=true
# Enable automatic user creation
AUTO_USER=true
# Default username for the live environment
DEFAULT_USER=particle
# Enable automatic login
AUTO_LOGIN=true
EOF
# Find ISOLINUX files
local isolinux_base_dir=""
for dir in /usr/lib/ISOLINUX /usr/lib/syslinux /usr/share/syslinux; do
if [ -f "$dir/isolinux.bin" ]; then
isolinux_base_dir="$dir"
break
fi
done
if [ -z "$isolinux_base_dir" ]; then
print_error "ISOLINUX files not found"
fi
# Find syslinux modules directory
local syslinux_modules_dir=""
if [ -d "/usr/lib/syslinux/modules/bios" ]; then
syslinux_modules_dir="/usr/lib/syslinux/modules/bios"
elif [ -d "/usr/share/syslinux/modules/bios" ]; then
syslinux_modules_dir="/usr/share/syslinux/modules/bios"
elif [ -d "$isolinux_base_dir/modules/bios" ]; then
syslinux_modules_dir="$isolinux_base_dir/modules/bios"
fi
# Copy ISOLINUX files with robust module detection
cp "$isolinux_base_dir/isolinux.bin" "$iso_dir/isolinux/" || print_error "Failed to copy isolinux.bin"
# Copy ldlinux.c32 from modules directory if available, otherwise from base directory
if [ -f "$syslinux_modules_dir/ldlinux.c32" ]; then
cp "$syslinux_modules_dir/ldlinux.c32" "$iso_dir/isolinux/" || print_error "Failed to copy ldlinux.c32 from modules dir"
elif [ -f "$isolinux_base_dir/ldlinux.c32" ]; then
cp "$isolinux_base_dir/ldlinux.c32" "$iso_dir/isolinux/" || print_error "Failed to copy ldlinux.c32 from base dir"
else
print_error "ldlinux.c32 not found in any expected location"
fi
# Copy other modules if found
for module in menu.c32 memdisk mboot.c32 libutil.c32; do
if [ -f "$syslinux_modules_dir/$module" ]; then
cp "$syslinux_modules_dir/$module" "$iso_dir/isolinux/" || print_warning "Failed to copy $module from modules dir"
elif [ -f "$isolinux_base_dir/$module" ]; then
cp "$isolinux_base_dir/$module" "$iso_dir/isolinux/" || print_warning "Failed to copy $module from base dir"
else
print_warning "Syslinux module $module not found, ISOLINUX might have issues"
fi
done
# Copy memtest86+ if available
local memtest_paths=(
"/boot/memtest86+.bin"
"/usr/lib/memtest86+/memtest86+.bin"
"/usr/share/memtest86+/memtest86+.bin"
)
for memtest_path in "${memtest_paths[@]}"; do
if [ -f "$memtest_path" ]; then
cp "$memtest_path" "$iso_dir/isolinux/memtest86+.bin" || print_warning "Failed to copy memtest86+.bin"
cp "$memtest_path" "$iso_dir/boot/grub/memtest86+.bin" || print_warning "Failed to copy memtest86+.bin to grub"
break
fi
done
# Create isolinux.cfg
cat > "$iso_dir/isolinux/isolinux.cfg" << EOF
UI menu.c32
prompt 0
menu title ParticleOS Live
timeout 30
label live
menu label ^ParticleOS Live
menu default
kernel /casper/vmlinuz
append boot=casper quiet splash ---
label live-nomodeset
menu label ParticleOS Live (safe graphics)
kernel /casper/vmlinuz
append boot=casper quiet splash nomodeset ---
label memtest
menu label ^Memory test
kernel /isolinux/memdisk
append initrd=/isolinux/memtest86+.bin
label hd
menu label ^Boot from first hard disk
localboot 0x80
EOF
# Create GRUB configuration
cat > "$iso_dir/boot/grub/grub.cfg" << EOF
set timeout=30
set default=0
menuentry "ParticleOS Live" {
linux /casper/vmlinuz boot=casper quiet splash ---
initrd /casper/initrd
}
menuentry "ParticleOS Live (safe graphics)" {
linux /casper/vmlinuz boot=casper quiet splash nomodeset ---
initrd /casper/initrd
}
menuentry "Memory test" {
linux16 /boot/grub/memtest86+.bin
}
menuentry "Boot from first hard disk" {
set root=(hd0)
chainloader +1
}
EOF
# Create EFI boot image
print_status "Creating EFI boot image..."
grub-mkimage -o "$iso_dir/EFI/BOOT/bootx64.efi" \
-p "/boot/grub" \
-O x86_64-efi \
boot linux normal configfile part_gpt part_msdos fat squash4 test configfile search loadenv efi_gop efi_uga all_video gfxterm_menu chain iso9660 || print_error "Failed to create EFI boot image."
# Create the ISO
print_status "Creating ISO with xorriso..."
xorriso -as mkisofs \
-o "$OUTPUT_DIR/${PROJECT_NAME}-${BUILD_TIMESTAMP}.iso" \
-J -joliet-long \
-r -V "ParticleOS ${VERSION}" \
-b isolinux/isolinux.bin \
-c isolinux/boot.cat \
-boot-load-size 4 -boot-info-table \
-no-emul-boot \
-eltorito-alt-boot \
-e EFI/BOOT/bootx64.efi \
-no-emul-boot \
-isohybrid-mbr "$isolinux_base_dir/isohdpfx.bin" \
-partition_offset 16 \
-part_like_isohybrid \
"$iso_dir" || print_error "Failed to create ISO with xorriso."
print_success "ISO created: $OUTPUT_DIR/${PROJECT_NAME}-${BUILD_TIMESTAMP}.iso"
}
# Cleanup function
cleanup() {
print_status "Cleaning up..."
# Remove temporary containers and images
podman container rm -f "$CONTAINER_NAME" 2>/dev/null || true
podman image rm -f "$SYSTEM_IMAGE" "$LIVE_IMAGE" 2>/dev/null || true
# Remove build directory
if [ -d "$BUILD_DIR" ]; then
sudo rm -rf "$BUILD_DIR"
fi
print_success "Cleanup completed"
}
# Main execution
main() {
echo "$(date): Starting ParticleOS ISO build with true bootc approach"
echo "$(date): Log directory: $LOG_DIR"
echo -e "${GREEN}🚀 ParticleOS ISO Builder (True bootc Native)${NC}"
echo "======================================"
echo "Project: $PROJECT_NAME"
echo "Version: $VERSION"
echo "Build Directory: $BUILD_DIR"
echo "Tool: True bootc + Minimal Live ISO"
echo ""
echo -e "${BLUE}🔄 This build creates:${NC}"
echo " • OCI system image for deployment"
echo " • Minimal live ISO with bootc tools"
echo " • Live environment can install OCI image"
echo " • True bootc-managed target system"
echo ""
# Set up signal handlers
trap cleanup EXIT
trap 'print_error "Build interrupted by user"' INT TERM
# Execute build phases
check_prerequisites
clean_build
create_system_image
create_live_iso
create_iso
echo ""
echo -e "${GREEN}================================${NC}"
echo -e "${GREEN}🎉 Build Completed Successfully!${NC}"
echo -e "${GREEN}================================${NC}"
echo ""
echo -e "${BLUE}📦 Generated Files:${NC}"
echo " • System Image: $SYSTEM_IMAGE"
echo " • Live Image: $LIVE_IMAGE"
echo " • ISO: $OUTPUT_DIR/${PROJECT_NAME}-${BUILD_TIMESTAMP}.iso"
echo ""
echo -e "${BLUE}📋 Summary of Cacher Usage:${NC}"
echo " • Container Build: $CACHER_CONTAINER_BUILD_USED"
echo ""
echo -e "${BLUE}🚀 Next Steps:${NC}"
echo " 1. Test the ISO in QEMU:"
echo " qemu-system-x86_64 -m 4G -enable-kvm -cdrom $OUTPUT_DIR/${PROJECT_NAME}-${BUILD_TIMESTAMP}.iso"
echo ""
echo " 2. Boot from ISO and install:"
echo " ./install-particleos /dev/sda"
echo ""
echo -e "${BLUE}📝 Logs:${NC}"
echo " • Build log: $LOG_DIR/build.log"
echo ""
}
# Run main function
main "$@"