#!/bin/bash # # Archipelago Complete ISO Build System # ===================================== # # This script builds a complete, flashable ISO from source with one command. # It handles backend compilation, frontend bundling, and ISO creation. # # Usage: # ./build-iso-complete.sh [options] # # Options: # --local Build everything locally (requires Rust + Node.js) # --remote HOST Build on remote server (recommended for ARM -> x86 cross-compile) # --skip-backend Skip backend compilation (use existing binary) # --skip-frontend Skip frontend build (use existing dist) # --clean Clean all build artifacts before building # --help Show this help message # # Examples: # ./build-iso-complete.sh --remote archipelago@192.168.1.228 # ./build-iso-complete.sh --local --clean # # Auto-installer from live server: when using --remote HOST, the ISO script # (build-auto-installer-iso.sh) is run with DEV_SERVER=HOST so it captures # backend, frontend, and container images from that host. Alternatively run # DEV_SERVER=archipelago@192.168.1.228 ./image-recipe/build-auto-installer-iso.sh # to build the auto-installer ISO with live capture only (no backend/frontend build). # set -e # Exit on error # ============================================================================= # Configuration # ============================================================================= SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BUILD_DIR="$SCRIPT_DIR/image-recipe/build" BACKEND_SRC="$SCRIPT_DIR/core/archipelago" FRONTEND_SRC="$SCRIPT_DIR/neode-ui" ISO_SCRIPT="$SCRIPT_DIR/image-recipe/build-auto-installer-iso.sh" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Build options (defaults) BUILD_MODE="remote" REMOTE_HOST="" SKIP_BACKEND=false SKIP_FRONTEND=false CLEAN_BUILD=false # ============================================================================= # Helper Functions # ============================================================================= print_header() { echo "" echo -e "${BLUE}╔════════════════════════════════════════════════════════╗${NC}" echo -e "${BLUE}║${NC} $1" echo -e "${BLUE}╚════════════════════════════════════════════════════════╝${NC}" echo "" } print_success() { echo -e "${GREEN}✅ $1${NC}" } print_error() { echo -e "${RED}❌ $1${NC}" } print_warning() { echo -e "${YELLOW}⚠️ $1${NC}" } print_info() { echo -e "${BLUE}ℹ️ $1${NC}" } show_help() { head -n 25 "$0" | grep "^#" | sed 's/^# //' | sed 's/^#//' exit 0 } check_command() { if ! command -v "$1" &> /dev/null; then print_error "$1 is not installed" return 1 fi return 0 } # ============================================================================= # Parse Arguments # ============================================================================= while [[ $# -gt 0 ]]; do case $1 in --local) BUILD_MODE="local" shift ;; --remote) BUILD_MODE="remote" REMOTE_HOST="$2" shift 2 ;; --skip-backend) SKIP_BACKEND=true shift ;; --skip-frontend) SKIP_FRONTEND=true shift ;; --clean) CLEAN_BUILD=true shift ;; --help|-h) show_help ;; *) print_error "Unknown option: $1" show_help ;; esac done # ============================================================================= # Pre-flight Checks # ============================================================================= print_header "Archipelago Complete ISO Builder" print_info "Build mode: $BUILD_MODE" [[ -n "$REMOTE_HOST" ]] && print_info "Remote host: $REMOTE_HOST" [[ "$SKIP_BACKEND" = true ]] && print_warning "Skipping backend build" [[ "$SKIP_FRONTEND" = true ]] && print_warning "Skipping frontend build" [[ "$CLEAN_BUILD" = true ]] && print_warning "Clean build enabled" echo "" # Check for required commands if [[ "$BUILD_MODE" == "remote" ]] && [[ -z "$REMOTE_HOST" ]]; then print_error "Remote build mode requires --remote HOST" exit 1 fi if [[ "$BUILD_MODE" == "remote" ]]; then if ! check_command ssh; then exit 1 fi if ! check_command rsync; then exit 1 fi fi # ============================================================================= # Step 1: Clean Build Artifacts (if requested) # ============================================================================= if [[ "$CLEAN_BUILD" = true ]]; then print_header "Cleaning Build Artifacts" if [[ "$SKIP_BACKEND" = false ]]; then print_info "Cleaning backend..." rm -rf "$BACKEND_SRC/target" print_success "Backend cleaned" fi if [[ "$SKIP_FRONTEND" = false ]]; then print_info "Cleaning frontend..." rm -rf "$FRONTEND_SRC/dist" rm -rf "$FRONTEND_SRC/node_modules/.vite" print_success "Frontend cleaned" fi print_info "Cleaning ISO build directory..." rm -rf "$BUILD_DIR" rm -rf "$SCRIPT_DIR/image-recipe/iso-workdir" rm -rf "$SCRIPT_DIR/image-recipe/results" print_success "ISO build artifacts cleaned" fi # ============================================================================= # Step 2: Build Backend # ============================================================================= if [[ "$SKIP_BACKEND" = false ]]; then print_header "Building Backend (Rust)" if [[ "$BUILD_MODE" == "local" ]]; then print_info "Building backend locally..." cd "$BACKEND_SRC" if ! check_command cargo; then print_error "Rust/Cargo not installed. Install from: https://rustup.rs" exit 1 fi cargo build --release # Copy to build directory mkdir -p "$BUILD_DIR/backend" cp target/release/archipelago "$BUILD_DIR/backend/" chmod +x "$BUILD_DIR/backend/archipelago" print_success "Backend built locally" elif [[ "$BUILD_MODE" == "remote" ]]; then print_info "Building backend on remote server: $REMOTE_HOST" # Sync source code to remote print_info "Syncing source code to remote..." ssh "$REMOTE_HOST" "mkdir -p ~/archy-build" rsync -az --delete \ --exclude 'target/' \ --exclude 'node_modules/' \ --exclude '.git/' \ "$BACKEND_SRC/" "$REMOTE_HOST:~/archy-build/core/archipelago/" # Build on remote print_info "Compiling backend on remote..." ssh "$REMOTE_HOST" "cd ~/archy-build/core/archipelago && cargo build --release" # Copy binary back mkdir -p "$BUILD_DIR/backend" print_info "Copying binary back to local..." scp "$REMOTE_HOST:~/archy-build/core/archipelago/target/release/archipelago" "$BUILD_DIR/backend/" chmod +x "$BUILD_DIR/backend/archipelago" print_success "Backend built on remote server" fi # Verify binary if [[ ! -f "$BUILD_DIR/backend/archipelago" ]]; then print_error "Backend binary not found after build!" exit 1 fi BINARY_SIZE=$(du -h "$BUILD_DIR/backend/archipelago" | awk '{print $1}') print_success "Backend binary ready ($BINARY_SIZE)" else print_warning "Skipping backend build (using existing binary)" if [[ ! -f "$BUILD_DIR/backend/archipelago" ]]; then print_error "No existing backend binary found at $BUILD_DIR/backend/archipelago" exit 1 fi fi # ============================================================================= # Step 3: Build Frontend # ============================================================================= if [[ "$SKIP_FRONTEND" = false ]]; then print_header "Building Frontend (Vue.js)" cd "$FRONTEND_SRC" if ! check_command npm; then print_error "Node.js/npm not installed. Install from: https://nodejs.org" exit 1 fi # Install dependencies if needed if [[ ! -d "node_modules" ]] || [[ "$CLEAN_BUILD" = true ]]; then print_info "Installing dependencies..." npm install fi # Build frontend print_info "Building frontend..." npm run build # Copy to build directory mkdir -p "$BUILD_DIR/frontend" cp -r dist/* "$BUILD_DIR/frontend/" print_success "Frontend built" # Verify dist if [[ ! -d "$BUILD_DIR/frontend" ]] || [[ -z "$(ls -A "$BUILD_DIR/frontend")" ]]; then print_error "Frontend build directory is empty!" exit 1 fi DIST_SIZE=$(du -sh "$BUILD_DIR/frontend" | awk '{print $1}') print_success "Frontend assets ready ($DIST_SIZE)" else print_warning "Skipping frontend build (using existing dist)" if [[ ! -d "$BUILD_DIR/frontend" ]] || [[ -z "$(ls -A "$BUILD_DIR/frontend")" ]]; then print_error "No existing frontend build found at $BUILD_DIR/frontend" exit 1 fi fi # ============================================================================= # Step 4: Build ISO # ============================================================================= print_header "Building Bootable ISO" # Check if running on remote or need to transfer if [[ "$BUILD_MODE" == "remote" ]]; then print_info "Transferring build artifacts to remote server..." # Sync entire project to remote ssh "$REMOTE_HOST" "mkdir -p ~/archy" rsync -az --delete \ --exclude '.git/' \ --exclude 'node_modules/' \ --exclude 'core/target/' \ --exclude 'core/parmanode/' \ "$SCRIPT_DIR/" "$REMOTE_HOST:~/archy/" print_success "Files synced to remote" print_info "Running ISO build on remote server (auto-installer, DEV_SERVER=$REMOTE_HOST)..." ssh -t "$REMOTE_HOST" "cd ~/archy/image-recipe && DEV_SERVER=$REMOTE_HOST sudo -E bash build-auto-installer-iso.sh" || { print_error "ISO build failed on remote server" exit 1 } print_success "ISO built on remote server" # Copy ISO back to local ISO_NAME="archipelago-installer-x86_64.iso" print_info "Copying ISO back to local machine..." mkdir -p "$SCRIPT_DIR/image-recipe/results" scp "$REMOTE_HOST:~/archy/image-recipe/results/$ISO_NAME" "$SCRIPT_DIR/image-recipe/results/" ISO_PATH="$SCRIPT_DIR/image-recipe/results/$ISO_NAME" else # Local build print_info "Running ISO build locally (auto-installer)..." cd "$SCRIPT_DIR/image-recipe" sudo bash build-auto-installer-iso.sh ISO_PATH="$SCRIPT_DIR/image-recipe/results/archipelago-installer-x86_64.iso" fi # ============================================================================= # Step 5: Verify and Report # ============================================================================= print_header "Build Complete!" if [[ -f "$ISO_PATH" ]]; then ISO_SIZE=$(du -h "$ISO_PATH" | awk '{print $1}') ISO_MD5=$(md5 -q "$ISO_PATH" 2>/dev/null || md5sum "$ISO_PATH" | awk '{print $1}') echo "" echo -e "${GREEN}✅ ISO ready for flashing!${NC}" echo "" echo -e " 📀 ${BLUE}ISO:${NC} $ISO_PATH" echo -e " 📏 ${BLUE}Size:${NC} $ISO_SIZE" echo -e " 🔐 ${BLUE}MD5:${NC} $ISO_MD5" echo "" echo -e "${YELLOW}Next steps:${NC}" echo "" echo " 1. Insert USB drive" echo " 2. Find device: ${BLUE}diskutil list${NC}" echo " 3. Flash ISO:" echo "" echo " ${BLUE}cd image-recipe && ./write-usb-dd.sh /dev/diskN${NC}" echo "" echo " 4. Boot from USB on target device" echo "" # Create a flash script for convenience cat > "$SCRIPT_DIR/flash-to-usb.sh" <<'FLASH_EOF' #!/bin/bash # Quick USB flash script cd "$(dirname "$0")/image-recipe" && ./write-usb-dd.sh "$@" FLASH_EOF chmod +x "$SCRIPT_DIR/flash-to-usb.sh" print_success "Created convenience script: ./flash-to-usb.sh" else print_error "ISO not found at expected location: $ISO_PATH" exit 1 fi # ============================================================================= # Done! # ============================================================================= echo "" echo -e "${GREEN}╔════════════════════════════════════════════════════════╗${NC}" echo -e "${GREEN}║ 🎉 Build Complete - Ready to Flash! ║${NC}" echo -e "${GREEN}╚════════════════════════════════════════════════════════╝${NC}" echo ""