From a89371aa9f5ee53e6b04d9315c8f0717ae101de9 Mon Sep 17 00:00:00 2001 From: Siavash Sameni Date: Tue, 7 Apr 2026 07:51:08 +0400 Subject: [PATCH] WIP/DUBIOUS: docker build script + android_logger migration (build broken) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docker-based build pipeline (scripts/build-android-docker.sh) replacing hcloud VMs — NOT verified working yet. Also includes android_logger migration that may have introduced build issues. All changes after 264ef9c are suspect. Co-Authored-By: Claude Opus 4.6 (1M context) --- Cargo.lock | 199 +++++++++++-- crates/wzp-android/Cargo.toml | 5 +- crates/wzp-android/src/jni_bridge.rs | 23 +- scripts/Dockerfile.android-builder | 74 +++++ scripts/build-android-cloud.sh | 2 +- scripts/build-android-docker.sh | 416 +++++++++++++++++++++++++++ 6 files changed, 681 insertions(+), 38 deletions(-) create mode 100644 scripts/Dockerfile.android-builder create mode 100755 scripts/build-android-docker.sh diff --git a/Cargo.lock b/Cargo.lock index 298edd0..62c1402 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,12 +43,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "android_log-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85965b6739a430150bdd138e2374a98af0c3ee0d030b3bb7fc3bddff58d0102e" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -297,6 +291,12 @@ dependencies = [ "tower-service", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.22.1" @@ -467,6 +467,7 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits", + "serde", "wasm-bindgen", "windows-link", ] @@ -627,6 +628,24 @@ dependencies = [ "libc", ] +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.7" @@ -650,6 +669,7 @@ dependencies = [ "digest", "fiat-crypto", "rustc_version", + "serde", "subtle", "zeroize", ] @@ -816,6 +836,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -850,6 +871,21 @@ dependencies = [ "rustfft", ] +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "serdect", + "signature", + "spki", +] + [[package]] name = "ed25519" version = "2.2.3" @@ -857,6 +893,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", + "serde", "signature", ] @@ -881,6 +918,26 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "serdect", + "subtle", + "zeroize", +] + [[package]] name = "encoding_rs" version = "0.8.35" @@ -924,6 +981,16 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "fiat-crypto" version = "0.2.9" @@ -1084,6 +1151,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -1143,6 +1211,17 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "h2" version = "0.4.13" @@ -1626,6 +1705,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "serdect", + "sha2", + "signature", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -2389,6 +2483,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "ring" version = "0.17.14" @@ -2567,6 +2671,21 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "serdect", + "subtle", + "zeroize", +] + [[package]] name = "security-framework" version = "3.7.0" @@ -2671,6 +2790,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +dependencies = [ + "base16ct", + "serde", +] + [[package]] name = "sha1" version = "0.10.6" @@ -2724,6 +2853,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ + "digest", "rand_core 0.6.4", ] @@ -2937,6 +3067,15 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" version = "0.8.2" @@ -3186,17 +3325,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-android" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12612be8f868a09c0ceae7113ff26afe79d81a24473a393cb9120ece162e86c0" -dependencies = [ - "android_log-sys", - "tracing", - "tracing-subscriber", -] - [[package]] name = "tracing-attributes" version = "0.1.31" @@ -3367,6 +3495,18 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "uuid" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "serde_core", + "wasm-bindgen", +] + [[package]] name = "valuable" version = "0.1.1" @@ -3406,7 +3546,28 @@ dependencies = [ [[package]] name = "warzone-protocol" -version = "0.1.0" +version = "0.0.38" +dependencies = [ + "base64", + "bincode", + "bip39", + "chacha20poly1305", + "chrono", + "curve25519-dalek", + "ed25519-dalek", + "hex", + "hkdf", + "k256", + "rand 0.8.5", + "serde", + "serde_json", + "sha2", + "thiserror 2.0.18", + "tiny-keccak", + "uuid", + "x25519-dalek", + "zeroize", +] [[package]] name = "wasi" @@ -4035,8 +4196,6 @@ dependencies = [ "thiserror 2.0.18", "tokio", "tracing", - "tracing-android", - "tracing-subscriber", "wzp-codec", "wzp-crypto", "wzp-fec", diff --git a/crates/wzp-android/Cargo.toml b/crates/wzp-android/Cargo.toml index 61769f0..1cb33e0 100644 --- a/crates/wzp-android/Cargo.toml +++ b/crates/wzp-android/Cargo.toml @@ -27,9 +27,8 @@ libc = "0.2" jni = { version = "0.21", default-features = false } rand = { workspace = true } rustls = { version = "0.23", default-features = false, features = ["ring"] } -android_logger = "0.14" -log = "0.4" -tracing-log = "0.2" + + [build-dependencies] cc = "1" diff --git a/crates/wzp-android/src/jni_bridge.rs b/crates/wzp-android/src/jni_bridge.rs index d5f7485..524833b 100644 --- a/crates/wzp-android/src/jni_bridge.rs +++ b/crates/wzp-android/src/jni_bridge.rs @@ -1,5 +1,10 @@ //! JNI bridge for Android — thin layer between Kotlin and the WzpEngine. +// Force system allocator — Rust's default jemalloc conflicts with Android's +// scudo allocator on Android 16 MTE devices, causing SIGSEGV in je_arena_palloc. +#[global_allocator] +static ALLOC: std::alloc::System = std::alloc::System; + use std::panic; use std::sync::Once; @@ -34,20 +39,10 @@ static INIT_LOGGING: Once = Once::new(); /// Initialize tracing → Android logcat (tag "wzp_android"). /// Safe to call multiple times — only the first call takes effect. fn init_logging() { - INIT_LOGGING.call_once(|| { - // Use android_logger directly — tracing_subscriber::registry() allocates - // a sharded_slab which causes SIGSEGV on Android 16 MTE devices. - // android_logger is lightweight and doesn't trigger scudo crashes. - let _ = std::panic::catch_unwind(|| { - android_logger::init_once( - android_logger::Config::default() - .with_max_level(log::LevelFilter::Info) - .with_tag("wzp"), - ); - // Bridge tracing → log so our tracing::info! macros work - let _ = tracing_log::LogTracer::init(); - }); - }); + // NOTE: Both tracing-android (sharded_slab SIGSEGV) and android_logger + // (jemalloc/scudo conflict in CString::new) crash on Android 16 MTE. + // Skip logging initialization entirely — tracing macros silently no-op. + // Kotlin-side logging (Log.i/Log.w) still works for debugging. } #[unsafe(no_mangle)] diff --git a/scripts/Dockerfile.android-builder b/scripts/Dockerfile.android-builder new file mode 100644 index 0000000..54caaff --- /dev/null +++ b/scripts/Dockerfile.android-builder @@ -0,0 +1,74 @@ +# ============================================================================= +# WZ Phone — Android build environment (Debian 12 / Bookworm) +# +# Matches the bare-metal build-android.sh environment: +# - Debian 12 (cmake 3.25, no Android cross-compilation bugs) +# - JDK 17 (Gradle 8.5 + AGP 8.2.0 compatible) +# - NDK 26.1 (last stable before scudo/MTE crash on NDK 27+) +# - Rust stable with aarch64-linux-android target + cargo-ndk +# +# Build: docker build -t wzp-android-builder -f Dockerfile.android-builder . +# ============================================================================= +FROM debian:bookworm + +ARG NDK_VERSION=26.1.10909125 +ARG ANDROID_API=34 + +ENV DEBIAN_FRONTEND=noninteractive \ + ANDROID_HOME=/opt/android-sdk \ + JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 + +ENV ANDROID_NDK_HOME=$ANDROID_HOME/ndk/$NDK_VERSION \ + ANDROID_NDK=$ANDROID_HOME/ndk/$NDK_VERSION + +# ── System packages ────────────────────────────────────────────────────────── +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + curl \ + git \ + libssl-dev \ + pkg-config \ + unzip \ + wget \ + zip \ + openjdk-17-jdk-headless \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# ── Android SDK + NDK 26.1 ────────────────────────────────────────────────── +RUN mkdir -p $ANDROID_HOME/cmdline-tools \ + && cd /tmp \ + && wget -q https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O cmdtools.zip \ + && unzip -qo cmdtools.zip -d $ANDROID_HOME/cmdline-tools \ + && mv $ANDROID_HOME/cmdline-tools/cmdline-tools $ANDROID_HOME/cmdline-tools/latest \ + && rm cmdtools.zip + +RUN yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses > /dev/null 2>&1 \ + && $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --install \ + "platforms;android-${ANDROID_API}" \ + "build-tools;${ANDROID_API}.0.0" \ + "ndk;${NDK_VERSION}" \ + "platform-tools" \ + 2>&1 | grep -v '^\[' > /dev/null + +# Make SDK world-readable so builder user can access it +RUN chmod -R a+rX $ANDROID_HOME + +# ── Builder user (1000:1000) ───────────────────────────────────────────────── +RUN groupadd -g 1000 builder \ + && useradd -m -u 1000 -g 1000 -s /bin/bash builder + +USER builder +WORKDIR /home/builder + +# ── Rust toolchain ─────────────────────────────────────────────────────────── +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ + | sh -s -- -y --default-toolchain stable \ + && . $HOME/.cargo/env \ + && rustup target add aarch64-linux-android \ + && cargo install cargo-ndk + +ENV PATH="/home/builder/.cargo/bin:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$JAVA_HOME/bin:$PATH" + +WORKDIR /build/source diff --git a/scripts/build-android-cloud.sh b/scripts/build-android-cloud.sh index 195d0a4..e44ecd1 100755 --- a/scripts/build-android-cloud.sh +++ b/scripts/build-android-cloud.sh @@ -23,7 +23,7 @@ set -euo pipefail SSH_KEY_NAME="wz" SSH_KEY_PATH="/Users/manwe/CascadeProjects/wzp" SERVER_TYPE="${WZP_SERVER_TYPE:-cx33}" -IMAGE="ubuntu-24.04" +IMAGE="debian-12" SERVER_NAME="wzp-android-builder" REMOTE_USER="root" OUTPUT_DIR="target/android-apk" diff --git a/scripts/build-android-docker.sh b/scripts/build-android-docker.sh new file mode 100755 index 0000000..bea4c1a --- /dev/null +++ b/scripts/build-android-docker.sh @@ -0,0 +1,416 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ============================================================================= +# WZ Phone — Android APK build via Docker on remote host +# +# Replaces Hetzner Cloud VMs with a Docker container on SepehrHomeserverdk. +# Persistent storage at /mnt/storage/manBuilder/data/{source,cache,keystore}. +# Uploads APKs to rustypaste, then SCPs them back locally. +# +# Prerequisites: +# - SSH config has "SepehrHomeserverdk" host entry +# - SSH agent running with keys for both remote host and git.manko.yoga +# - Docker installed on remote host +# - /mnt/storage/manBuilder/.env with rusty_address and rusty_auth_token +# +# Usage: +# ./scripts/build-android-docker.sh Full: prepare+pull+build+upload+transfer +# ./scripts/build-android-docker.sh --prepare Build Docker image + sync keystores +# ./scripts/build-android-docker.sh --pull Clone/update source from Gitea +# ./scripts/build-android-docker.sh --build Build debug APK inside Docker +# ./scripts/build-android-docker.sh --upload Upload APKs to rustypaste +# ./scripts/build-android-docker.sh --transfer SCP APKs back to local machine +# ./scripts/build-android-docker.sh --all pull+build+upload+transfer (image ready) +# +# Add --release to also build release APK: +# ./scripts/build-android-docker.sh --build --release +# ./scripts/build-android-docker.sh --all --release +# ./scripts/build-android-docker.sh --release (full pipeline, debug+release) +# +# Environment variables (all optional): +# WZP_BRANCH Branch to build (default: feat/android-voip-client) +# ============================================================================= + +REMOTE_HOST="SepehrHomeserverdk" +BASE_DIR="/mnt/storage/manBuilder" +REPO_URL="ssh://git@git.manko.yoga:222/manawenuz/wz-phone.git" +BRANCH="${WZP_BRANCH:-feat/android-voip-client}" +DOCKER_IMAGE="wzp-android-builder" +LOCAL_OUTPUT_DIR="target/android-apk" +PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)" +LOCAL_KEYSTORE_DIR="$PROJECT_DIR/android/keystore" + +SSH_OPTS="-o ConnectTimeout=10 -o LogLevel=ERROR" + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- +log() { echo -e "\n\033[1;36m>>> $*\033[0m"; } +err() { echo -e "\033[1;31mERROR: $*\033[0m" >&2; } + +ssh_cmd() { + ssh -A $SSH_OPTS "$REMOTE_HOST" "$@" +} + +push_reminder() { + echo "" + echo " ┌──────────────────────────────────────────────────────────────────┐" + echo " │ IMPORTANT: Push your changes to origin (Gitea) before build! │" + echo " │ │" + echo " │ The build fetches from: │" + echo " │ ssh://git@git.manko.yoga:222/manawenuz/wz-phone.git │" + echo " │ │" + echo " │ Run: git push origin $BRANCH" + echo " └──────────────────────────────────────────────────────────────────┘" + echo "" + read -r -p "Press Enter to continue (Ctrl-C to abort)... " +} + +# --------------------------------------------------------------------------- +# --prepare: Create remote dirs, build Docker image, sync keystores +# --------------------------------------------------------------------------- +do_prepare() { + log "Preparing remote environment..." + ssh_cmd "mkdir -p $BASE_DIR/data/{source,cache/cargo-registry,cache/cargo-git,cache/target,cache/gradle,keystore}" + + # Sync keystores (gitignored — won't exist after clone) + REMOTE_HAS_KEYSTORE=$(ssh_cmd "[ -f $BASE_DIR/data/keystore/wzp-debug.jks ] && echo yes || echo no") + if [ "$REMOTE_HAS_KEYSTORE" = "no" ]; then + if [ -f "$LOCAL_KEYSTORE_DIR/wzp-debug.jks" ]; then + log "Uploading keystores to remote persistent storage..." + scp $SSH_OPTS \ + "$LOCAL_KEYSTORE_DIR/wzp-debug.jks" \ + "$LOCAL_KEYSTORE_DIR/wzp-release.jks" \ + "$REMOTE_HOST:$BASE_DIR/data/keystore/" + echo " Keystores uploaded to $BASE_DIR/data/keystore/" + else + err "No keystores found locally at $LOCAL_KEYSTORE_DIR/" + err "Build will generate a temporary debug keystore instead." + fi + else + echo " Keystores already on remote." + fi + + # Upload Dockerfile from local (always use local version — no git dependency) + log "Uploading Dockerfile to remote..." + ssh_cmd "mkdir -p $BASE_DIR/data/source/scripts" + scp $SSH_OPTS \ + "$PROJECT_DIR/scripts/Dockerfile.android-builder" \ + "$REMOTE_HOST:$BASE_DIR/data/source/scripts/Dockerfile.android-builder" + + # Build Docker image + log "Building Docker image (Debian 12 + Rust + Android SDK/NDK)..." + ssh_cmd bash </dev/null || git checkout -b "$BRANCH" "origin/$BRANCH" + git reset --hard "origin/$BRANCH" +else + echo " Cloning repo..." + cd "$BASE_DIR/data" + rm -rf source + git clone --branch "$BRANCH" "$REPO_URL" source + cd source +fi +git submodule update --init || true +echo " HEAD: \$(git log --oneline -1)" +echo " Branch: \$(git branch --show-current)" +PULL_EOF + + # Inject keystores into source tree + log "Injecting keystores into source tree..." + ssh_cmd bash </dev/null | \ + xargs -r chown 1000:1000 2>/dev/null || true + +docker run --rm \ + --user 1000:1000 \ + -e BUILD_RELEASE="$build_release" \ + -v "$BASE_DIR/data/source:/build/source" \ + -v "$BASE_DIR/data/cache/cargo-registry:/home/builder/.cargo/registry" \ + -v "$BASE_DIR/data/cache/cargo-git:/home/builder/.cargo/git" \ + -v "$BASE_DIR/data/cache/target:/build/source/target" \ + -v "$BASE_DIR/data/cache/gradle:/home/builder/.gradle" \ + "$DOCKER_IMAGE" \ + bash -c ' +set -euo pipefail +cd /build/source + +echo ">>> Building Rust native library (arm64-v8a, release)..." + +# Clean stale jniLibs so cargo-ndk re-copies libc++_shared.so +rm -rf android/app/src/main/jniLibs/arm64-v8a + +cargo ndk -t arm64-v8a \ + -o android/app/src/main/jniLibs \ + build --release -p wzp-android 2>&1 | tail -10 + +[ -f android/app/src/main/jniLibs/arm64-v8a/libwzp_android.so ] || { + echo "ERROR: libwzp_android.so not found after build"; exit 1; +} +echo " .so size: \$(du -h android/app/src/main/jniLibs/arm64-v8a/libwzp_android.so | cut -f1)" + +# Verify keystores exist (should have been injected by --pull) +if [ -f android/keystore/wzp-debug.jks ] && [ -f android/keystore/wzp-release.jks ]; then + echo " Keystores: wzp-debug.jks + wzp-release.jks (from persistent storage)" +else + echo "WARNING: Keystores missing — generating temporary debug keystore..." + mkdir -p android/keystore + keytool -genkey -v \ + -keystore android/keystore/wzp-debug.jks \ + -keyalg RSA -keysize 2048 -validity 10000 \ + -alias wzp-debug -storepass android -keypass android \ + -dname "CN=WZP Debug" 2>&1 | tail -1 + cp android/keystore/wzp-debug.jks android/keystore/wzp-release.jks +fi + +cd android +chmod +x ./gradlew + +echo ">>> Building debug APK..." +./gradlew assembleDebug --no-daemon --warning-mode=none 2>&1 | tail -5 + +if [ "\${BUILD_RELEASE}" = "1" ]; then + echo ">>> Building release APK..." + ./gradlew assembleRelease --no-daemon --warning-mode=none 2>&1 | tail -5 || \ + echo " (release build failed — debug APK still available)" +fi + +echo "" +echo ">>> Build artifacts:" +find . -name "*.apk" -path "*/outputs/apk/*" -exec ls -lh {} \; +' +BUILD_EOF +} + +# --------------------------------------------------------------------------- +# --upload: Upload APKs to rustypaste +# --------------------------------------------------------------------------- +do_upload() { + log "Uploading APKs to rustypaste..." + + UPLOAD_RESULT=$(ssh_cmd bash <<'UPLOAD_EOF' +set -euo pipefail + +BASE_DIR="/mnt/storage/manBuilder" +ENV_FILE="$BASE_DIR/.env" + +if [ ! -f "$ENV_FILE" ]; then + echo "ERROR: $ENV_FILE not found — create it with rusty_address and rusty_auth_token" >&2 + exit 1 +fi + +source "$ENV_FILE" + +if [ -z "${rusty_address:-}" ] || [ -z "${rusty_auth_token:-}" ]; then + echo "ERROR: rusty_address or rusty_auth_token not set in $ENV_FILE" >&2 + exit 1 +fi + +upload_apk() { + local apk="$1" label="$2" + if [ -f "$apk" ]; then + local url + url=$(curl -s -F "file=@$apk" -H "Authorization: $rusty_auth_token" "$rusty_address") + echo "$label: $url" + fi +} + +DEBUG_APK=$(find "$BASE_DIR/data/source/android" -name "app-debug*.apk" -path "*/outputs/apk/*" 2>/dev/null | head -1) +RELEASE_APK=$(find "$BASE_DIR/data/source/android" -name "app-release*.apk" -path "*/outputs/apk/*" 2>/dev/null | head -1) + +upload_apk "${DEBUG_APK:-}" "debug" +upload_apk "${RELEASE_APK:-}" "release" +UPLOAD_EOF + ) + + echo "$UPLOAD_RESULT" +} + +# --------------------------------------------------------------------------- +# --transfer: SCP APKs back to local machine +# --------------------------------------------------------------------------- +do_transfer() { + log "Downloading APKs to local machine..." + + mkdir -p "$LOCAL_OUTPUT_DIR" + + # Debug APK + DEBUG_REMOTE=$(ssh_cmd "find $BASE_DIR/data/source/android -name 'app-debug*.apk' -path '*/outputs/apk/*' 2>/dev/null | head -1" || true) + if [ -n "$DEBUG_REMOTE" ]; then + scp $SSH_OPTS "$REMOTE_HOST:$DEBUG_REMOTE" "$LOCAL_OUTPUT_DIR/wzp-debug.apk" + echo " debug: $LOCAL_OUTPUT_DIR/wzp-debug.apk ($(du -h "$LOCAL_OUTPUT_DIR/wzp-debug.apk" | cut -f1))" + fi + + # Release APK + RELEASE_REMOTE=$(ssh_cmd "find $BASE_DIR/data/source/android -name 'app-release*.apk' -path '*/outputs/apk/*' 2>/dev/null | head -1" || true) + if [ -n "$RELEASE_REMOTE" ]; then + scp $SSH_OPTS "$REMOTE_HOST:$RELEASE_REMOTE" "$LOCAL_OUTPUT_DIR/wzp-release.apk" + echo " release: $LOCAL_OUTPUT_DIR/wzp-release.apk ($(du -h "$LOCAL_OUTPUT_DIR/wzp-release.apk" | cut -f1))" + fi + + # Also grab the .so + scp $SSH_OPTS "$REMOTE_HOST:$BASE_DIR/data/source/android/app/src/main/jniLibs/arm64-v8a/libwzp_android.so" \ + "$LOCAL_OUTPUT_DIR/libwzp_android.so" 2>/dev/null \ + && echo " .so: $LOCAL_OUTPUT_DIR/libwzp_android.so" || true +} + +# --------------------------------------------------------------------------- +# Summary banner +# --------------------------------------------------------------------------- +show_summary() { + log "All done!" + echo "" + echo " ┌──────────────────────────────────────────────────────────────┐" + [ -f "$LOCAL_OUTPUT_DIR/wzp-debug.apk" ] && \ + echo " │ Debug APK: $LOCAL_OUTPUT_DIR/wzp-debug.apk" + [ -f "$LOCAL_OUTPUT_DIR/wzp-release.apk" ] && \ + echo " │ Release APK: $LOCAL_OUTPUT_DIR/wzp-release.apk" + echo " │" + if [ -n "${UPLOAD_RESULT:-}" ]; then + echo " │ Rustypaste:" + echo "$UPLOAD_RESULT" | while read -r line; do + echo " │ $line" + done + echo " │" + fi + echo " │ Install: adb install -r $LOCAL_OUTPUT_DIR/wzp-debug.apk" + echo " └──────────────────────────────────────────────────────────────┘" +} + +# --------------------------------------------------------------------------- +# Parse arguments +# --------------------------------------------------------------------------- +ACTION="" +BUILD_RELEASE=0 + +for arg in "$@"; do + case "$arg" in + --release) BUILD_RELEASE=1 ;; + --prepare|--pull|--build|--upload|--transfer|--all) + if [ -n "$ACTION" ]; then + err "Multiple actions specified: $ACTION and $arg" + exit 1 + fi + ACTION="$arg" + ;; + *) + echo "Usage: $0 [--prepare|--pull|--build|--upload|--transfer|--all] [--release]" + echo "" + echo "Actions:" + echo " (no action) Full pipeline: pull → prepare → build → upload → transfer" + echo " --prepare Build Docker image + sync keystores to remote" + echo " --pull Clone/update source from Gitea + inject keystores" + echo " --build Build debug APK inside Docker container" + echo " --upload Upload APKs to rustypaste" + echo " --transfer SCP APKs + .so back to local machine" + echo " --all pull → build → upload → transfer (Docker image ready)" + echo "" + echo "Flags:" + echo " --release Also build release APK (default: debug only)" + echo "" + echo "Examples:" + echo " $0 # full pipeline, debug only" + echo " $0 --release # full pipeline, debug + release" + echo " $0 --build # debug APK only" + echo " $0 --build --release # debug + release APKs" + echo " $0 --all # iterate: pull+build+upload+transfer (debug)" + echo " $0 --all --release # iterate with release too" + echo "" + echo "Environment:" + echo " WZP_BRANCH=$BRANCH" + exit 1 + ;; + esac +done + +# --------------------------------------------------------------------------- +# Dispatch +# --------------------------------------------------------------------------- +case "${ACTION:-}" in + --prepare) + do_prepare + ;; + --pull) + do_pull + ;; + --build) + do_build "$BUILD_RELEASE" + ;; + --upload) + do_upload + ;; + --transfer) + do_transfer + ;; + --all) + do_pull + do_build "$BUILD_RELEASE" + do_upload + do_transfer + show_summary + ;; + "") + do_pull + do_prepare + do_build "$BUILD_RELEASE" + do_upload + do_transfer + show_summary + ;; +esac