#!/bin/bash # unpack_and_offline_build_airgap_macos.sh # ============================================================================ # Execution Environment: OFFLINE (Air-gapped, No Internet) # Purpose: Extract bundle and run offline build # ============================================================================ # macOS Bash Script # Version: 3.1 # # IMPORTANT: This script automatically: # 1. Extracts the archive # 2. Sets GRADLE_USER_HOME to project local cache # 3. Configures settings.gradle for offline resolution # 4. Runs build with --offline flag # ============================================================================ set -e # ============================================================================ # Configuration # ============================================================================ WRAPPER_SEED_PATH="wrapper_jar_seed" OFFLINE_HOME_NAME="_offline_gradle_home" # Color codes RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' GRAY='\033[0;90m' WHITE='\033[1;37m' NC='\033[0m' # No Color echo "" echo -e "${CYAN}============================================================${NC}" echo -e "${CYAN} Gradle Offline Build Runner (macOS)${NC}" echo -e "${CYAN} Environment: AIR-GAPPED (No Internet)${NC}" echo -e "${CYAN} Mode: Fully Offline (--offline enforced)${NC}" echo -e "${CYAN}============================================================${NC}" echo "" # ============================================================================ # [1/16] Check Current Directory # ============================================================================ echo -e "${YELLOW}==[1/16] Check Current Directory ==${NC}" START_DIR="$(pwd)" echo "PWD: $START_DIR" echo "" # ============================================================================ # [2/16] Select Archive # ============================================================================ echo -e "${YELLOW}==[2/16] Select Archive ==${NC}" ARCHIVE="" if [ $# -ge 1 ]; then ARCHIVE="$1" fi if [ -z "$ARCHIVE" ]; then # Auto-detect most recent .tar.gz file (macOS compatible) ARCHIVE=$(find "$START_DIR" -maxdepth 1 -type f \( -name "*.tar.gz" -o -name "*.tgz" \) -exec stat -f "%m %N" {} \; 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2-) if [ -z "$ARCHIVE" ]; then echo -e "${RED}[ERROR] No archive found${NC}" ls -lh "$START_DIR" exit 1 fi echo -e "${CYAN}[AUTO] $(basename "$ARCHIVE")${NC}" else if [ ! -f "$ARCHIVE" ]; then ARCHIVE="$START_DIR/$ARCHIVE" fi echo -e "${CYAN}[USER] $(basename "$ARCHIVE")${NC}" fi if [ ! -f "$ARCHIVE" ]; then echo -e "${RED}ERROR: Archive not found: $ARCHIVE${NC}" exit 1 fi # macOS stat command ARCHIVE_SIZE=$(stat -f%z "$ARCHIVE" 2>/dev/null) ARCHIVE_SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $ARCHIVE_SIZE / 1048576}") echo "Size: ${ARCHIVE_SIZE_MB} MB" echo "" # ============================================================================ # [3/16] Check tar # ============================================================================ echo -e "${YELLOW}==[3/16] Check tar ==${NC}" if ! command -v tar &>/dev/null; then echo -e "${RED}ERROR: tar not found${NC}" exit 1 fi echo -e "${GREEN}[OK] tar found${NC}" echo "" # ============================================================================ # [4/16] Extract Archive # ============================================================================ echo -e "${YELLOW}==[4/16] Extract Archive ==${NC}" echo -e "${GRAY}[INFO] Extracting...${NC}" tar -xzf "$ARCHIVE" -C "$START_DIR" if [ $? -ne 0 ]; then echo -e "${RED}ERROR: Extraction failed${NC}" exit 1 fi echo -e "${GREEN}[OK] Extracted${NC}" echo "" # ============================================================================ # [5/16] Set Permissions # ============================================================================ echo -e "${YELLOW}==[5/16] Set Permissions ==${NC}" chmod -R u+rw "$START_DIR" 2>/dev/null || true # Remove extended attributes that macOS may add xattr -cr "$START_DIR" 2>/dev/null || true echo -e "${GREEN}[OK] Permissions set${NC}" echo "" # ============================================================================ # [6/16] Find Project Root # ============================================================================ echo -e "${YELLOW}==[6/16] Find Project Root ==${NC}" GRADLEW=$(find "$START_DIR" -name "gradlew" -type f 2>/dev/null | sort | head -1) if [ -z "$GRADLEW" ]; then echo -e "${RED}ERROR: gradlew not found${NC}" exit 1 fi PROJECT_DIR=$(dirname "$GRADLEW") echo -e "${CYAN}Project: $PROJECT_DIR${NC}" cd "$PROJECT_DIR" echo "" # ============================================================================ # [7/16] Fix Permissions # ============================================================================ echo -e "${YELLOW}==[7/16] Fix Permissions ==${NC}" chmod +x ./gradlew find . -name "*.sh" -type f -exec chmod +x {} \; 2>/dev/null || true # Remove quarantine attributes that macOS adds to downloaded files xattr -d com.apple.quarantine ./gradlew 2>/dev/null || true find . -name "*.jar" -exec xattr -d com.apple.quarantine {} \; 2>/dev/null || true echo -e "${GREEN}[OK] Permissions fixed${NC}" echo "" # ============================================================================ # [8/16] Verify Wrapper # ============================================================================ echo -e "${YELLOW}==[8/16] Verify Wrapper ==${NC}" WRAPPER_DIR="$PROJECT_DIR/gradle/wrapper" WRAPPER_JAR="$WRAPPER_DIR/gradle-wrapper.jar" WRAPPER_PROP="$WRAPPER_DIR/gradle-wrapper.properties" if [ ! -f "$WRAPPER_PROP" ]; then echo -e "${RED}ERROR: gradle-wrapper.properties missing${NC}" exit 1 fi if [ ! -f "$WRAPPER_JAR" ]; then SEED_JAR="$PROJECT_DIR/$WRAPPER_SEED_PATH/gradle-wrapper.jar" if [ -f "$SEED_JAR" ]; then mkdir -p "$WRAPPER_DIR" cp "$SEED_JAR" "$WRAPPER_JAR" echo -e "${GREEN}[OK] Injected from seed${NC}" else echo -e "${RED}ERROR: wrapper jar missing${NC}" exit 1 fi else echo -e "${GREEN}[OK] Wrapper verified${NC}" fi echo "" # ============================================================================ # [9/16] Set GRADLE_USER_HOME # ============================================================================ echo -e "${YELLOW}==[9/16] Set GRADLE_USER_HOME ==${NC}" OFFLINE_HOME="$PROJECT_DIR/$OFFLINE_HOME_NAME" if [ ! -d "$OFFLINE_HOME" ]; then echo -e "${RED}ERROR: _offline_gradle_home not found in archive${NC}" exit 1 fi export GRADLE_USER_HOME="$OFFLINE_HOME" echo -e "${CYAN}GRADLE_USER_HOME = $GRADLE_USER_HOME${NC}" # Check cache CACHES_DIR="$OFFLINE_HOME/caches" if [ -d "$CACHES_DIR" ]; then # macOS du command if du -k "$CACHES_DIR" &>/dev/null; then CACHE_SIZE=$(du -sk "$CACHES_DIR" 2>/dev/null | cut -f1) CACHE_SIZE=$((CACHE_SIZE * 1024)) else CACHE_SIZE=0 fi CACHE_SIZE_MB=$(awk "BEGIN {printf \"%.2f\", $CACHE_SIZE / 1048576}") echo -e "${CYAN}[INFO] Cache size: ${CACHE_SIZE_MB} MB${NC}" else echo -e "${YELLOW}[WARN] No cache folder found${NC}" fi echo "" # ============================================================================ # [10/16] Verify settings.gradle # ============================================================================ echo -e "${YELLOW}==[10/16] Verify settings.gradle ==${NC}" SETTINGS_FILE="" if [ -f "./settings.gradle" ]; then SETTINGS_FILE="settings.gradle" elif [ -f "./settings.gradle.kts" ]; then SETTINGS_FILE="settings.gradle.kts" fi if [ -n "$SETTINGS_FILE" ]; then if grep -q "mavenLocal()" "$SETTINGS_FILE" && grep -q "pluginManagement" "$SETTINGS_FILE"; then echo -e "${GREEN}[OK] settings.gradle configured for offline${NC}" else echo -e "${YELLOW}[WARN] settings.gradle may not be configured for offline${NC}" echo -e "${GRAY}[INFO] Build may fail if plugins not cached${NC}" fi fi echo "" # ============================================================================ # [11/16] Test Gradle # ============================================================================ echo -e "${YELLOW}==[11/16] Test Gradle ==${NC}" GRADLE_WORKS=false if ./gradlew --offline --version &>/dev/null; then GRADLE_WORKS=true echo -e "${GREEN}[OK] Gradle working in offline mode${NC}" else echo -e "${YELLOW}[WARN] Gradle --version failed${NC}" fi echo "" # ============================================================================ # [12/16] Stop Daemon # ============================================================================ echo -e "${YELLOW}==[12/16] Stop Daemon ==${NC}" ./gradlew --stop &>/dev/null || true sleep 2 echo -e "${GREEN}[OK] Daemon stopped${NC}" echo "" # ============================================================================ # [13/16] Run Offline Build # ============================================================================ echo -e "${YELLOW}==[13/16] Run Offline Build ==${NC}" echo "" echo -e "${CYAN}============================================================${NC}" echo -e "${CYAN} Building with --offline flag${NC}" echo -e "${CYAN} All dependencies from local cache${NC}" echo -e "${CYAN}============================================================${NC}" echo "" BUILD_SUCCESS=false BUILD_TASK="" # Try bootJar echo -e "${GRAY}[TRY] --offline bootJar...${NC}" if ./gradlew --offline clean bootJar --no-daemon; then BUILD_SUCCESS=true BUILD_TASK="bootJar" fi # Try jar if [ "$BUILD_SUCCESS" = false ]; then echo -e "${GRAY}[TRY] --offline jar...${NC}" if ./gradlew --offline clean jar --no-daemon; then BUILD_SUCCESS=true BUILD_TASK="jar" fi fi # Try build if [ "$BUILD_SUCCESS" = false ]; then echo -e "${GRAY}[TRY] --offline build...${NC}" if ./gradlew --offline build --no-daemon; then BUILD_SUCCESS=true BUILD_TASK="build" fi fi echo "" if [ "$BUILD_SUCCESS" = true ]; then echo -e "${GREEN}============================================================${NC}" echo -e "${GREEN} BUILD SUCCESS! (task: $BUILD_TASK)${NC}" echo -e "${GREEN}============================================================${NC}" else echo -e "${RED}============================================================${NC}" echo -e "${RED} BUILD FAILED!${NC}" echo -e "${RED}============================================================${NC}" echo "" echo -e "${YELLOW}Possible causes:${NC}" echo -e "${WHITE} - Dependencies not in cache${NC}" echo -e "${WHITE} - Plugin resolution failed${NC}" echo -e "${WHITE} - Need complete build in online env first${NC}" exit 1 fi echo "" # ============================================================================ # [14/16] Show Build Output # ============================================================================ echo -e "${YELLOW}==[14/16] Build Output ==${NC}" LIBS_DIR="$PROJECT_DIR/build/libs" if [ -d "$LIBS_DIR" ]; then echo -e "${CYAN}build/libs contents:${NC}" ls -lh "$LIBS_DIR"/*.jar 2>/dev/null | awk '{printf " %-40s %10s\n", $9, $5}' MAIN_JAR=$(find "$LIBS_DIR" -name "*.jar" -type f ! -name "*-plain.jar" ! -name "*-sources.jar" ! -name "*-javadoc.jar" 2>/dev/null | head -1) else echo -e "${YELLOW}[WARN] build/libs not found${NC}" fi echo "" # ============================================================================ # [15/16] Run Instructions # ============================================================================ echo -e "${YELLOW}==[15/16] Run Instructions ==${NC}" echo "" if [ -n "$MAIN_JAR" ]; then echo -e "${CYAN}To run the application:${NC}" echo -e "${WHITE} java -jar $(basename "$MAIN_JAR")${NC}" echo "" fi echo -e "${CYAN}To rebuild:${NC}" echo -e "${WHITE} export GRADLE_USER_HOME=\"./_offline_gradle_home\"${NC}" echo -e "${WHITE} ./gradlew --offline bootJar --no-daemon${NC}" echo "" # ============================================================================ # [16/16] Complete # ============================================================================ echo -e "${GREEN}============================================================${NC}" echo -e "${GREEN} Offline Build Complete!${NC}" echo -e "${GREEN}============================================================${NC}" echo "" echo -e "${CYAN}Project: $PROJECT_DIR${NC}" echo ""