322ce8f305
Fills in the CHANGELOG.md entry for the checkpoint-anchoring security fix, fuzzing infrastructure and its findings, OP_RETURN/coinbase-tag decoding, and localization fixes since 0.9.1 (see previous commits), and bumps <Version>/versionCode across the App and Android head csproj files ahead of the tag.
237 lines
9.8 KiB
Bash
Executable File
237 lines
9.8 KiB
Bash
Executable File
#!/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 single-file binary → dist/linux/
|
|
android Android APK (release-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).
|
|
# Optional extra `docker run` args (e.g. keystore mount, signing passwords via
|
|
# -e) can be set by the caller in the EXTRA_DOCKER_ARGS array beforehand.
|
|
EXTRA_DOCKER_ARGS=()
|
|
|
|
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" \
|
|
"${EXTRA_DOCKER_ARGS[@]}" \
|
|
"$image" \
|
|
bash -euo pipefail -c "
|
|
cp -r /src/. /tmp/build
|
|
cd /tmp/build
|
|
${commands}
|
|
chown -R $(id -u):$(id -g) /output
|
|
"
|
|
}
|
|
|
|
# ── 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 \
|
|
-p:IncludeNativeLibrariesForSelfExtract=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 \
|
|
-p:PublishSingleFile=true \
|
|
-p:IncludeNativeLibrariesForSelfExtract=true \
|
|
--self-contained \
|
|
-o /tmp/linux-out
|
|
install -m 755 /tmp/linux-out/PalladiumWallet \
|
|
\"/output/PalladiumWallet-${VERSION}-linux-x64\"" \
|
|
"${DIST_DIR}/linux"
|
|
ok "Linux → dist/linux/PalladiumWallet-${VERSION}-linux-x64"
|
|
}
|
|
|
|
build_android() {
|
|
ensure_android_image
|
|
|
|
local keystore="${SCRIPT_DIR}/keystore/release.keystore"
|
|
[[ -f "$keystore" ]] || die "No release keystore found at docker/keystore/release.keystore. Run ./docker/keystore/generate-keystore.sh once first (see docker/keystore/README.md)."
|
|
|
|
info "Building Android APK …"
|
|
read -r -s -p "Keystore password: " ANDROID_KS_PASS
|
|
echo
|
|
read -r -s -p "Key password (press Enter to reuse the keystore password): " ANDROID_KEY_PASS
|
|
echo
|
|
ANDROID_KEY_PASS="${ANDROID_KEY_PASS:-$ANDROID_KS_PASS}"
|
|
|
|
# versionCode derived from <Version> (MAJOR.MINOR.PATCH, pre-release suffix
|
|
# stripped) so it always increases with releases — required for some
|
|
# installers to accept an in-place update even when the signature matches.
|
|
local semver="${VERSION%%-*}"
|
|
IFS='.' read -r VMAJOR VMINOR VPATCH <<< "$semver"
|
|
local VERSION_CODE=$(( ${VMAJOR:-0} * 10000 + ${VMINOR:-0} * 100 + ${VPATCH:-0} ))
|
|
info "versionCode: ${VERSION_CODE}"
|
|
|
|
EXTRA_DOCKER_ARGS=(
|
|
--volume "${keystore}:/keystore/release.keystore:ro"
|
|
--env "ANDROID_KS_PASS=${ANDROID_KS_PASS}"
|
|
--env "ANDROID_KEY_PASS=${ANDROID_KEY_PASS}"
|
|
)
|
|
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} \
|
|
-p:ApplicationVersion=${VERSION_CODE} \
|
|
-p:AndroidKeyStore=true \
|
|
-p:AndroidSigningKeyStore=/keystore/release.keystore \
|
|
-p:AndroidSigningKeyAlias=palladiumwallet \
|
|
-p:AndroidSigningStorePass=\${ANDROID_KS_PASS} \
|
|
-p:AndroidSigningKeyPass=\${ANDROID_KEY_PASS}
|
|
cp src/App.Android/bin/Release/net10.0-android/*-Signed.apk \
|
|
\"/output/PalladiumWallet-${VERSION}.apk\"" \
|
|
"${DIST_DIR}/android"
|
|
EXTRA_DOCKER_ARGS=()
|
|
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}/"
|