Files
PalladiumWallet/docker/build.sh
T

198 lines
8.0 KiB
Bash
Raw Normal View History

2026-06-24 16:15:57 +02:00
#!/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}/"