temp
This commit is contained in:
@@ -0,0 +1,37 @@
|
|||||||
|
FROM mcr.microsoft.com/dotnet/sdk:10.0
|
||||||
|
|
||||||
|
# ── Java (required by the Android SDK tools) ─────────────────────────────────
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
openjdk-17-jdk-headless \
|
||||||
|
wget \
|
||||||
|
unzip \
|
||||||
|
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
|
||||||
|
ENV ANDROID_HOME=/opt/android-sdk
|
||||||
|
ENV ANDROID_SDK_PLATFORM=34
|
||||||
|
ENV ANDROID_SDK_BUILD_TOOLS=34.0.0
|
||||||
|
|
||||||
|
# ── Android command-line tools ────────────────────────────────────────────────
|
||||||
|
# Pin the build number to a known-good release; update when Google breaks the URL.
|
||||||
|
# Latest as of 2025: commandlinetools-linux-11076708_latest.zip (cmdline-tools 12.0)
|
||||||
|
RUN mkdir -p "${ANDROID_HOME}/cmdline-tools" && \
|
||||||
|
wget -q "https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip" \
|
||||||
|
-O /tmp/cmdtools.zip && \
|
||||||
|
unzip -q /tmp/cmdtools.zip -d "${ANDROID_HOME}/cmdline-tools" && \
|
||||||
|
mv "${ANDROID_HOME}/cmdline-tools/cmdline-tools" "${ANDROID_HOME}/cmdline-tools/latest" && \
|
||||||
|
rm /tmp/cmdtools.zip
|
||||||
|
|
||||||
|
ENV PATH="${JAVA_HOME}/bin:${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools:${PATH}"
|
||||||
|
|
||||||
|
# ── Android SDK packages ──────────────────────────────────────────────────────
|
||||||
|
RUN yes | sdkmanager --licenses > /dev/null && \
|
||||||
|
sdkmanager \
|
||||||
|
"platform-tools" \
|
||||||
|
"platforms;android-${ANDROID_SDK_PLATFORM}" \
|
||||||
|
"build-tools;${ANDROID_SDK_BUILD_TOOLS}"
|
||||||
|
|
||||||
|
# ── dotnet android workload (~1 GB, baked into this layer) ───────────────────
|
||||||
|
RUN dotnet workload install android
|
||||||
|
|
||||||
|
WORKDIR /tmp/build
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
FROM mcr.microsoft.com/dotnet/sdk:10.0
|
||||||
|
|
||||||
|
# clang and zlib are required by the .NET SDK for native compilation steps
|
||||||
|
# that occur even during managed cross-publish (win-x64 / linux-x64).
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
clang \
|
||||||
|
zlib1g-dev \
|
||||||
|
libkrb5-dev \
|
||||||
|
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /tmp/build
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
# PalladiumWallet — Reproducible Builds via Docker
|
||||||
|
|
||||||
|
All three distribution targets (Windows, Linux, Android) are built inside
|
||||||
|
Docker containers so the output is identical regardless of what is installed
|
||||||
|
on the host machine.
|
||||||
|
|
||||||
|
**Prerequisites:** Docker Engine (or Docker Desktop) running on the host.
|
||||||
|
No .NET SDK, JDK, or Android SDK required on the host.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From the repository root (or the docker/ folder — both work):
|
||||||
|
./docker/build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Running without arguments shows an interactive menu. Pick a target or `all`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CLI usage
|
||||||
|
|
||||||
|
```
|
||||||
|
./docker/build.sh [TARGET] [--rebuild]
|
||||||
|
|
||||||
|
Targets:
|
||||||
|
windows Win x64 single-file executable
|
||||||
|
linux Linux x64 self-contained tarball
|
||||||
|
android Android APK (debug-signed)
|
||||||
|
all All three targets
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--rebuild Force rebuild of Docker images (needed after Dockerfile changes)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build everything
|
||||||
|
./docker/build.sh all
|
||||||
|
|
||||||
|
# Windows only
|
||||||
|
./docker/build.sh windows
|
||||||
|
|
||||||
|
# Android, forcing a fresh Docker image
|
||||||
|
./docker/build.sh android --rebuild
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
All artifacts land in `dist/` at the repository root:
|
||||||
|
|
||||||
|
| Target | Path |
|
||||||
|
|---------|--------------------------------------------------|
|
||||||
|
| Windows | `dist/windows/PalladiumWallet-{ver}-win-x64.exe` |
|
||||||
|
| Linux | `dist/linux/PalladiumWallet-{ver}-linux-x64.tar.gz` |
|
||||||
|
| Android | `dist/android/PalladiumWallet-{ver}.apk` |
|
||||||
|
|
||||||
|
The version is read automatically from `src/App/PalladiumWallet.App.csproj`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Docker images
|
||||||
|
|
||||||
|
| Image name | Dockerfile | Used for | Approx. size |
|
||||||
|
|---------------------|-----------------------|--------------------|--------------|
|
||||||
|
| `plm-build-desktop` | `Dockerfile.desktop` | windows + linux | ~1.5 GB |
|
||||||
|
| `plm-build-android` | `Dockerfile.android` | android | ~5 GB |
|
||||||
|
|
||||||
|
Images are built automatically on first use and reused on subsequent runs.
|
||||||
|
Use `--rebuild` only after you modify a Dockerfile.
|
||||||
|
|
||||||
|
### NuGet package cache
|
||||||
|
|
||||||
|
A Docker named volume `plm-nuget-cache` is created on first run and reused
|
||||||
|
for all subsequent builds, so NuGet packages are not re-downloaded every time.
|
||||||
|
|
||||||
|
To inspect or remove it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker volume inspect plm-nuget-cache
|
||||||
|
docker volume rm plm-nuget-cache # forces full re-download on next build
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Source isolation
|
||||||
|
|
||||||
|
The repository is mounted **read-only** inside every container. The build
|
||||||
|
commands work on a copy at `/tmp/build`, so `bin/`, `obj/`, and other
|
||||||
|
generated files never appear in your working tree.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Android notes
|
||||||
|
|
||||||
|
The `plm-build-android` image bakes in the entire Android SDK and the
|
||||||
|
`dotnet android workload` (~5 GB total). The first `docker build` for this
|
||||||
|
image can take 10–20 minutes depending on network speed.
|
||||||
|
|
||||||
|
The resulting APK is **debug-signed** (suitable for sideloading during
|
||||||
|
development). For Play Store distribution, release signing must be configured
|
||||||
|
separately.
|
||||||
|
|
||||||
|
If the `commandlinetools` URL in `Dockerfile.android` becomes stale (Google
|
||||||
|
rotates the build number), update the URL to the latest
|
||||||
|
[Android command-line tools](https://developer.android.com/studio#command-tools)
|
||||||
|
and run `./docker/build.sh android --rebuild`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Linux AppImage (future)
|
||||||
|
|
||||||
|
The Linux target currently produces a self-contained binary tarball. Once a
|
||||||
|
`pupnet.conf` is added to the repository, the `build_linux` function in
|
||||||
|
`build.sh` can be extended to call `dotnet pupnet --runtime linux-x64` inside
|
||||||
|
the same `plm-build-desktop` image to produce an AppImage.
|
||||||
Executable
+197
@@ -0,0 +1,197 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Reproducible build script for PalladiumWallet using Docker.
|
||||||
|
# Run from anywhere; paths are resolved relative to this script.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ── Paths ─────────────────────────────────────────────────────────────────────
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||||
|
DIST_DIR="${PROJECT_ROOT}/dist"
|
||||||
|
|
||||||
|
# ── Docker image names ────────────────────────────────────────────────────────
|
||||||
|
IMAGE_DESKTOP="plm-build-desktop"
|
||||||
|
IMAGE_ANDROID="plm-build-android"
|
||||||
|
|
||||||
|
# Named volume for NuGet package cache (shared across all builds, survives reboots).
|
||||||
|
NUGET_VOLUME="plm-nuget-cache"
|
||||||
|
|
||||||
|
# ── Helpers ───────────────────────────────────────────────────────────────────
|
||||||
|
bold() { printf '\033[1m%s\033[0m\n' "$*"; }
|
||||||
|
info() { printf '\033[1;34m>>>\033[0m %s\n' "$*"; }
|
||||||
|
ok() { printf '\033[1;32m✓\033[0m %s\n' "$*"; }
|
||||||
|
err() { printf '\033[1;31m✗\033[0m %s\n' "$*" >&2; }
|
||||||
|
die() { err "$*"; exit 1; }
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
$(bold "Usage:") $(basename "$0") [TARGET] [OPTIONS]
|
||||||
|
|
||||||
|
$(bold "Targets:")
|
||||||
|
windows Win x64 single-file executable → dist/windows/
|
||||||
|
linux Linux x64 self-contained build → dist/linux/
|
||||||
|
android Android APK (debug-signed) → dist/android/
|
||||||
|
all All three targets
|
||||||
|
|
||||||
|
$(bold "Options:")
|
||||||
|
--rebuild Force rebuild of Docker images (e.g. after Dockerfile change)
|
||||||
|
-h, --help Show this help
|
||||||
|
|
||||||
|
$(bold "Examples:")
|
||||||
|
$(basename "$0") # interactive menu
|
||||||
|
$(basename "$0") all # build everything
|
||||||
|
$(basename "$0") windows # Windows only
|
||||||
|
$(basename "$0") android --rebuild
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Argument parsing ──────────────────────────────────────────────────────────
|
||||||
|
REBUILD=false
|
||||||
|
TARGET=""
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
windows|linux|android|all) TARGET="$arg" ;;
|
||||||
|
--rebuild) REBUILD=true ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) err "Unknown argument: $arg"; usage; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# ── Interactive menu if no target given ───────────────────────────────────────
|
||||||
|
if [[ -z "$TARGET" ]]; then
|
||||||
|
bold "PalladiumWallet — reproducible build"
|
||||||
|
echo ""
|
||||||
|
PS3="Select target: "
|
||||||
|
options=("windows" "linux" "android" "all" "quit")
|
||||||
|
select opt in "${options[@]}"; do
|
||||||
|
case "$opt" in
|
||||||
|
windows|linux|android|all) TARGET="$opt"; break ;;
|
||||||
|
quit) echo "Aborted."; exit 0 ;;
|
||||||
|
*) echo "Invalid choice, try again." ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Preflight checks ──────────────────────────────────────────────────────────
|
||||||
|
command -v docker &>/dev/null || die "Docker is not installed or not in PATH."
|
||||||
|
docker info &>/dev/null || die "Docker daemon is not running."
|
||||||
|
|
||||||
|
# ── Read project version from csproj ─────────────────────────────────────────
|
||||||
|
CSPROJ="${PROJECT_ROOT}/src/App/PalladiumWallet.App.csproj"
|
||||||
|
[[ -f "$CSPROJ" ]] || die "Cannot find $CSPROJ — run this script from the repo."
|
||||||
|
VERSION=$(grep -oP '(?<=<Version>)[^<]+' "$CSPROJ") || die "Cannot extract <Version> from $CSPROJ."
|
||||||
|
info "Version: ${VERSION}"
|
||||||
|
|
||||||
|
# ── Ensure NuGet volume exists ────────────────────────────────────────────────
|
||||||
|
docker volume inspect "$NUGET_VOLUME" &>/dev/null || \
|
||||||
|
docker volume create "$NUGET_VOLUME" > /dev/null
|
||||||
|
|
||||||
|
# ── Image builders ────────────────────────────────────────────────────────────
|
||||||
|
ensure_desktop_image() {
|
||||||
|
if [[ "$REBUILD" == true ]] || ! docker image inspect "$IMAGE_DESKTOP" &>/dev/null; then
|
||||||
|
info "Building Docker image: ${IMAGE_DESKTOP}"
|
||||||
|
docker build \
|
||||||
|
--tag "$IMAGE_DESKTOP" \
|
||||||
|
--file "${SCRIPT_DIR}/Dockerfile.desktop" \
|
||||||
|
"${SCRIPT_DIR}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_android_image() {
|
||||||
|
if [[ "$REBUILD" == true ]] || ! docker image inspect "$IMAGE_ANDROID" &>/dev/null; then
|
||||||
|
info "Building Docker image: ${IMAGE_ANDROID}"
|
||||||
|
docker build \
|
||||||
|
--tag "$IMAGE_ANDROID" \
|
||||||
|
--file "${SCRIPT_DIR}/Dockerfile.android" \
|
||||||
|
"${SCRIPT_DIR}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Common docker run wrapper ─────────────────────────────────────────────────
|
||||||
|
# $1 = image name, $2 = inline bash commands to execute inside the container.
|
||||||
|
# Source is copied to /tmp/build inside the container so bin/obj never pollute
|
||||||
|
# the repo. Output is written to /output (→ host DIST_DIR sub-folder).
|
||||||
|
run_build() {
|
||||||
|
local image="$1"
|
||||||
|
local commands="$2"
|
||||||
|
local out_dir="$3"
|
||||||
|
|
||||||
|
mkdir -p "$out_dir"
|
||||||
|
|
||||||
|
docker run --rm \
|
||||||
|
--volume "${PROJECT_ROOT}:/src:ro" \
|
||||||
|
--volume "${out_dir}:/output" \
|
||||||
|
--volume "${NUGET_VOLUME}:/root/.nuget/packages" \
|
||||||
|
"$image" \
|
||||||
|
bash -euo pipefail -c "
|
||||||
|
cp -r /src/. /tmp/build
|
||||||
|
cd /tmp/build
|
||||||
|
${commands}
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Per-target build functions ────────────────────────────────────────────────
|
||||||
|
build_windows() {
|
||||||
|
ensure_desktop_image
|
||||||
|
info "Building Windows x64 …"
|
||||||
|
run_build "$IMAGE_DESKTOP" \
|
||||||
|
"dotnet publish src/App.Desktop \
|
||||||
|
-r win-x64 \
|
||||||
|
-c Release \
|
||||||
|
-p:PublishSingleFile=true \
|
||||||
|
--self-contained \
|
||||||
|
-o /tmp/win-out
|
||||||
|
cp /tmp/win-out/PalladiumWallet.exe \
|
||||||
|
\"/output/PalladiumWallet-${VERSION}-win-x64.exe\"" \
|
||||||
|
"${DIST_DIR}/windows"
|
||||||
|
ok "Windows → dist/windows/PalladiumWallet-${VERSION}-win-x64.exe"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_linux() {
|
||||||
|
ensure_desktop_image
|
||||||
|
info "Building Linux x64 …"
|
||||||
|
run_build "$IMAGE_DESKTOP" \
|
||||||
|
"dotnet publish src/App.Desktop \
|
||||||
|
-r linux-x64 \
|
||||||
|
-c Release \
|
||||||
|
--self-contained \
|
||||||
|
-o /tmp/linux-out
|
||||||
|
tar -czf \"/output/PalladiumWallet-${VERSION}-linux-x64.tar.gz\" \
|
||||||
|
-C /tmp/linux-out ." \
|
||||||
|
"${DIST_DIR}/linux"
|
||||||
|
ok "Linux → dist/linux/PalladiumWallet-${VERSION}-linux-x64.tar.gz"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_android() {
|
||||||
|
ensure_android_image
|
||||||
|
info "Building Android APK …"
|
||||||
|
run_build "$IMAGE_ANDROID" \
|
||||||
|
"JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 \
|
||||||
|
dotnet build src/App.Android \
|
||||||
|
-c Release \
|
||||||
|
-t:SignAndroidPackage \
|
||||||
|
-p:AndroidSdkDirectory=\${ANDROID_HOME}
|
||||||
|
cp src/App.Android/bin/Release/net10.0-android/*-Signed.apk \
|
||||||
|
\"/output/PalladiumWallet-${VERSION}.apk\"" \
|
||||||
|
"${DIST_DIR}/android"
|
||||||
|
ok "Android → dist/android/PalladiumWallet-${VERSION}.apk"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Dispatch ──────────────────────────────────────────────────────────────────
|
||||||
|
START=$(date +%s)
|
||||||
|
|
||||||
|
case "$TARGET" in
|
||||||
|
windows) build_windows ;;
|
||||||
|
linux) build_linux ;;
|
||||||
|
android) build_android ;;
|
||||||
|
all)
|
||||||
|
build_windows
|
||||||
|
build_linux
|
||||||
|
build_android
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
ELAPSED=$(( $(date +%s) - START ))
|
||||||
|
bold ""
|
||||||
|
bold "Done in ${ELAPSED}s. Artifacts in: ${DIST_DIR}/"
|
||||||
Reference in New Issue
Block a user