Files
jellytau/Dockerfile.builder
T
dtourolleandClaude Opus 5 50934e2ac6
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 10m7s
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 5m28s
Traceability Validation / Check Requirement Traces (push) Successful in 19s
Build & Release / Run Tests (push) Successful in 7m35s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 3m2s
Build & Release / Build Linux (push) Successful in 20m0s
Build & Release / Build Windows (push) Successful in 8m36s
Build & Release / Build Android (push) Successful in 30m30s
Build & Release / Create Release (push) Successful in 21s
ci(android): ship Gradle in the builder image instead of downloading it
The release APK job died at the Gradle wrapper step, after the 11-minute
Rust compile had already succeeded:

    Downloading https://services.gradle.org/distributions/gradle-8.14.3-bin.zip
    java.net.SocketException: Unexpected end of file from server

`tauri android init` regenerates gen/android with a wrapper pointing at
services.gradle.org, so every Android job re-downloaded ~130MB of Gradle at
build time. That is slow on a good day and a hard build failure when the CDN
drops the connection mid-transfer. It was also a standing violation of the
rule that every build tool must already live in the builder image.

Dockerfile.builder installs Gradle 8.14.3, keeping both the unpacked
distribution (on PATH) and the original zip under /opt/gradle/dist. A
`gradle --version` smoke-test fails the image build on a bad version rather
than letting CI discover it.

sync-android-sources.sh then repoints the regenerated wrapper at that local
zip, which is the established place for fixing up the generated project.
It parses the version the wrapper actually requests, so a future Tauri Gradle
bump logs "not in image, will download" instead of pointing at a missing
file. On dev machines /opt/gradle/dist does not exist and the properties file
is left untouched.

Verified by running the project's own wrapper jar inside a network namespace
with no connectivity: it resolved and unpacked the local zip to 100% and
proceeded into build-script evaluation.

Note: this is inert until the builder image is rebuilt and pushed
(scripts/build-builder-image.sh).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 07:47:43 +02:00

137 lines
5.5 KiB
Docker

# JellyTau Builder Image
# Pre-built image with all dependencies for building, testing, and packaging:
# - Android APK (SDK/NDK), Linux desktop (deb/rpm),
# - Windows cross via the official Tauri path: MSVC target + cargo-xwin + NSIS
# Arch packages build in a separate archlinux image (Dockerfile.arch) since
# makepkg is Arch-specific.
# Push to your registry: docker build -f Dockerfile.builder -t gitea.tourolle.paris/dtourolle/jellytau-builder:latest .
FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive \
ANDROID_HOME=/opt/android-sdk \
NDK_VERSION=27.0.11902837 \
SDK_VERSION=36 \
BUILD_TOOLS_VERSION=35.0.0 \
RUST_BACKTRACE=1 \
PATH="/root/.bun/bin:/root/.cargo/bin:$PATH" \
CARGO_HOME=/root/.cargo
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
curl \
wget \
git \
ca-certificates \
unzip \
jq \
openjdk-17-jdk-headless \
pkg-config \
libssl-dev \
libclang-dev \
llvm-dev \
# Tauri Linux desktop dependencies (needed for `cargo test` on the host target)
libglib2.0-dev \
libgtk-3-dev \
libwebkit2gtk-4.1-dev \
libjavascriptcoregtk-4.1-dev \
libsoup-3.0-dev \
librsvg2-dev \
libayatana-appindicator3-dev \
# mpv player library (linked via libmpv-sys)
libmpv-dev \
&& rm -rf /var/lib/apt/lists/*
# Install Node.js 20.x from NodeSource
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
apt-get install -y --no-install-recommends nodejs && \
rm -rf /var/lib/apt/lists/*
# Install Bun
RUN curl -fsSL https://bun.sh/install | bash && \
ln -s /root/.bun/bin/bun /usr/local/bin/bun
# Install Rust using rustup
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && \
. $HOME/.cargo/env && \
rustup target add aarch64-linux-android && \
rustup target add armv7-linux-androideabi && \
rustup target add x86_64-linux-android && \
rustup component add rustfmt clippy
# Setup Android SDK
RUN mkdir -p $ANDROID_HOME && \
mkdir -p /root/.android && \
echo '### User Sources for `android` cmd line tool ###' > /root/.android/repositories.cfg && \
echo 'count=0' >> /root/.android/repositories.cfg
# Download and setup Android Command Line Tools
RUN wget -q https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O /tmp/cmdline-tools.zip && \
unzip -q /tmp/cmdline-tools.zip -d $ANDROID_HOME && \
rm /tmp/cmdline-tools.zip && \
mkdir -p $ANDROID_HOME/cmdline-tools/latest && \
mv $ANDROID_HOME/cmdline-tools/* $ANDROID_HOME/cmdline-tools/latest/ 2>/dev/null || true
# Accept all SDK licenses up front so Gradle can install/use components non-interactively
RUN yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=$ANDROID_HOME --licenses > /dev/null
# Install Android SDK components (must match the compileSdk/targetSdk in the generated Gradle project)
RUN $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=$ANDROID_HOME \
"platform-tools" \
"platforms;android-$SDK_VERSION" \
"build-tools;$BUILD_TOOLS_VERSION" \
"ndk;$NDK_VERSION" \
--channel=0 2>&1 | grep -v "Warning" || true
# Set NDK environment variable
ENV NDK_HOME=$ANDROID_HOME/ndk/$NDK_VERSION
# Gradle distribution. `tauri android init` regenerates gen/android with a
# wrapper pointing at services.gradle.org, so every Android job would otherwise
# download ~130MB of Gradle at build time — slow, and a hard failure when the
# CDN hiccups ("Unexpected end of file from server"). Ship the distribution in
# the image instead; scripts/sync-android-sources.sh repoints the regenerated
# wrapper at this local copy. Keep GRADLE_VERSION in sync with the version
# Tauri's generated wrapper requests.
ENV GRADLE_VERSION=8.14.3 \
GRADLE_HOME=/opt/gradle/gradle-8.14.3
RUN mkdir -p /opt/gradle/dist && \
wget -q "https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip" \
-O "/opt/gradle/dist/gradle-${GRADLE_VERSION}-bin.zip" && \
unzip -q "/opt/gradle/dist/gradle-${GRADLE_VERSION}-bin.zip" -d /opt/gradle && \
"$GRADLE_HOME/bin/gradle" --version
ENV PATH="$GRADLE_HOME/bin:$PATH"
# ---------------------------------------------------------------------------
# Desktop packaging tools — kept in a trailing layer ON PURPOSE so that adding
# or changing a packaging tool doesn't invalidate the expensive apt/rust/Android
# layers above (a tool tweak becomes a ~1-2 min rebuild, not ~15). Covers Linux
# (deb/rpm) and Windows cross (MSVC via cargo-xwin + NSIS).
RUN apt-get update && apt-get install -y --no-install-recommends \
# Linux desktop packaging: rpmbuild for the .rpm bundle (deb needs nothing extra)
rpm \
file \
# Windows cross-compile (official Tauri path: MSVC target via cargo-xwin).
# clang provides clang-cl, the MSVC-compatible C compiler cc-rs uses to build
# C deps (bundled sqlite, ring, ...); lld = linker; llvm = llvm-lib/ar etc;
# nsis = installer generator.
clang \
lld \
llvm \
nsis \
&& rm -rf /var/lib/apt/lists/* \
# Ubuntu's clang package ships clang but NOT the clang-cl alias that cc-rs
# invokes for MSVC targets. clang-cl is the same binary in MSVC-compat mode,
# so provide it as a symlink.
&& ln -sf /usr/bin/clang /usr/local/bin/clang-cl
# Windows rust target + cargo-xwin (downloads the MSVC CRT/SDK at build time).
RUN . $HOME/.cargo/env && \
rustup target add x86_64-pc-windows-msvc && \
cargo install --locked cargo-xwin
WORKDIR /app
ENTRYPOINT ["/bin/bash"]