🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
262 lines
9.2 KiB
Bash
Executable File
262 lines
9.2 KiB
Bash
Executable File
#!/bin/bash
|
|
# Build Dangerous Pi image using pi-gen
|
|
set -e
|
|
|
|
# Colors for output
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Configuration
|
|
PI_GEN_DIR="/home/work/pi-gen-builder" # Official pi-gen builder
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
PM3_STAGE_DIR="$SCRIPT_DIR/pi-gen/stagePM3"
|
|
DTPI_STAGE_DIR="$SCRIPT_DIR/pi-gen/stageDangerousPi"
|
|
CONFIG_FILE="$SCRIPT_DIR/pi-gen/config"
|
|
KEEP_CONTAINER=0
|
|
|
|
# Parse flags
|
|
for arg in "$@"; do
|
|
case $arg in
|
|
--keep-container)
|
|
KEEP_CONTAINER=1
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Verify pi-gen directory exists
|
|
if [ ! -d "$PI_GEN_DIR" ]; then
|
|
echo "Error: pi-gen directory not found at $PI_GEN_DIR"
|
|
echo "Please run: cd /home/work && git clone https://github.com/RPi-Distro/pi-gen.git pi-gen-builder"
|
|
exit 1
|
|
fi
|
|
|
|
echo -e "${GREEN}Using pi-gen at: $PI_GEN_DIR${NC}"
|
|
|
|
# Build frontend
|
|
build_frontend() {
|
|
echo -e "${GREEN}Building frontend...${NC}"
|
|
cd "$SCRIPT_DIR/app/frontend"
|
|
|
|
# Check if npm is available
|
|
if ! command -v npm &> /dev/null; then
|
|
echo -e "${YELLOW}WARNING: npm not found, skipping frontend build${NC}"
|
|
echo -e "${YELLOW}Install Node.js to build frontend: https://nodejs.org/${NC}"
|
|
cd "$SCRIPT_DIR"
|
|
return 1
|
|
fi
|
|
|
|
# Install dependencies if needed
|
|
if [ ! -d "node_modules" ]; then
|
|
echo -e "${GREEN}Installing frontend dependencies...${NC}"
|
|
npm install
|
|
fi
|
|
|
|
# Build the frontend
|
|
echo -e "${GREEN}Running npm build...${NC}"
|
|
npm run build
|
|
|
|
echo -e "${GREEN}✓ Frontend build complete${NC}"
|
|
cd "$SCRIPT_DIR"
|
|
return 0
|
|
}
|
|
|
|
# Helper function to copy stages
|
|
copy_stages() {
|
|
cd "$PI_GEN_DIR"
|
|
|
|
# Copy config
|
|
cp "$CONFIG_FILE" config
|
|
|
|
# Copy PM3 stage
|
|
rm -rf stagePM3
|
|
cp -r "$PM3_STAGE_DIR" .
|
|
|
|
# Copy DangerousPi stage
|
|
rm -rf stageDangerousPi
|
|
cp -r "$DTPI_STAGE_DIR" .
|
|
|
|
# Remove intermediate image exports (we only want the final image)
|
|
rm -f stage2/EXPORT_IMAGE
|
|
|
|
# Build frontend before copying
|
|
if build_frontend; then
|
|
echo -e "${GREEN}Frontend built successfully${NC}"
|
|
else
|
|
echo -e "${YELLOW}Continuing without frontend build${NC}"
|
|
fi
|
|
|
|
# Return to pi-gen directory
|
|
cd "$PI_GEN_DIR"
|
|
|
|
# Copy Dangerous Pi source files into the stage
|
|
echo -e "${GREEN}Copying Dangerous Pi source files...${NC}"
|
|
mkdir -p stageDangerousPi/03-dangerous-pi/files
|
|
cp -r "$SCRIPT_DIR/app" stageDangerousPi/03-dangerous-pi/files/
|
|
cp -r "$SCRIPT_DIR/systemd" stageDangerousPi/03-dangerous-pi/files/
|
|
cp -r "$SCRIPT_DIR/scripts" stageDangerousPi/03-dangerous-pi/files/
|
|
cp "$SCRIPT_DIR/requirements.txt" stageDangerousPi/03-dangerous-pi/files/
|
|
}
|
|
|
|
# Build type
|
|
BUILD_TYPE="${1:-full}"
|
|
|
|
case "$BUILD_TYPE" in
|
|
full)
|
|
echo -e "${GREEN}Starting full build (all stages)...${NC}"
|
|
|
|
# Remove container but KEEP the volume for caching
|
|
if docker ps -a --filter name=pigen_work --format "{{.Names}}" | grep -q pigen_work; then
|
|
echo -e "${YELLOW}Removing existing container (keeping cache)...${NC}"
|
|
docker rm pigen_work > /dev/null 2>&1 || true
|
|
fi
|
|
|
|
copy_stages
|
|
|
|
# Remove any SKIP files to ensure full build
|
|
rm -f stage0/SKIP stage1/SKIP stage2/SKIP stagePM3/SKIP stageDangerousPi/SKIP
|
|
|
|
# Full build (uses docker, no root needed)
|
|
PIGEN_DOCKER_MODE=1 ./build-docker.sh
|
|
;;
|
|
|
|
from-pm3)
|
|
echo -e "${GREEN}Building from PM3 stage (PM3 + DangerousPi)...${NC}"
|
|
copy_stages
|
|
|
|
# Skip early stages if cached
|
|
if ls work/*/stage2/*.qcow2 2>/dev/null | grep -q .; then
|
|
echo -e "${GREEN}Found cached stage2, creating SKIP markers...${NC}"
|
|
touch stage0/SKIP stage1/SKIP stage2/SKIP
|
|
echo -e "${GREEN}Will build: stagePM3 → stageDangerousPi${NC}"
|
|
else
|
|
echo -e "${YELLOW}No cached stages found - will build all stages${NC}"
|
|
rm -f stage0/SKIP stage1/SKIP stage2/SKIP
|
|
fi
|
|
|
|
# Ensure PM3 and DangerousPi stages build
|
|
rm -f stagePM3/SKIP stageDangerousPi/SKIP
|
|
|
|
# Build with continue flag
|
|
CONTINUE=1 PIGEN_DOCKER_MODE=1 ./build-docker.sh
|
|
;;
|
|
|
|
from-dtpi)
|
|
echo -e "${GREEN}Building from DangerousPi stage (customizations only)...${NC}"
|
|
copy_stages
|
|
|
|
# Check for cached PM3 stage
|
|
if ls work/*/stagePM3/*.qcow2 2>/dev/null | grep -q .; then
|
|
echo -e "${GREEN}Found cached stagePM3, creating SKIP markers...${NC}"
|
|
touch stage0/SKIP stage1/SKIP stage2/SKIP stagePM3/SKIP
|
|
echo -e "${GREEN}Will build: stageDangerousPi only (~5 min)${NC}"
|
|
else
|
|
echo -e "${YELLOW}WARNING: No cached PM3 stage found!${NC}"
|
|
echo -e "${YELLOW}You need to run './build-image.sh full' or './build-image.sh from-pm3' first${NC}"
|
|
echo -e "${YELLOW}Falling back to full build from PM3...${NC}"
|
|
touch stage0/SKIP stage1/SKIP stage2/SKIP
|
|
rm -f stagePM3/SKIP
|
|
fi
|
|
|
|
# Ensure DangerousPi stage builds
|
|
rm -f stageDangerousPi/SKIP
|
|
|
|
# Build with continue flag
|
|
CONTINUE=1 PIGEN_DOCKER_MODE=1 ./build-docker.sh
|
|
;;
|
|
|
|
clean)
|
|
echo -e "${YELLOW}Removing ALL build cache and container...${NC}"
|
|
if docker ps -a --filter name=pigen_work --format "{{.Names}}" | grep -q pigen_work; then
|
|
docker rm -v pigen_work > /dev/null 2>&1 || true
|
|
echo -e "${GREEN}✓ Removed container and volume${NC}"
|
|
else
|
|
docker volume rm pigen_work > /dev/null 2>&1 || true
|
|
echo -e "${GREEN}✓ Removed volume${NC}"
|
|
fi
|
|
echo ""
|
|
echo "Cache wiped. Next build will be from scratch."
|
|
exit 0
|
|
;;
|
|
|
|
test)
|
|
echo -e "${GREEN}Validating stage scripts...${NC}"
|
|
|
|
# Syntax check - PM3 build
|
|
bash -n "$PM3_STAGE_DIR/01-proxmark3/00-run-chroot.sh"
|
|
|
|
# Syntax check - WiFi AP
|
|
bash -n "$DTPI_STAGE_DIR/01-Wireless-AP/00-run-chroot.sh"
|
|
|
|
# Syntax check - ttyd
|
|
bash -n "$DTPI_STAGE_DIR/02-ttyd/00-run-chroot.sh"
|
|
|
|
# Syntax check - Dangerous Pi
|
|
bash -n "$DTPI_STAGE_DIR/03-dangerous-pi/00-run.sh"
|
|
bash -n "$DTPI_STAGE_DIR/03-dangerous-pi/00-run-chroot.sh"
|
|
bash -n "$DTPI_STAGE_DIR/03-dangerous-pi/01-run-chroot.sh"
|
|
|
|
echo -e "${GREEN}✓ All scripts pass syntax validation${NC}"
|
|
|
|
# Check required files exist
|
|
[ -d "$(dirname "$0")/app" ] || { echo "Error: app/ directory not found"; exit 1; }
|
|
[ -f "$(dirname "$0")/requirements.txt" ] || { echo "Error: requirements.txt not found"; exit 1; }
|
|
[ -d "$(dirname "$0")/systemd" ] || { echo "Error: systemd/ directory not found"; exit 1; }
|
|
|
|
echo -e "${GREEN}✓ All required files exist${NC}"
|
|
;;
|
|
|
|
*)
|
|
echo "Usage: $0 {full|from-pm3|from-dtpi|test|clean} [--keep-container]"
|
|
echo ""
|
|
echo "Build Commands:"
|
|
echo " full - Build all stages (~1 hour first time, cached after)"
|
|
echo " Use for: First build or when base system needs updates"
|
|
echo " ✓ Preserves cache for fast rebuilds"
|
|
echo ""
|
|
echo " from-pm3 - Rebuild PM3 + customizations (~15 min with cache)"
|
|
echo " Use for: Updating Proxmark3 firmware/client"
|
|
echo " Skips: stage0, stage1, stage2 (uses cache)"
|
|
echo ""
|
|
echo " from-dtpi - Rebuild only customizations (~5 min) ⭐"
|
|
echo " Use for: Daily development, app changes"
|
|
echo " Skips: stage0, stage1, stage2, stagePM3 (uses cache)"
|
|
echo " Requires: Previous 'full' or 'from-pm3' build"
|
|
echo ""
|
|
echo "Utility Commands:"
|
|
echo " test - Validate all scripts without building"
|
|
echo " clean - Wipe ALL cache (next build will be from scratch)"
|
|
echo ""
|
|
echo "Flags:"
|
|
echo " --keep-container - Keep Docker container after build (for debugging)"
|
|
echo " Default: Auto-cleanup container, preserve cache"
|
|
echo ""
|
|
echo "Cache Info:"
|
|
echo " All builds now preserve cache in Docker volume 'pigen_work'"
|
|
echo " Use 'clean' only if you need to completely start over"
|
|
echo ""
|
|
echo "Stage Structure:"
|
|
echo " stage0, stage1, stage2 → Base Raspberry Pi OS (cached)"
|
|
echo " stagePM3 → Proxmark3 build (cached)"
|
|
echo " stageDangerousPi → WiFi AP + ttyd + your app"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
echo -e "${GREEN}Build complete!${NC}"
|
|
echo "Image location: $PI_GEN_DIR/deploy/"
|
|
|
|
# Clean up container but preserve work volume for future builds
|
|
if [ $KEEP_CONTAINER -eq 0 ]; then
|
|
if docker ps -a --filter name=pigen_work --format "{{.Names}}" | grep -q pigen_work; then
|
|
echo -e "${GREEN}Cleaning up build container (preserving cache)...${NC}"
|
|
docker rm pigen_work > /dev/null 2>&1
|
|
echo -e "${GREEN}✓ Container removed, cache preserved for fast rebuilds${NC}"
|
|
fi
|
|
else
|
|
echo -e "${YELLOW}Container kept for debugging (--keep-container flag)${NC}"
|
|
echo "Inspect with: docker exec -it pigen_work bash"
|
|
echo "Remove with: docker rm -v pigen_work"
|
|
fi
|