Optimize Android APK CI: fix staging flag, add caching, faster runner (#429)

This commit is contained in:
Danny M
2026-03-02 18:23:35 -03:00
committed by GitHub
parent 586fc374ef
commit 6401a1f05f
10 changed files with 518 additions and 448 deletions
+55 -15
View File
@@ -41,7 +41,7 @@ jobs:
build-apk:
name: Build Staging APK
runs-on: ubuntu-latest
runs-on: blacksmith-8vcpu-ubuntu-2404
needs: [check-team]
# Run when: push/dispatch (not a PR, check-team was skipped), or PR where
# the "apk" label is present and actor is a contributor.
@@ -55,12 +55,15 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
cache: 'gradle'
- name: Setup Flutter
uses: subosito/flutter-action@v2
@@ -69,11 +72,6 @@ jobs:
channel: 'stable'
cache: true
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-linux-android,armv7-linux-androideabi,x86_64-linux-android
- name: Cache Flutter dependencies
uses: actions/cache@v4
with:
@@ -84,7 +82,22 @@ jobs:
restore-keys: |
${{ runner.os }}-pub-cache-
- name: Cache pre-built Android native libraries
id: jnilibs-cache
uses: actions/cache@v4
with:
path: android/app/src/main/jniLibs
key: ${{ runner.os }}-jnilibs-${{ hashFiles('rust/Cargo.toml', 'rust/Cargo.lock', 'rust/src/**', 'scripts/build_android.sh', 'scripts/build_openssl_android.sh', 'scripts/setup_android_config.sh') }}
# ── Rust build steps (skipped when native libs are cached) ──
- name: Setup Rust
if: steps.jnilibs-cache.outputs.cache-hit != 'true'
uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-linux-android,armv7-linux-androideabi,x86_64-linux-android
- name: Cache Rust dependencies
if: steps.jnilibs-cache.outputs.cache-hit != 'true'
uses: actions/cache@v4
with:
path: |
@@ -95,28 +108,52 @@ jobs:
restore-keys: |
${{ runner.os }}-cargo-android-
- name: Cache OpenSSL for Android
if: steps.jnilibs-cache.outputs.cache-hit != 'true'
uses: actions/cache@v4
with:
path: rust/target/openssl/install
key: ${{ runner.os }}-openssl-android-${{ hashFiles('scripts/build_openssl_android.sh') }}
- name: Cache Android SDK & NDK
id: android-cache
uses: actions/cache@v4
with:
path: |
/usr/local/lib/android/sdk/ndk/27.0.12077973
/usr/local/lib/android/sdk/build-tools
/usr/local/lib/android/sdk/platforms
key: ${{ runner.os }}-android-ndk-27.0.12077973
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Install Android NDK
run: |
echo "y" | sdkmanager --install "ndk;27.0.12077973"
echo "ANDROID_NDK_HOME=$ANDROID_HOME/ndk/27.0.12077973" >> $GITHUB_ENV
if: steps.android-cache.outputs.cache-hit != 'true'
run: echo "y" | sdkmanager --install "ndk;27.0.12077973"
- name: Set NDK environment
if: steps.jnilibs-cache.outputs.cache-hit != 'true'
run: echo "ANDROID_NDK_HOME=$ANDROID_HOME/ndk/27.0.12077973" >> $GITHUB_ENV
- name: Install Flutter dependencies
run: flutter pub get
- name: Build Rust libraries for Android
if: steps.jnilibs-cache.outputs.cache-hit != 'true'
run: ./scripts/build_android.sh
- name: Build staging APK
run: flutter build apk --flavor staging --split-per-abi
run: flutter build apk --flavor staging --split-per-abi --dart-define=APP_FLAVOR=staging --build-number=${{ github.run_number }}
- name: Set artifact name
env:
EVENT_NAME: ${{ github.event_name }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
if [ "${{ github.event_name }}" = "pull_request" ]; then
echo "ARTIFACT_SUFFIX=pr-${{ github.event.pull_request.number }}-${GITHUB_SHA::7}" >> $GITHUB_ENV
if [ "$EVENT_NAME" = "pull_request" ]; then
echo "ARTIFACT_SUFFIX=pr-${PR_NUMBER}-${GITHUB_SHA::7}" >> $GITHUB_ENV
else
BRANCH_NAME="${GITHUB_REF_NAME//\//-}"
echo "ARTIFACT_SUFFIX=${BRANCH_NAME}-${GITHUB_SHA::7}" >> $GITHUB_ENV
@@ -134,8 +171,11 @@ jobs:
env:
SAFE_PR_TITLE: ${{ github.event.pull_request.title }}
SAFE_PR_NUMBER: ${{ github.event.pull_request.number }}
EVENT_NAME: ${{ github.event_name }}
COMMIT_SHA: ${{ github.sha }}
ARTIFACT_SUFFIX: ${{ env.ARTIFACT_SUFFIX }}
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
if [ "$EVENT_NAME" = "pull_request" ]; then
PR_INFO="**PR:** #${SAFE_PR_NUMBER} — ${SAFE_PR_TITLE}"
else
PR_INFO=""
@@ -144,14 +184,14 @@ jobs:
cat >> "${GITHUB_STEP_SUMMARY}" <<SUMMARY
## Android APK Build Complete
**Commit:** ${{ github.sha }}
**Commit:** ${COMMIT_SHA}
${PR_INFO}
### Download APKs
1. Go to the **Actions** tab
2. Click on this workflow run
3. Scroll down to **Artifacts**
4. Download **apk-staging-${{ env.ARTIFACT_SUFFIX }}**
4. Download **apk-staging-${ARTIFACT_SUFFIX}**
### APK Files
SUMMARY
+3
View File
@@ -1,3 +1,6 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.daemon=true
android.useAndroidX=true
android.enableJetifier=true
+57 -54
View File
@@ -1,25 +1,25 @@
#!/bin/bash
# Build script for Android targets
set -e # Exit on any error
set -e # Exit on any error
echo "🚀 Building Rust library for Android targets..."
# Function to print colored output
print_step() {
echo -e "\n\033[1;34m=== $1 ===\033[0m"
echo -e "\n\033[1;34m=== $1 ===\033[0m"
}
print_success() {
echo -e "\033[1;32m✅ $1\033[0m"
echo -e "\033[1;32m✅ $1\033[0m"
}
print_warning() {
echo -e "\033[1;33m⚠️ $1\033[0m"
echo -e "\033[1;33m⚠️ $1\033[0m"
}
print_error() {
echo -e "\033[1;31m❌ $1\033[0m"
echo -e "\033[1;31m❌ $1\033[0m"
}
# Auto-detect Android SDK and NDK paths
@@ -27,59 +27,62 @@ print_step "Detecting Android SDK and NDK paths"
# Try to find Android SDK
if [ -z "$ANDROID_HOME" ] && [ -z "$ANDROID_SDK_ROOT" ]; then
# Common Android SDK locations
POSSIBLE_SDK_PATHS=(
"$HOME/Library/Android/sdk" # macOS default
"$HOME/Android/Sdk" # Linux default
"$HOME/AppData/Local/Android/Sdk" # Windows default
"/opt/android-sdk" # Linux alternative
)
# Common Android SDK locations
POSSIBLE_SDK_PATHS=(
"$HOME/Library/Android/sdk" # macOS default
"$HOME/Android/Sdk" # Linux default
"$HOME/AppData/Local/Android/Sdk" # Windows default
"/opt/android-sdk" # Linux alternative
)
for path in "${POSSIBLE_SDK_PATHS[@]}"; do
if [ -d "$path" ]; then
export ANDROID_HOME="$path"
export ANDROID_SDK_ROOT="$path"
print_success "Found Android SDK at: $path"
break
fi
done
for path in "${POSSIBLE_SDK_PATHS[@]}"; do
if [ -d "$path" ]; then
export ANDROID_HOME="$path"
export ANDROID_SDK_ROOT="$path"
print_success "Found Android SDK at: $path"
break
fi
done
else
export ANDROID_HOME="${ANDROID_HOME:-$ANDROID_SDK_ROOT}"
export ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT:-$ANDROID_HOME}"
print_success "Using Android SDK from environment: $ANDROID_HOME"
export ANDROID_HOME="${ANDROID_HOME:-$ANDROID_SDK_ROOT}"
export ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT:-$ANDROID_HOME}"
print_success "Using Android SDK from environment: $ANDROID_HOME"
fi
if [ -z "$ANDROID_HOME" ]; then
print_error "Android SDK not found. Please install Android SDK or set ANDROID_HOME environment variable"
exit 1
print_error "Android SDK not found. Please install Android SDK or set ANDROID_HOME environment variable"
exit 1
fi
# Auto-detect NDK path
if [ -z "$ANDROID_NDK_HOME" ]; then
# Look for NDK in the SDK directory
NDK_DIR="$ANDROID_HOME/ndk"
if [ -d "$NDK_DIR" ]; then
# Find the latest NDK version
NDK_VERSION=$(ls "$NDK_DIR" | sort -V | tail -n 1)
if [ -n "$NDK_VERSION" ]; then
export ANDROID_NDK_HOME="$NDK_DIR/$NDK_VERSION"
print_success "Found NDK version $NDK_VERSION at: $ANDROID_NDK_HOME"
fi
# Look for NDK in the SDK directory
NDK_DIR="$ANDROID_HOME/ndk"
if [ -d "$NDK_DIR" ]; then
# Find the latest NDK version
NDK_VERSION=$(ls "$NDK_DIR" | sort -V | tail -n 1)
if [ -n "$NDK_VERSION" ]; then
export ANDROID_NDK_HOME="$NDK_DIR/$NDK_VERSION"
print_success "Found NDK version $NDK_VERSION at: $ANDROID_NDK_HOME"
fi
fi
fi
if [ -z "$ANDROID_NDK_HOME" ] || [ ! -d "$ANDROID_NDK_HOME" ]; then
print_error "Android NDK not found. Please install Android NDK or set ANDROID_NDK_HOME environment variable"
print_error "You can install NDK through Android Studio SDK Manager"
exit 1
print_error "Android NDK not found. Please install Android NDK or set ANDROID_NDK_HOME environment variable"
print_error "You can install NDK through Android Studio SDK Manager"
exit 1
fi
# Detect host OS for NDK toolchain path
case "$(uname -s)" in
Darwin*) HOST_TAG="darwin-x86_64" ;;
Linux*) HOST_TAG="linux-x86_64" ;;
MINGW*|CYGWIN*|MSYS*) HOST_TAG="windows-x86_64" ;;
*) print_error "Unsupported host OS: $(uname -s)"; exit 1 ;;
Darwin*) HOST_TAG="darwin-x86_64" ;;
Linux*) HOST_TAG="linux-x86_64" ;;
MINGW* | CYGWIN* | MSYS*) HOST_TAG="windows-x86_64" ;;
*)
print_error "Unsupported host OS: $(uname -s)"
exit 1
;;
esac
export PATH="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$HOST_TAG/bin:$PATH"
@@ -96,9 +99,9 @@ OPENSSL_ANDROID_DIR="$PWD/rust/target/openssl/install"
# Check if required tools are installed
print_step "Checking development environment"
if ! command -v rustup &> /dev/null; then
print_error "Rustup is not installed or not in PATH"
exit 1
if ! command -v rustup &>/dev/null; then
print_error "Rustup is not installed or not in PATH"
exit 1
fi
# Generate Cargo config for current environment
@@ -107,9 +110,9 @@ print_step "Setting up Cargo configuration"
# Add Android targets
print_step "Adding Android targets to Rust"
rustup target add aarch64-linux-android # arm64-v8a (64-bit ARM)
rustup target add armv7-linux-androideabi # armeabi-v7a (32-bit ARM)
rustup target add x86_64-linux-android # x86_64 (64-bit Intel)
rustup target add aarch64-linux-android # arm64-v8a (64-bit ARM)
rustup target add armv7-linux-androideabi # armeabi-v7a (32-bit ARM)
rustup target add x86_64-linux-android # x86_64 (64-bit Intel)
print_success "Android targets added to Rust"
# Create output directories
@@ -124,19 +127,19 @@ cd rust
# Build helper: sets per-target OpenSSL env vars and runs cargo build
build_for_target() {
local target="$1"
local label="$2"
local jni_dir="$3"
local target="$1"
local label="$2"
local jni_dir="$3"
print_step "Building for $label"
OPENSSL_DIR="$OPENSSL_ANDROID_DIR/$target" \
print_step "Building for $label"
OPENSSL_DIR="$OPENSSL_ANDROID_DIR/$target" \
OPENSSL_INCLUDE_DIR="$OPENSSL_ANDROID_DIR/$target/include" \
OPENSSL_LIB_DIR="$OPENSSL_ANDROID_DIR/$target/lib" \
OPENSSL_STATIC=1 \
OPENSSL_NO_VENDOR=1 \
cargo build --target "$target" --release --quiet
cp "target/$target/release/librust_lib_whitenoise.so" "../android/app/src/main/jniLibs/$jni_dir/"
print_success "Built for $label"
cp "target/$target/release/librust_lib_whitenoise.so" "../android/app/src/main/jniLibs/$jni_dir/"
print_success "Built for $label"
}
build_for_target "aarch64-linux-android" "aarch64 (arm64-v8a)" "arm64-v8a"
+28 -25
View File
@@ -1,56 +1,56 @@
#!/bin/bash
# Build script for iOS targets
set -e # Exit on any error
set -e # Exit on any error
echo "🚀 Building Rust library for iOS targets..."
# Function to print colored output
print_step() {
echo -e "\n\033[1;34m=== $1 ===\033[0m"
echo -e "\n\033[1;34m=== $1 ===\033[0m"
}
print_success() {
echo -e "\033[1;32m✅ $1\033[0m"
echo -e "\033[1;32m✅ $1\033[0m"
}
print_error() {
echo -e "\033[1;31m❌ $1\033[0m"
echo -e "\033[1;31m❌ $1\033[0m"
}
# Check if required tools are installed
print_step "Checking development environment"
if ! command -v rustup &> /dev/null; then
print_error "Rustup is not installed or not in PATH"
exit 1
if ! command -v rustup &>/dev/null; then
print_error "Rustup is not installed or not in PATH"
exit 1
fi
if ! command -v cargo &> /dev/null; then
print_error "Cargo is not installed or not in PATH"
exit 1
if ! command -v cargo &>/dev/null; then
print_error "Cargo is not installed or not in PATH"
exit 1
fi
if ! command -v xcodebuild &> /dev/null; then
print_error "Xcode command line tools are not installed"
exit 1
if ! command -v xcodebuild &>/dev/null; then
print_error "Xcode command line tools are not installed"
exit 1
fi
if ! command -v pod &> /dev/null; then
print_error "CocoaPods is not installed or not in PATH"
exit 1
if ! command -v pod &>/dev/null; then
print_error "CocoaPods is not installed or not in PATH"
exit 1
fi
# Add iOS targets
print_step "Adding iOS targets to Rust"
rustup target add aarch64-apple-ios # Physical devices (arm64)
rustup target add aarch64-apple-ios-sim # Simulator on Apple Silicon
rustup target add aarch64-apple-ios # Physical devices (arm64)
rustup target add aarch64-apple-ios-sim # Simulator on Apple Silicon
print_success "iOS targets added to Rust"
# Build for each iOS architecture
print_step "Building for iOS architectures"
if ! test -d "rust"; then
print_error "rust directory not found"
exit 1
print_error "rust directory not found"
exit 1
fi
cd rust
@@ -66,13 +66,16 @@ cd ..
# Run pod install to ensure pods are up to date
print_step "Installing CocoaPods dependencies"
pushd ios > /dev/null || { print_error "Failed to enter ios directory"; exit 1; }
pushd ios >/dev/null || {
print_error "Failed to enter ios directory"
exit 1
}
if ! pod install --silent; then
print_error "pod install failed"
popd > /dev/null
exit 1
print_error "pod install failed"
popd >/dev/null
exit 1
fi
popd > /dev/null
popd >/dev/null
print_success "All Rust libraries built for iOS"
print_success "iOS build completed successfully!"
+123 -120
View File
@@ -6,47 +6,47 @@
set -eo pipefail
print_step() {
echo -e "\n\033[1;34m=== $1 ===\033[0m"
echo -e "\n\033[1;34m=== $1 ===\033[0m"
}
print_success() {
echo -e "\033[1;32m$1\033[0m"
echo -e "\033[1;32m$1\033[0m"
}
print_error() {
echo -e "\033[1;31m$1\033[0m"
echo -e "\033[1;31m$1\033[0m"
}
# Spinner for long-running commands
# Usage: run_quiet "description" logfile command [args...]
run_quiet() {
local desc="$1"
local logfile="$2"
shift 2
local desc="$1"
local logfile="$2"
shift 2
printf " %-40s " "$desc"
printf " %-40s " "$desc"
# Run command in background with output redirected to log file
"$@" >> "$logfile" 2>&1 &
local pid=$!
local spin='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
local i=0
while kill -0 "$pid" 2>/dev/null; do
printf "\b%s" "${spin:i++%${#spin}:1}"
sleep 0.1
done
wait "$pid"
local exit_code=$?
# Run command in background with output redirected to log file
"$@" >>"$logfile" 2>&1 &
local pid=$!
local spin='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
local i=0
while kill -0 "$pid" 2>/dev/null; do
printf "\b%s" "${spin:i++%${#spin}:1}"
sleep 0.1
done
wait "$pid"
local exit_code=$?
if [ $exit_code -eq 0 ]; then
printf "\b\033[1;32m✓\033[0m\n"
else
printf "\b\033[1;31m✗\033[0m\n"
print_error "Command failed. Last 20 lines of log:"
tail -20 "$logfile"
print_error "Full log: $logfile"
exit 1
fi
if [ $exit_code -eq 0 ]; then
printf "\b\033[1;32m✓\033[0m\n"
else
printf "\b\033[1;31m✗\033[0m\n"
print_error "Command failed. Last 20 lines of log:"
tail -20 "$logfile"
print_error "Full log: $logfile"
exit 1
fi
}
# Configuration
@@ -63,136 +63,139 @@ OPENSSL_INSTALL_DIR="$OPENSSL_BUILD_DIR/install"
# Auto-detect Android NDK
if [ -z "$ANDROID_NDK_HOME" ]; then
if [ -n "$NDK_HOME" ]; then
ANDROID_NDK_HOME="$NDK_HOME"
elif [ -n "$ANDROID_HOME" ]; then
NDK_DIR="$ANDROID_HOME/ndk"
if [ -d "$NDK_DIR" ]; then
NDK_VERSION=$(ls "$NDK_DIR" | sort -V | tail -n 1)
if [ -n "$NDK_VERSION" ]; then
ANDROID_NDK_HOME="$NDK_DIR/$NDK_VERSION"
fi
fi
if [ -n "$NDK_HOME" ]; then
ANDROID_NDK_HOME="$NDK_HOME"
elif [ -n "$ANDROID_HOME" ]; then
NDK_DIR="$ANDROID_HOME/ndk"
if [ -d "$NDK_DIR" ]; then
NDK_VERSION=$(ls "$NDK_DIR" | sort -V | tail -n 1)
if [ -n "$NDK_VERSION" ]; then
ANDROID_NDK_HOME="$NDK_DIR/$NDK_VERSION"
fi
fi
fi
fi
if [ -z "$ANDROID_NDK_HOME" ] || [ ! -d "$ANDROID_NDK_HOME" ]; then
print_error "Android NDK not found. Set ANDROID_NDK_HOME or NDK_HOME."
exit 1
print_error "Android NDK not found. Set ANDROID_NDK_HOME or NDK_HOME."
exit 1
fi
# Detect host OS
case "$(uname -s)" in
Darwin*)
case "$(uname -m)" in
arm64|aarch64) HOST_TAG="darwin-arm64" ;;
*) HOST_TAG="darwin-x86_64" ;;
esac
;;
Linux*) HOST_TAG="linux-x86_64" ;;
*) print_error "Unsupported host OS: $(uname -s)"; exit 1 ;;
Darwin*)
case "$(uname -m)" in
arm64 | aarch64) HOST_TAG="darwin-arm64" ;;
*) HOST_TAG="darwin-x86_64" ;;
esac
;;
Linux*) HOST_TAG="linux-x86_64" ;;
*)
print_error "Unsupported host OS: $(uname -s)"
exit 1
;;
esac
TOOLCHAIN="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$HOST_TAG"
# Target configurations: (rust_target openssl_target arch)
TARGETS=(
"aarch64-linux-android:android-arm64:aarch64"
"armv7-linux-androideabi:android-arm:armv7a"
"x86_64-linux-android:android-x86_64:x86_64"
"aarch64-linux-android:android-arm64:aarch64"
"armv7-linux-androideabi:android-arm:armv7a"
"x86_64-linux-android:android-x86_64:x86_64"
)
build_openssl_for_target() {
local rust_target="$1"
local openssl_target="$2"
local arch="$3"
local install_prefix="$OPENSSL_INSTALL_DIR/$rust_target"
local rust_target="$1"
local openssl_target="$2"
local arch="$3"
local install_prefix="$OPENSSL_INSTALL_DIR/$rust_target"
# Skip if already built
if [ -f "$install_prefix/lib/libcrypto.a" ]; then
print_success "OpenSSL already built for $rust_target (skipping)"
return 0
fi
# Skip if already built
if [ -f "$install_prefix/lib/libcrypto.a" ]; then
print_success "OpenSSL already built for $rust_target (skipping)"
return 0
fi
print_step "Building OpenSSL for $rust_target ($openssl_target)"
print_step "Building OpenSSL for $rust_target ($openssl_target)"
# Clean and re-extract source for each target (OpenSSL doesn't support out-of-tree builds well)
local build_src="$OPENSSL_BUILD_DIR/build-$rust_target"
local logfile="$OPENSSL_BUILD_DIR/$rust_target.log"
rm -rf "$build_src"
: > "$logfile"
cp -r "$OPENSSL_SRC_DIR" "$build_src"
cd "$build_src"
# Clean and re-extract source for each target (OpenSSL doesn't support out-of-tree builds well)
local build_src="$OPENSSL_BUILD_DIR/build-$rust_target"
local logfile="$OPENSSL_BUILD_DIR/$rust_target.log"
rm -rf "$build_src"
: >"$logfile"
cp -r "$OPENSSL_SRC_DIR" "$build_src"
cd "$build_src"
export ANDROID_NDK_ROOT="$ANDROID_NDK_HOME"
export PATH="$TOOLCHAIN/bin:$PATH"
export ANDROID_NDK_ROOT="$ANDROID_NDK_HOME"
export PATH="$TOOLCHAIN/bin:$PATH"
run_quiet "Configuring ($openssl_target)..." "$logfile" \
./Configure "$openssl_target" \
-D__ANDROID_API__=$ANDROID_API \
--prefix="$install_prefix" \
--openssldir="$install_prefix/ssl" \
no-shared \
no-tests \
no-ui-console \
no-stdio \
-fPIC
run_quiet "Configuring ($openssl_target)..." "$logfile" \
./Configure "$openssl_target" \
-D__ANDROID_API__=$ANDROID_API \
--prefix="$install_prefix" \
--openssldir="$install_prefix/ssl" \
no-shared \
no-tests \
no-ui-console \
no-stdio \
-fPIC
run_quiet "Compiling..." "$logfile" \
make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" build_libs
run_quiet "Compiling..." "$logfile" \
make -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu)" build_libs
run_quiet "Installing headers & libs..." "$logfile" \
make install_dev
run_quiet "Installing headers & libs..." "$logfile" \
make install_dev
cd "$PROJECT_ROOT"
rm -rf "$build_src"
cd "$PROJECT_ROOT"
rm -rf "$build_src"
if [ -f "$install_prefix/lib/libcrypto.a" ]; then
print_success " Built OpenSSL for $rust_target"
else
print_error "Failed to build OpenSSL for $rust_target"
print_error "Check log: $logfile"
exit 1
fi
if [ -f "$install_prefix/lib/libcrypto.a" ]; then
print_success " Built OpenSSL for $rust_target"
else
print_error "Failed to build OpenSSL for $rust_target"
print_error "Check log: $logfile"
exit 1
fi
}
# Download OpenSSL source if needed
if [ ! -d "$OPENSSL_SRC_DIR" ]; then
print_step "Downloading OpenSSL $OPENSSL_VERSION"
mkdir -p "$OPENSSL_BUILD_DIR"
cd "$OPENSSL_BUILD_DIR"
print_step "Downloading OpenSSL $OPENSSL_VERSION"
mkdir -p "$OPENSSL_BUILD_DIR"
cd "$OPENSSL_BUILD_DIR"
TARBALL="openssl-$OPENSSL_VERSION.tar.gz"
if [ ! -f "$TARBALL" ]; then
curl -L --progress-bar -o "$TARBALL" "https://github.com/openssl/openssl/releases/download/openssl-$OPENSSL_VERSION/$TARBALL"
fi
TARBALL="openssl-$OPENSSL_VERSION.tar.gz"
if [ ! -f "$TARBALL" ]; then
curl -L --progress-bar -o "$TARBALL" "https://github.com/openssl/openssl/releases/download/openssl-$OPENSSL_VERSION/$TARBALL"
fi
print_step "Verifying tarball integrity"
if command -v shasum >/dev/null 2>&1; then
ACTUAL_SHA256=$(shasum -a 256 "$TARBALL" | awk '{print $1}')
elif command -v sha256sum >/dev/null 2>&1; then
ACTUAL_SHA256=$(sha256sum "$TARBALL" | awk '{print $1}')
else
print_error "No SHA-256 tool found (need shasum or sha256sum)"
exit 1
fi
if [ "$ACTUAL_SHA256" != "$OPENSSL_SHA256" ]; then
print_error "SHA-256 mismatch for $TARBALL"
print_error " Expected: $OPENSSL_SHA256"
print_error " Actual: $ACTUAL_SHA256"
rm -f "$TARBALL"
exit 1
fi
print_success "SHA-256 verified"
print_step "Verifying tarball integrity"
if command -v shasum >/dev/null 2>&1; then
ACTUAL_SHA256=$(shasum -a 256 "$TARBALL" | awk '{print $1}')
elif command -v sha256sum >/dev/null 2>&1; then
ACTUAL_SHA256=$(sha256sum "$TARBALL" | awk '{print $1}')
else
print_error "No SHA-256 tool found (need shasum or sha256sum)"
exit 1
fi
if [ "$ACTUAL_SHA256" != "$OPENSSL_SHA256" ]; then
print_error "SHA-256 mismatch for $TARBALL"
print_error " Expected: $OPENSSL_SHA256"
print_error " Actual: $ACTUAL_SHA256"
rm -f "$TARBALL"
exit 1
fi
print_success "SHA-256 verified"
tar xzf "$TARBALL"
cd "$PROJECT_ROOT"
tar xzf "$TARBALL"
cd "$PROJECT_ROOT"
fi
# Build for each target
for target_spec in "${TARGETS[@]}"; do
IFS=':' read -r rust_target openssl_target arch <<< "$target_spec"
build_openssl_for_target "$rust_target" "$openssl_target" "$arch"
IFS=':' read -r rust_target openssl_target arch <<<"$target_spec"
build_openssl_for_target "$rust_target" "$openssl_target" "$arch"
done
print_success "All OpenSSL Android builds complete!"
+92 -83
View File
@@ -24,11 +24,11 @@ BLUE='\033[0;34m'
YELLOW='\033[1;33m'
NC='\033[0m'
print_step() { echo -e "\n${BLUE}=== $1 ===${NC}"; }
print_step() { echo -e "\n${BLUE}=== $1 ===${NC}"; }
print_success() { echo -e "${GREEN}$1${NC}"; }
print_warning() { echo -e "${YELLOW}⚠️ $1${NC}"; }
print_error() { echo -e "${RED}$1${NC}"; }
print_info() { echo -e "${BLUE}$1${NC}"; }
print_error() { echo -e "${RED}$1${NC}"; }
print_info() { echo -e "${BLUE}$1${NC}"; }
# ---------------------------------------------------------------------------
# Argument parsing
@@ -39,31 +39,40 @@ BUILD_IOS=false
CUSTOM_OUTPUT_DIR=""
while [[ $# -gt 0 ]]; do
case $1 in
--android) BUILD_ANDROID=true; shift ;;
--ios) BUILD_IOS=true; shift ;;
--output-dir) CUSTOM_OUTPUT_DIR="$2"; shift 2 ;;
--help)
sed -n '/^# Usage:/,/^[^#]/p' "$0" | sed 's/^# \{0,2\}//'
exit 0
;;
*)
print_error "Unknown option: $1"
exit 1
;;
esac
case $1 in
--android)
BUILD_ANDROID=true
shift
;;
--ios)
BUILD_IOS=true
shift
;;
--output-dir)
CUSTOM_OUTPUT_DIR="$2"
shift 2
;;
--help)
sed -n '/^# Usage:/,/^[^#]/p' "$0" | sed 's/^# \{0,2\}//'
exit 0
;;
*)
print_error "Unknown option: $1"
exit 1
;;
esac
done
# Default: build both (iOS only on macOS)
if [ "$BUILD_ANDROID" = false ] && [ "$BUILD_IOS" = false ]; then
BUILD_ANDROID=true
[[ "$OSTYPE" == "darwin"* ]] && BUILD_IOS=true
BUILD_ANDROID=true
[[ "$OSTYPE" == "darwin"* ]] && BUILD_IOS=true
fi
# iOS requires macOS
if [ "$BUILD_IOS" = true ] && [[ "$OSTYPE" != "darwin"* ]]; then
print_warning "iOS builds require macOS — skipping iOS."
BUILD_IOS=false
print_warning "iOS builds require macOS — skipping iOS."
BUILD_IOS=false
fi
# ---------------------------------------------------------------------------
@@ -72,8 +81,8 @@ fi
VERSION_LINE=$(grep "^version:" pubspec.yaml)
if [ -z "$VERSION_LINE" ]; then
print_error "Could not find version in pubspec.yaml"
exit 1
print_error "Could not find version in pubspec.yaml"
exit 1
fi
FULL_VERSION=$(echo "$VERSION_LINE" | sed 's/version: //' | tr -d ' ')
@@ -85,9 +94,9 @@ BUILD_NUMBER=$(echo "$FULL_VERSION" | cut -d'+' -f2)
# ---------------------------------------------------------------------------
if [ -n "$CUSTOM_OUTPUT_DIR" ]; then
OUTPUT_DIR="$CUSTOM_OUTPUT_DIR"
OUTPUT_DIR="$CUSTOM_OUTPUT_DIR"
else
OUTPUT_DIR="build/releases/v${VERSION_NAME}+${BUILD_NUMBER}"
OUTPUT_DIR="build/releases/v${VERSION_NAME}+${BUILD_NUMBER}"
fi
# ---------------------------------------------------------------------------
@@ -106,43 +115,43 @@ mkdir -p "$OUTPUT_DIR"
# ---------------------------------------------------------------------------
if [ "$BUILD_ANDROID" = true ]; then
print_step "Building Android"
print_info "Building Rust native libraries..."
./scripts/build_android.sh
print_step "Building Android"
print_info "Building Rust native libraries..."
./scripts/build_android.sh
print_info "Building split APKs (production flavor)..."
flutter build apk --flavor production --split-per-abi
print_info "Building split APKs (production flavor)..."
flutter build apk --flavor production --split-per-abi
APK_DIR="build/app/outputs/flutter-apk"
APK_DIR="build/app/outputs/flutter-apk"
print_step "Staging Android artifacts"
print_step "Staging Android artifacts"
for ABI in arm64-v8a armeabi-v7a x86_64; do
# Flutter names the file: app-<abi>-production-release.apk
SRC=$(find "$APK_DIR" -name "app-${ABI}-production-release.apk" -type f | head -n 1)
for ABI in arm64-v8a armeabi-v7a x86_64; do
# Flutter names the file: app-<abi>-production-release.apk
SRC=$(find "$APK_DIR" -name "app-${ABI}-production-release.apk" -type f | head -n 1)
if [ -z "$SRC" ] || [ ! -f "$SRC" ]; then
if [ "$ABI" = "armeabi-v7a" ]; then
print_warning "armeabi-v7a APK not found (expected for modern-only builds)"
else
print_error "$ABI APK not found in $APK_DIR"
fi
continue
fi
if [ -z "$SRC" ] || [ ! -f "$SRC" ]; then
if [ "$ABI" = "armeabi-v7a" ]; then
print_warning "armeabi-v7a APK not found (expected for modern-only builds)"
else
print_error "$ABI APK not found in $APK_DIR"
fi
continue
fi
DEST_NAME="whitenoise-${VERSION_NAME}-${ABI}.apk"
DEST="$OUTPUT_DIR/$DEST_NAME"
DEST_NAME="whitenoise-${VERSION_NAME}-${ABI}.apk"
DEST="$OUTPUT_DIR/$DEST_NAME"
cp "$SRC" "$DEST"
cp "$SRC" "$DEST"
# SHA-256 file hash (download integrity)
HASH=$(shasum -a 256 "$DEST" | awk '{print $1}')
echo "$HASH $DEST_NAME" > "${DEST}.sha256"
# SHA-256 file hash (download integrity)
HASH=$(shasum -a 256 "$DEST" | awk '{print $1}')
echo "$HASH $DEST_NAME" >"${DEST}.sha256"
print_success "$DEST_NAME"
print_info " SHA-256: $HASH"
print_info " Hash file: ${DEST_NAME}.sha256"
done
print_success "$DEST_NAME"
print_info " SHA-256: $HASH"
print_info " Hash file: ${DEST_NAME}.sha256"
done
fi
# ---------------------------------------------------------------------------
@@ -150,22 +159,22 @@ fi
# ---------------------------------------------------------------------------
if [ "$BUILD_IOS" = true ]; then
print_step "Building iOS"
print_info "Building Rust native libraries..."
./scripts/build_ios.sh
print_step "Building iOS"
print_info "Building Rust native libraries..."
./scripts/build_ios.sh
print_info "Building IPA (production flavor)..."
flutter build ipa --flavor production --export-method app-store
print_info "Building IPA (production flavor)..."
flutter build ipa --flavor production --export-method app-store
IPA_PATH=$(find build/ios -name "*.ipa" -type f | head -n 1)
IPA_PATH=$(find build/ios -name "*.ipa" -type f | head -n 1)
if [ -n "$IPA_PATH" ] && [ -f "$IPA_PATH" ]; then
DEST_NAME="whitenoise-${VERSION_NAME}+${BUILD_NUMBER}.ipa"
cp "$IPA_PATH" "$OUTPUT_DIR/$DEST_NAME"
print_success "$DEST_NAME"
else
print_warning "IPA not found after build — check signing configuration"
fi
if [ -n "$IPA_PATH" ] && [ -f "$IPA_PATH" ]; then
DEST_NAME="whitenoise-${VERSION_NAME}+${BUILD_NUMBER}.ipa"
cp "$IPA_PATH" "$OUTPUT_DIR/$DEST_NAME"
print_success "$DEST_NAME"
else
print_warning "IPA not found after build — check signing configuration"
fi
fi
# ---------------------------------------------------------------------------
@@ -175,24 +184,24 @@ fi
print_step "Writing build_info.txt"
{
echo "White Noise Build Information"
echo "=============================="
echo ""
echo "Version: $VERSION_NAME"
echo "Build Number: $BUILD_NUMBER"
echo "Build Date: $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
echo "Git Commit: $(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')"
echo "Git Branch: $(git branch --show-current 2>/dev/null || echo 'unknown')"
echo ""
echo "Artifacts:"
for f in "$OUTPUT_DIR"/*.apk "$OUTPUT_DIR"/*.ipa; do
[ -f "$f" ] || continue
fname=$(basename "$f")
hash=$(shasum -a 256 "$f" | awk '{print $1}')
echo " $fname"
echo " SHA-256: $hash"
done
} > "$OUTPUT_DIR/build_info.txt"
echo "White Noise Build Information"
echo "=============================="
echo ""
echo "Version: $VERSION_NAME"
echo "Build Number: $BUILD_NUMBER"
echo "Build Date: $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
echo "Git Commit: $(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')"
echo "Git Branch: $(git branch --show-current 2>/dev/null || echo 'unknown')"
echo ""
echo "Artifacts:"
for f in "$OUTPUT_DIR"/*.apk "$OUTPUT_DIR"/*.ipa; do
[ -f "$f" ] || continue
fname=$(basename "$f")
hash=$(shasum -a 256 "$f" | awk '{print $1}')
echo " $fname"
echo " SHA-256: $hash"
done
} >"$OUTPUT_DIR/build_info.txt"
print_success "build_info.txt written"
+115 -115
View File
@@ -19,141 +19,141 @@ MIN_COVERAGE=""
WARNINGS_FILE=""
print_error() {
printf '%b%s%b\n' "\e[31;1m" "$1" "\e[0m" >&2
printf '%b%s%b\n' "\e[31;1m" "$1" "\e[0m" >&2
}
print_success() {
printf '%b%s%b\n' "\e[32;1m" "$1" "\e[0m" >&2
printf '%b%s%b\n' "\e[32;1m" "$1" "\e[0m" >&2
}
print_warning() {
printf '%b%s%b\n' "\e[33;1m" "$1" "\e[0m" >&2
printf '%b%s%b\n' "\e[33;1m" "$1" "\e[0m" >&2
}
raise_error() {
print_error "$1"
exit 1
print_error "$1"
exit 1
}
parse_arguments() {
while [[ $# -gt 0 ]]; do
case $1 in
--min)
MIN_COVERAGE="$2"
shift 2
;;
--warnings-file)
WARNINGS_FILE="$2"
shift 2
;;
*)
LCOV_FILE="$1"
shift
;;
esac
done
while [[ $# -gt 0 ]]; do
case $1 in
--min)
MIN_COVERAGE="$2"
shift 2
;;
--warnings-file)
WARNINGS_FILE="$2"
shift 2
;;
*)
LCOV_FILE="$1"
shift
;;
esac
done
}
check_lcov_file_presence() {
if [ ! -f "$LCOV_FILE" ]; then
raise_error "Error: $LCOV_FILE not found. Run 'flutter test --coverage' first."
fi
if [ ! -f "$LCOV_FILE" ]; then
raise_error "Error: $LCOV_FILE not found. Run 'flutter test --coverage' first."
fi
}
is_generated_file() {
local file="$1"
if [[ "$file" == *".freezed.dart" ]] ||
[[ "$file" == *".g.dart" ]] ||
[[ "$file" == lib/src/rust/* ]] ||
[[ "$file" == lib/l10n/generated/* ]]; then
return 0
fi
return 1
local file="$1"
if [[ "$file" == *".freezed.dart" ]] ||
[[ "$file" == *".g.dart" ]] ||
[[ "$file" == lib/src/rust/* ]] ||
[[ "$file" == lib/l10n/generated/* ]]; then
return 0
fi
return 1
}
is_coverage_ignored() {
local file="$1"
grep -q '// coverage:ignore-file' "$file"
local file="$1"
grep -q '// coverage:ignore-file' "$file"
}
count_lines() {
local file="$1"
wc -l <"$file" | tr -d ' '
local file="$1"
wc -l <"$file" | tr -d ' '
}
get_covered_files() {
grep "^SF:" "$LCOV_FILE" | sed 's/^SF://' | sort -u
grep "^SF:" "$LCOV_FILE" | sed 's/^SF://' | sort -u
}
generate_zero_coverage_record() {
local file="$1"
local line_count="$2"
local file="$1"
local line_count="$2"
echo "SF:$file"
for ((i = 1; i <= line_count; i++)); do
echo "DA:$i,0"
done
echo "LF:$line_count"
echo "LH:0"
echo "end_of_record"
echo "SF:$file"
for ((i = 1; i <= line_count; i++)); do
echo "DA:$i,0"
done
echo "LF:$line_count"
echo "LH:0"
echo "end_of_record"
}
print_missing_files_warning() {
local missing_count="$1"
shift
local missing_files=("$@")
local missing_count="$1"
shift
local missing_files=("$@")
if [ "$missing_count" -gt 0 ]; then
print_warning "⚠️ Found $missing_count file(s) with no test coverage:"
for file in "${missing_files[@]}"; do
print_warning " - $file"
done
fi
if [ "$missing_count" -gt 0 ]; then
print_warning "⚠️ Found $missing_count file(s) with no test coverage:"
for file in "${missing_files[@]}"; do
print_warning " - $file"
done
fi
}
inject_missing_files() {
local missing_count=0
local missing_files=()
local covered_files
covered_files=$(get_covered_files)
local missing_count=0
local missing_files=()
local covered_files
covered_files=$(get_covered_files)
while IFS= read -r -d '' dart_file; do
dart_file="${dart_file#./}"
while IFS= read -r -d '' dart_file; do
dart_file="${dart_file#./}"
if is_generated_file "$dart_file"; then
continue
fi
if is_generated_file "$dart_file"; then
continue
fi
if is_coverage_ignored "$dart_file"; then
continue
fi
if is_coverage_ignored "$dart_file"; then
continue
fi
if echo "$covered_files" | grep -qx "$dart_file"; then
continue
fi
if echo "$covered_files" | grep -qx "$dart_file"; then
continue
fi
local line_count
line_count=$(count_lines "$dart_file")
local line_count
line_count=$(count_lines "$dart_file")
if [ "$line_count" -gt 0 ]; then
generate_zero_coverage_record "$dart_file" "$line_count" >>"$LCOV_FILE"
missing_files+=("$dart_file")
missing_count=$((missing_count + 1))
fi
done < <(find lib -name "*.dart" -type f -print0 2>/dev/null)
if [ "$line_count" -gt 0 ]; then
generate_zero_coverage_record "$dart_file" "$line_count" >>"$LCOV_FILE"
missing_files+=("$dart_file")
missing_count=$((missing_count + 1))
fi
done < <(find lib -name "*.dart" -type f -print0 2>/dev/null)
if [ "$missing_count" -gt 0 ]; then
print_missing_files_warning "$missing_count" "${missing_files[@]}"
if [ -n "$WARNINGS_FILE" ]; then
printf '%s\n' "${missing_files[@]}" >"$WARNINGS_FILE"
fi
elif [ -n "$WARNINGS_FILE" ]; then
: >"$WARNINGS_FILE"
fi
if [ "$missing_count" -gt 0 ]; then
print_missing_files_warning "$missing_count" "${missing_files[@]}"
if [ -n "$WARNINGS_FILE" ]; then
printf '%s\n' "${missing_files[@]}" >"$WARNINGS_FILE"
fi
elif [ -n "$WARNINGS_FILE" ]; then
: >"$WARNINGS_FILE"
fi
}
filter_generated_files() {
awk '
awk '
BEGIN { skip = 0 }
/^SF:/ {
file = substr($0, 4)
@@ -172,11 +172,11 @@ filter_generated_files() {
}
{ if (!skip) print }
' "$LCOV_FILE" >"${LCOV_FILE}.tmp"
mv "${LCOV_FILE}.tmp" "$LCOV_FILE"
mv "${LCOV_FILE}.tmp" "$LCOV_FILE"
}
calculate_coverage() {
awk '
awk '
BEGIN {
total_lines = 0
covered_lines = 0
@@ -209,43 +209,43 @@ calculate_coverage() {
}
check_coverage_threshold() {
local coverage="$1"
local min_coverage="$2"
local coverage="$1"
local min_coverage="$2"
if (($(awk "BEGIN {print ($coverage >= $min_coverage)}"))); then
return 0
fi
return 1
if (($(awk "BEGIN {print ($coverage >= $min_coverage)}"))); then
return 0
fi
return 1
}
print_coverage_result() {
local coverage="$1"
local min_coverage="$2"
local coverage="$1"
local min_coverage="$2"
if check_coverage_threshold "$coverage" "$min_coverage"; then
print_success "✅ Coverage: ${coverage}%"
exit 0
else
print_error "❌ Coverage: ${coverage}% (below minimum ${min_coverage}%)"
exit 1
fi
if check_coverage_threshold "$coverage" "$min_coverage"; then
print_success "✅ Coverage: ${coverage}%"
exit 0
else
print_error "❌ Coverage: ${coverage}% (below minimum ${min_coverage}%)"
exit 1
fi
}
main() {
parse_arguments "$@"
check_lcov_file_presence
inject_missing_files
filter_generated_files
parse_arguments "$@"
check_lcov_file_presence
inject_missing_files
filter_generated_files
local coverage
coverage=$(calculate_coverage)
local coverage
coverage=$(calculate_coverage)
if [ -z "$MIN_COVERAGE" ]; then
echo "$coverage"
exit 0
fi
if [ -z "$MIN_COVERAGE" ]; then
echo "$coverage"
exit 0
fi
print_coverage_result "$coverage" "$MIN_COVERAGE"
print_coverage_result "$coverage" "$MIN_COVERAGE"
}
main "$@"
+11 -5
View File
@@ -19,10 +19,16 @@ INPUT="$1"
# Detect format and normalize to both npub and hex
if [[ "$INPUT" == npub1* ]]; then
NPUB="$INPUT"
HEX=$(nak decode "$INPUT" 2>/dev/null) || { echo "ERROR: Invalid npub"; exit 1; }
HEX=$(nak decode "$INPUT" 2>/dev/null) || {
echo "ERROR: Invalid npub"
exit 1
}
else
HEX="$INPUT"
NPUB=$(nak encode npub "$INPUT" 2>/dev/null) || { echo "ERROR: Invalid hex pubkey"; exit 1; }
NPUB=$(nak encode npub "$INPUT" 2>/dev/null) || {
echo "ERROR: Invalid hex pubkey"
exit 1
}
fi
SOURCE_RELAYS="wss://relay.primal.net wss://relay.damus.io wss://purplepag.es wss://nos.lol"
@@ -78,12 +84,12 @@ while read -r pk; do
[ -z "$event" ] && continue
publish "$event" >/dev/null 2>&1
BATCH_COUNT=$((BATCH_COUNT + 1))
done <<< "$EVENTS"
done <<<"$EVENTS"
PUBLISHED=$((PUBLISHED + BATCH_COUNT))
printf " batch %d: %d metadata events (%d total)\n" "$BATCH_NUM" "$BATCH_COUNT" "$PUBLISHED"
BATCH_ARGS=()
fi
done <<< "$PUBKEYS"
done <<<"$PUBKEYS"
if [ ${#BATCH_ARGS[@]} -gt 0 ]; then
BATCH_NUM=$((BATCH_NUM + 1))
@@ -93,7 +99,7 @@ if [ ${#BATCH_ARGS[@]} -gt 0 ]; then
[ -z "$event" ] && continue
publish "$event" >/dev/null 2>&1
BATCH_COUNT=$((BATCH_COUNT + 1))
done <<< "$EVENTS"
done <<<"$EVENTS"
PUBLISHED=$((PUBLISHED + BATCH_COUNT))
printf " batch %d: %d metadata events (%d total)\n" "$BATCH_NUM" "$BATCH_COUNT" "$PUBLISHED"
fi
+20 -17
View File
@@ -7,44 +7,47 @@ echo "🔧 Setting up Android Cargo configuration..."
# Function to print colored output
print_success() {
echo -e "\033[1;32m✅ $1\033[0m"
echo -e "\033[1;32m✅ $1\033[0m"
}
print_error() {
echo -e "\033[1;31m❌ $1\033[0m"
echo -e "\033[1;31m❌ $1\033[0m"
}
# Detect host OS for NDK toolchain path
case "$(uname -s)" in
Darwin*) HOST_TAG="darwin-x86_64" ;;
Linux*) HOST_TAG="linux-x86_64" ;;
MINGW*|CYGWIN*|MSYS*) HOST_TAG="windows-x86_64" ;;
*) print_error "Unsupported host OS: $(uname -s)"; exit 1 ;;
Darwin*) HOST_TAG="darwin-x86_64" ;;
Linux*) HOST_TAG="linux-x86_64" ;;
MINGW* | CYGWIN* | MSYS*) HOST_TAG="windows-x86_64" ;;
*)
print_error "Unsupported host OS: $(uname -s)"
exit 1
;;
esac
# Auto-detect Android NDK
if [ -z "$ANDROID_NDK_HOME" ]; then
if [ -n "$ANDROID_HOME" ]; then
NDK_DIR="$ANDROID_HOME/ndk"
if [ -d "$NDK_DIR" ]; then
NDK_VERSION=$(ls "$NDK_DIR" | sort -V | tail -n 1)
if [ -n "$NDK_VERSION" ]; then
ANDROID_NDK_HOME="$NDK_DIR/$NDK_VERSION"
fi
fi
if [ -n "$ANDROID_HOME" ]; then
NDK_DIR="$ANDROID_HOME/ndk"
if [ -d "$NDK_DIR" ]; then
NDK_VERSION=$(ls "$NDK_DIR" | sort -V | tail -n 1)
if [ -n "$NDK_VERSION" ]; then
ANDROID_NDK_HOME="$NDK_DIR/$NDK_VERSION"
fi
fi
fi
fi
if [ -z "$ANDROID_NDK_HOME" ] || [ ! -d "$ANDROID_NDK_HOME" ]; then
print_error "Android NDK not found. Please set ANDROID_NDK_HOME environment variable"
exit 1
print_error "Android NDK not found. Please set ANDROID_NDK_HOME environment variable"
exit 1
fi
# Create .cargo directory if it doesn't exist
mkdir -p rust/.cargo
# Generate config.toml
cat > rust/.cargo/config.toml << EOF
cat >rust/.cargo/config.toml <<EOF
[target.aarch64-linux-android]
ar = "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/${HOST_TAG}/bin/llvm-ar"
linker = "${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/${HOST_TAG}/bin/aarch64-linux-android33-clang"
+14 -14
View File
@@ -36,9 +36,9 @@ html_escape() {
}
format_date() {
date -u -d "$1" '+%B %d, %Y at %H:%M UTC' 2>/dev/null \
|| TZ=UTC date -jf '%Y-%m-%dT%H:%M:%SZ' "$1" '+%B %d, %Y at %H:%M UTC' 2>/dev/null \
|| echo "$1"
date -u -d "$1" '+%B %d, %Y at %H:%M UTC' 2>/dev/null ||
TZ=UTC date -jf '%Y-%m-%dT%H:%M:%SZ' "$1" '+%B %d, %Y at %H:%M UTC' 2>/dev/null ||
echo "$1"
}
# ---------------------------------------------------------------------------
@@ -53,9 +53,9 @@ if [[ -z "$RUN_ID" ]]; then
exit 1
fi
HEAD_SHA=$(echo "$RUNS_JSON" | jq -r '.workflow_runs[0].head_sha')
RUN_URL=$(echo "$RUNS_JSON" | jq -r '.workflow_runs[0].html_url')
RUN_DATE=$(echo "$RUNS_JSON" | jq -r '.workflow_runs[0].updated_at')
HEAD_SHA=$(echo "$RUNS_JSON" | jq -r '.workflow_runs[0].head_sha')
RUN_URL=$(echo "$RUNS_JSON" | jq -r '.workflow_runs[0].html_url')
RUN_DATE=$(echo "$RUNS_JSON" | jq -r '.workflow_runs[0].updated_at')
echo " Run #$RUN_ID sha=$HEAD_SHA"
@@ -66,7 +66,7 @@ echo "Fetching artifacts..."
ARTIFACTS_JSON=$(gh_api "$API/repos/$REPO/actions/runs/$RUN_ID/artifacts")
ARTIFACT_NAME=$(echo "$ARTIFACTS_JSON" | jq -r '.artifacts[0].name // empty')
ARTIFACT_ID=$(echo "$ARTIFACTS_JSON" | jq -r '.artifacts[0].id // empty')
ARTIFACT_ID=$(echo "$ARTIFACTS_JSON" | jq -r '.artifacts[0].id // empty')
ARTIFACT_SIZE=$(echo "$ARTIFACTS_JSON" | jq -r '.artifacts[0].size_in_bytes // 0')
ARTIFACT_EXPIRED=$(echo "$ARTIFACTS_JSON" | jq -r '.artifacts[0].expired // false')
@@ -91,10 +91,10 @@ echo " Artifact: $ARTIFACT_NAME ($ARTIFACT_SIZE_MB MB)"
echo "Fetching commit info for $HEAD_SHA..."
COMMIT_JSON=$(gh_api "$API/repos/$REPO/commits/$HEAD_SHA")
COMMIT_MSG=$(echo "$COMMIT_JSON" | jq -r '.commit.message' | head -1)
COMMIT_MSG=$(echo "$COMMIT_JSON" | jq -r '.commit.message' | head -1)
COMMIT_AUTHOR=$(echo "$COMMIT_JSON" | jq -r '.commit.author.name')
COMMIT_AUTHOR_ESCAPED=$(html_escape "$COMMIT_AUTHOR")
COMMIT_DATE=$(echo "$COMMIT_JSON" | jq -r '.commit.author.date')
COMMIT_DATE=$(echo "$COMMIT_JSON" | jq -r '.commit.author.date')
COMMIT_URL="https://github.com/$REPO/commit/$HEAD_SHA"
SHORT_SHA="${HEAD_SHA:0:7}"
@@ -236,7 +236,7 @@ PRETTY_COMMIT_DATE=$(format_date "$COMMIT_DATE")
# Escape commit message for safe HTML embedding
COMMIT_MSG_ESCAPED=$(html_escape "$COMMIT_MSG")
cat > "$OUT_DIR/index.html" <<'HTMLEOF_PART1'
cat >"$OUT_DIR/index.html" <<'HTMLEOF_PART1'
<!DOCTYPE html>
<html lang="en">
<head>
@@ -577,7 +577,7 @@ cat > "$OUT_DIR/index.html" <<'HTMLEOF_PART1'
HTMLEOF_PART1
# --- inject dynamic master build values ---
cat >> "$OUT_DIR/index.html" <<HTMLEOF_PART2
cat >>"$OUT_DIR/index.html" <<HTMLEOF_PART2
<a class="nes-btn" href="${NIGHTLY_LINK_URL}">
&#9733; DOWNLOAD APK &#9733;
</a>
@@ -646,11 +646,11 @@ HTMLEOF_PART2
# --- inject PR builds ---
if [[ -n "$PR_BUILDS_HTML" ]]; then
cat >> "$OUT_DIR/index.html" <<HTMLEOF_PR_BUILDS
cat >>"$OUT_DIR/index.html" <<HTMLEOF_PR_BUILDS
${PR_BUILDS_HTML}
HTMLEOF_PR_BUILDS
else
cat >> "$OUT_DIR/index.html" <<'HTMLEOF_PR_EMPTY'
cat >>"$OUT_DIR/index.html" <<'HTMLEOF_PR_EMPTY'
<div class="nes-box is-dark">
<p class="pr-empty">
No active PR builds right now.<br>
@@ -661,7 +661,7 @@ HTMLEOF_PR_EMPTY
fi
# --- close out the page ---
cat >> "$OUT_DIR/index.html" <<HTMLEOF_PART3
cat >>"$OUT_DIR/index.html" <<HTMLEOF_PART3
</div>
<div class="pixel-divider">&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;</div>