Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 12 additions & 21 deletions plugins/android/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,22 @@
"{{ .Virtenv }}/scripts/lib/lib.sh": "virtenv/scripts/lib/lib.sh",
"{{ .Virtenv }}/scripts/platform/core.sh": "virtenv/scripts/platform/core.sh",
"{{ .Virtenv }}/scripts/platform/device_config.sh": "virtenv/scripts/platform/device_config.sh",
"{{ .Virtenv }}/scripts/platform/drift.sh": "virtenv/scripts/platform/drift.sh",
"{{ .Virtenv }}/scripts/domain/avd.sh": "virtenv/scripts/domain/avd.sh",
"{{ .Virtenv }}/scripts/domain/avd-reset.sh": "virtenv/scripts/domain/avd-reset.sh",
"{{ .Virtenv }}/scripts/domain/emulator.sh": "virtenv/scripts/domain/emulator.sh",
"{{ .Virtenv }}/scripts/domain/deploy.sh": "virtenv/scripts/domain/deploy.sh",
"{{ .Virtenv }}/scripts/domain/validate.sh": "virtenv/scripts/domain/validate.sh",
"{{ .Virtenv }}/scripts/domain/hash-fix.sh": "virtenv/scripts/domain/hash-fix.sh",
"{{ .Virtenv }}/scripts/user/android.sh": "virtenv/scripts/user/android.sh",
"{{ .Virtenv }}/scripts/user/config.sh": "virtenv/scripts/user/config.sh",
"{{ .Virtenv }}/scripts/user/devices.sh": "virtenv/scripts/user/devices.sh",
"{{ .Virtenv }}/scripts/user/setup.sh": "virtenv/scripts/user/setup.sh",
"{{ .Virtenv }}/scripts/user/doctor.sh": "virtenv/scripts/user/doctor.sh",
"{{ .Virtenv }}/scripts/init/init-hook.sh": "virtenv/scripts/init/init-hook.sh",
"{{ .Virtenv }}/scripts/init/setup.sh": "virtenv/scripts/init/setup.sh",
"{{ .Virtenv }}/flake.nix": "virtenv/flake.nix",
"{{ .Virtenv }}/scripts/init/doctor.sh": "virtenv/scripts/init/doctor.sh",
"{{ .DevboxDir }}/flake.nix": "virtenv/flake.nix",
"{{ .DevboxDir }}/devices/min.json": "config/devices/min.json",
"{{ .DevboxDir }}/devices/max.json": "config/devices/max.json"
},
Expand All @@ -68,9 +72,15 @@
"setup": [
"bash {{ .Virtenv }}/scripts/user/setup.sh"
],
"android:sync": [
"android.sh devices sync"
],
"android:devices:eval": [
"ANDROID_SDK_REQUIRED=0 android.sh devices eval"
],
"android:hash-fix": [
"ANDROID_HASH_FIX_VERBOSE=1 bash {{ .Virtenv }}/scripts/domain/hash-fix.sh auto"
],
"start:emu": [
"android.sh emulator start \"${1:-}\""
],
Expand All @@ -81,26 +91,7 @@
"android.sh emulator reset"
],
"doctor": [
"echo 'Android Environment Check'",
"echo '========================='",
"echo ''",
"echo 'ANDROID_SDK_ROOT:' ${ANDROID_SDK_ROOT:-'NOT SET'}",
"test -n \"${ANDROID_SDK_ROOT}\" && echo '✓ ANDROID_SDK_ROOT is set' || echo '✗ ANDROID_SDK_ROOT is not set'",
"test -d \"${ANDROID_SDK_ROOT}\" && echo '✓ ANDROID_SDK_ROOT directory exists' || echo '✗ ANDROID_SDK_ROOT directory does not exist'",
"echo ''",
"echo 'ANDROID_AVD_HOME:' ${ANDROID_AVD_HOME:-'NOT SET'}",
"test -w \"${ANDROID_AVD_HOME}\" && echo '✓ ANDROID_AVD_HOME is writable' || echo '✗ ANDROID_AVD_HOME is not writable'",
"echo ''",
"command -v adb >/dev/null 2>&1 && echo '✓ adb is in PATH' || echo '✗ adb is not in PATH'",
"command -v emulator >/dev/null 2>&1 && echo '✓ emulator is in PATH' || echo '✗ emulator is not in PATH'",
"command -v avdmanager >/dev/null 2>&1 && echo '✓ avdmanager is in PATH' || echo '✗ avdmanager is not in PATH'",
"echo ''",
"echo 'Device Definitions:'",
"ls -1 ${ANDROID_DEVICES_DIR}/*.json 2>/dev/null | wc -l | xargs echo ' Count:'",
"echo ' ANDROID_DEVICES:' ${ANDROID_DEVICES:-'(all devices)'}",
"echo ''",
"test -f ${ANDROID_DEVICES_DIR}/devices.lock && echo '✓ Lock file exists' || echo '⚠ Lock file not generated yet (run devbox shell)'",
"echo ''"
"bash {{ .Virtenv }}/scripts/user/doctor.sh"
],
"verify:setup": [
"test -n \"${ANDROID_SDK_ROOT}\" && test -d \"${ANDROID_SDK_ROOT}\" && command -v adb >/dev/null 2>&1 && echo '✓ Android environment OK' || (echo '✗ Android environment check failed. Run: devbox run doctor' && exit 1)"
Expand Down
57 changes: 57 additions & 0 deletions plugins/android/virtenv/scripts/init/doctor.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
# Android Plugin - Doctor Init Check
# Lightweight health check run on shell init
# Shows ✓ if all good, warnings if issues detected

set -eu

# Source drift detection if available
if [ -n "${ANDROID_SCRIPTS_DIR:-}" ] && [ -f "${ANDROID_SCRIPTS_DIR}/platform/drift.sh" ]; then
. "${ANDROID_SCRIPTS_DIR}/platform/drift.sh"
fi

# Silent mode - only output if there are issues
issues=()

# Check 1: SDK Root
if [ -z "${ANDROID_SDK_ROOT:-}" ] || [ ! -d "${ANDROID_SDK_ROOT:-}" ]; then
issues+=("Android SDK not found")
fi

# Check 2: Essential tools
if [ -n "${ANDROID_SDK_ROOT:-}" ]; then
if ! command -v adb >/dev/null 2>&1; then
issues+=("adb not in PATH")
fi
if ! command -v emulator >/dev/null 2>&1; then
issues+=("emulator not in PATH")
fi
fi

# Check 3: Configuration drift (android.lock out of sync with env vars)
if command -v android_check_config_drift >/dev/null 2>&1; then
android_check_config_drift
if [ "${ANDROID_DRIFT_DETECTED:-false}" = true ]; then
issues+=("Config drift: env vars don't match android.lock")
fi
fi

# Output results
if [ ${#issues[@]} -eq 0 ]; then
echo "✓ Android"
else
echo "⚠️ Android issues detected:" >&2
for issue in "${issues[@]}"; do
echo " - $issue" >&2
done

# If drift detected, show details
if [ "${ANDROID_DRIFT_DETECTED:-false}" = true ]; then
echo "" >&2
echo " Config differences:" >&2
printf '%s' "${ANDROID_DRIFT_DETAILS}" >&2
echo " Fix: devbox run android:sync" >&2
fi

echo " Run 'devbox run doctor' for more details" >&2
fi
79 changes: 79 additions & 0 deletions plugins/android/virtenv/scripts/platform/drift.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/usr/bin/env bash
# Android Plugin - Configuration Drift Detection
# Detects when environment variables don't match android.lock

# Android configuration variables to check for drift
readonly ANDROID_CONFIG_VARS=(
"ANDROID_BUILD_TOOLS_VERSION"
"ANDROID_CMDLINE_TOOLS_VERSION"
"ANDROID_COMPILE_SDK"
"ANDROID_TARGET_SDK"
"ANDROID_SYSTEM_IMAGE_TAG"
"ANDROID_INCLUDE_NDK"
"ANDROID_NDK_VERSION"
"ANDROID_INCLUDE_CMAKE"
"ANDROID_CMAKE_VERSION"
)

# Normalize boolean value (consistent with jq test("true|1|yes|on"; "i"))
# Accepts: true/1/yes/on (case-insensitive)
android_normalize_bool() {
local val="$1"
# Convert to lowercase for case-insensitive comparison
case "${val,,}" in
1|true|yes|on) echo "true" ;;
*) echo "false" ;;
esac
}

# android_check_config_drift
# Compares Android env vars with android.lock and detects drift
# Sets global variables:
# ANDROID_DRIFT_DETECTED - "true" if drift detected, "false" if no drift, "unknown" if cannot check
# ANDROID_DRIFT_DETAILS - formatted string with drift details (for printf %s)
android_check_config_drift() {
local config_dir="${ANDROID_CONFIG_DIR:-./devbox.d/android}"
local android_lock="${config_dir}/android.lock"

ANDROID_DRIFT_DETECTED="false"
ANDROID_DRIFT_DETAILS=""

# Check if lock file exists
if [ ! -f "$android_lock" ]; then
return 0
fi

# Check if jq is available
if ! command -v jq >/dev/null 2>&1; then
ANDROID_DRIFT_DETECTED="unknown"
ANDROID_DRIFT_DETAILS=" jq not available, cannot check configuration drift\n"
export ANDROID_DRIFT_DETECTED
export ANDROID_DRIFT_DETAILS
return 0
fi

# Compare each env var with android.lock
for var in "${ANDROID_CONFIG_VARS[@]}"; do
local env_val="${!var:-}"
local lock_val
lock_val="$(jq -r ".${var} // empty" "$android_lock" 2>/dev/null || echo "")"

# Normalize boolean values for comparison
if [ "$var" = "ANDROID_INCLUDE_NDK" ] || [ "$var" = "ANDROID_INCLUDE_CMAKE" ]; then
env_val=$(android_normalize_bool "$env_val")
# lock_val is already normalized in android.lock (true/false)
fi

# Skip if lock value is empty (field doesn't exist in lock)
[ -z "$lock_val" ] && continue

# Detect drift
if [ "$env_val" != "$lock_val" ]; then
ANDROID_DRIFT_DETECTED="true"
ANDROID_DRIFT_DETAILS="${ANDROID_DRIFT_DETAILS} ${var}: \"${env_val}\" (env) vs \"${lock_val}\" (lock)\n"
fi
done

export ANDROID_DRIFT_DETECTED
export ANDROID_DRIFT_DETAILS
}
104 changes: 104 additions & 0 deletions plugins/android/virtenv/scripts/user/doctor.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/usr/bin/env bash
# Android Plugin - Doctor Script
# Comprehensive health check for Android environment

set -eu

# Source drift detection if available
if [ -n "${ANDROID_SCRIPTS_DIR:-}" ] && [ -f "${ANDROID_SCRIPTS_DIR}/platform/drift.sh" ]; then
. "${ANDROID_SCRIPTS_DIR}/platform/drift.sh"
fi

echo 'Android Environment Check'
echo '========================='
echo ''

# Check 1: Android SDK
echo 'Android SDK:'
if [ -n "${ANDROID_SDK_ROOT:-}" ]; then
echo " ANDROID_SDK_ROOT: ${ANDROID_SDK_ROOT}"
if [ -d "${ANDROID_SDK_ROOT}" ]; then
echo " ✓ SDK directory exists"
else
echo " ✗ SDK directory does not exist"
fi
else
echo " ✗ ANDROID_SDK_ROOT not set"
fi
echo ''

# Check 2: AVD Home
echo 'AVD Environment:'
if [ -n "${ANDROID_AVD_HOME:-}" ]; then
echo " ANDROID_AVD_HOME: ${ANDROID_AVD_HOME}"
if [ -w "${ANDROID_AVD_HOME}" ]; then
echo " ✓ AVD directory is writable"
else
echo " ⚠ AVD directory is not writable"
fi
else
echo " ANDROID_AVD_HOME: NOT SET"
fi
echo ''

# Check 3: Essential tools
echo 'Tools:'
if command -v adb >/dev/null 2>&1; then
echo " ✓ adb is in PATH"
else
echo " ✗ adb is not in PATH"
fi

if command -v emulator >/dev/null 2>&1; then
echo " ✓ emulator is in PATH"
else
echo " ✗ emulator is not in PATH"
fi

if command -v avdmanager >/dev/null 2>&1; then
echo " ✓ avdmanager is in PATH"
else
echo " ⚠ avdmanager is not in PATH"
fi
echo ''

# Check 4: Device configuration
echo 'Device Configuration:'
devices_dir="${ANDROID_DEVICES_DIR:-./devbox.d/android/devices}"
device_count=$(ls -1 "${devices_dir}"/*.json 2>/dev/null | wc -l | tr -d ' ')
echo " Device files: ${device_count}"
echo " ANDROID_DEVICES: ${ANDROID_DEVICES:-'(all devices)'}"

if [ -f "${devices_dir}/devices.lock" ]; then
echo " ✓ devices.lock exists"
else
echo " ⚠ devices.lock not generated yet (run devbox shell)"
fi
echo ''

# Check 5: Configuration drift (android.lock vs env vars)
config_dir="${ANDROID_CONFIG_DIR:-./devbox.d/android}"
android_lock="${config_dir}/android.lock"

echo 'Configuration Sync:'
if [ ! -f "$android_lock" ]; then
echo " ⚠ android.lock not found"
echo " Run: devbox run android:sync"
elif ! command -v jq >/dev/null 2>&1; then
echo " ⚠ jq not available, cannot check drift"
elif command -v android_check_config_drift >/dev/null 2>&1; then
# Use shared drift detection function
android_check_config_drift

if [ "${ANDROID_DRIFT_DETECTED}" = true ]; then
echo " ⚠ Configuration drift detected:"
printf '%s' "${ANDROID_DRIFT_DETAILS}"
echo ""
echo " Fix: devbox run android:sync"
else
echo " ✓ Env vars match android.lock"
fi
else
echo " ⚠ Cannot check drift (drift detection not available)"
fi
echo ''
12 changes: 4 additions & 8 deletions plugins/android/virtenv/scripts/user/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,9 @@ if [ -n "${ANDROID_RUNTIME_DIR:-}" ]; then
echo "${ANDROID_SDK_ROOT}" > "${ANDROID_RUNTIME_DIR}/.state/sdk_root"
fi

# Verify essential tools are in PATH
if ! command -v adb >/dev/null 2>&1; then
echo "⚠️ [WARN] adb not in PATH" >&2
fi
echo "✅ [OK] Android setup complete"

if ! command -v emulator >/dev/null 2>&1; then
echo "⚠️ [WARN] emulator not in PATH" >&2
# Run lightweight doctor check
if [ -n "${ANDROID_SCRIPTS_DIR:-}" ] && [ -f "${ANDROID_SCRIPTS_DIR}/init/doctor.sh" ]; then
bash "${ANDROID_SCRIPTS_DIR}/init/doctor.sh" 2>&1
fi

echo "✅ [OK] Android setup complete"
20 changes: 10 additions & 10 deletions plugins/ios/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"{{ .Virtenv }}/scripts/user/setup.sh": "virtenv/scripts/user/setup.sh",
"{{ .Virtenv }}/scripts/init/init-hook.sh": "virtenv/scripts/init/init-hook.sh",
"{{ .Virtenv }}/scripts/init/setup.sh": "virtenv/scripts/init/setup.sh",
"{{ .Virtenv }}/scripts/init/doctor.sh": "virtenv/scripts/init/doctor.sh",
"{{ .DevboxDir }}/devices/min.json": "config/devices/min.json",
"{{ .DevboxDir }}/devices/max.json": "config/devices/max.json"
},
Expand All @@ -79,18 +80,17 @@
"echo 'iOS Environment Check'",
"echo '===================='",
"echo ''",
"echo 'IOS_DEVELOPER_DIR:' ${IOS_DEVELOPER_DIR:-'NOT SET (using xcode-select)'}",
"xcrun --show-sdk-path >/dev/null 2>&1 && echo '✓ Xcode command line tools available' || echo '✗ Xcode command line tools not found'",
"echo 'Xcode and Tools:'",
"echo ' IOS_DEVELOPER_DIR:' ${IOS_DEVELOPER_DIR:-'NOT SET (using xcode-select)'}",
"xcrun --show-sdk-path >/dev/null 2>&1 && echo ' ✓ Xcode command line tools available' || echo ' ✗ Xcode command line tools not found'",
"command -v xcrun >/dev/null 2>&1 && echo ' ✓ xcrun is in PATH' || echo ' ✗ xcrun is not in PATH'",
"command -v simctl >/dev/null 2>&1 && echo ' ✓ simctl is available' || echo ' ⚠ simctl not in PATH (use xcrun simctl)'",
"xcrun simctl list devices >/dev/null 2>&1 && echo ' ✓ xcrun simctl working' || echo ' ✗ xcrun simctl not working'",
"echo ''",
"command -v xcrun >/dev/null 2>&1 && echo '✓ xcrun is in PATH' || echo '✗ xcrun is not in PATH'",
"command -v simctl >/dev/null 2>&1 && echo '✓ simctl is available' || echo '⚠ simctl not in PATH (use xcrun simctl)'",
"xcrun simctl list devices >/dev/null 2>&1 && echo '✓ xcrun simctl working' || echo '✗ xcrun simctl not working'",
"echo ''",
"echo 'Device Definitions:'",
"ls -1 ${IOS_DEVICES_DIR}/*.json 2>/dev/null | wc -l | xargs echo ' Count:'",
"echo 'Device Configuration:'",
"ls -1 ${IOS_DEVICES_DIR}/*.json 2>/dev/null | wc -l | xargs echo ' Device files:'",
"echo ' IOS_DEVICES:' ${IOS_DEVICES:-'(all devices)'}",
"echo ''",
"test -f ${IOS_DEVICES_DIR}/devices.lock && echo '✓ Lock file exists' || echo '⚠ Lock file not generated yet (run devbox shell)'",
"test -f ${IOS_DEVICES_DIR}/devices.lock && echo ' ✓ devices.lock exists' || echo ' ⚠ devices.lock not generated yet (run devbox shell)'",
"echo ''"
],
"verify:setup": [
Expand Down
Loading
Loading