Compare commits
3 Commits
4d730d7860
...
ef60ec0330
| Author | SHA1 | Date | |
|---|---|---|---|
| ef60ec0330 | |||
| 567c0de501 | |||
| 6a5daa0c18 |
@@ -29,6 +29,7 @@ src/App/ shared Avalonia UI library (App, Views, ViewModels, Loc, Asset
|
|||||||
src/App.Desktop/ desktop head (WinExe): Program.cs, app.manifest, .ico → runnable
|
src/App.Desktop/ desktop head (WinExe): Program.cs, app.manifest, .ico → runnable
|
||||||
src/App.Android/ Android head (net10.0-android): MainApplication/MainActivity → apk
|
src/App.Android/ Android head (net10.0-android): MainApplication/MainActivity → apk
|
||||||
src/Cli/ CLI on the same Core tests/ xUnit
|
src/Cli/ CLI on the same Core tests/ xUnit
|
||||||
|
docker/ reproducible release builds (build.sh + pinned Dockerfiles) → dist/
|
||||||
```
|
```
|
||||||
|
|
||||||
The Avalonia UI lives **once** in `src/App` (a library); the two heads only carry the
|
The Avalonia UI lives **once** in `src/App` (a library); the two heads only carry the
|
||||||
@@ -46,8 +47,9 @@ by `MainWindow` on desktop and as the single-view root on Android.
|
|||||||
- Tests (headless, the primary verification layer): `dotnet test` — single: `dotnet test --filter "FullyQualifiedName~TestName"`; property-based tests (CsCheck, `PropertyTests.cs`) run in the same command and take ~30 s
|
- Tests (headless, the primary verification layer): `dotnet test` — single: `dotnet test --filter "FullyQualifiedName~TestName"`; property-based tests (CsCheck, `PropertyTests.cs`) run in the same command and take ~30 s
|
||||||
- GUI hot reload: `dotnet watch --project src/App.Desktop` (on WSL2/WSLg the window shows on the Windows desktop, no graphics dependencies to install)
|
- GUI hot reload: `dotnet watch --project src/App.Desktop` (on WSL2/WSLg the window shows on the Windows desktop, no graphics dependencies to install)
|
||||||
- CLI: `dotnet run --project src/Cli -- <command>` (no args → usage)
|
- CLI: `dotnet run --project src/Cli -- <command>` (no args → usage)
|
||||||
- Windows publish: `dotnet publish src/App.Desktop -r win-x64 -p:PublishSingleFile=true --self-contained`
|
- **Release binaries (all 3 targets): `./docker/build.sh [windows|linux|android|all]`** — reproducible builds in Docker (toolchain pinned in `docker/Dockerfile.*`, no SDK needed on host), artifacts in `dist/`, version taken from the App csproj. See `docker/README.md`. Gotchas already encoded there: single-file desktop publishes need `-p:IncludeNativeLibrariesForSelfExtract=true` (without it Avalonia's native libs — Skia/HarfBuzz/ANGLE — stay outside the exe, which then silently fails to start); the android workload dictates the SDK API level (error XA5207 → bump `ANDROID_SDK_PLATFORM` in `Dockerfile.android`).
|
||||||
- Linux publish: `dotnet publish src/App.Desktop -r linux-x64 --self-contained` (then AppImage via PupNet Deploy)
|
- Manual Windows publish: `dotnet publish src/App.Desktop -r win-x64 -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true --self-contained`
|
||||||
|
- Manual Linux publish: same with `-r linux-x64` (single-file binary; AppImage via PupNet Deploy is a future step, no pupnet.conf yet)
|
||||||
|
|
||||||
**Android (apk).** Needs the `android` workload (`dotnet workload install android`), a JDK
|
**Android (apk).** Needs the `android` workload (`dotnet workload install android`), a JDK
|
||||||
(`JAVA_HOME`), and the Android SDK. To provision the SDK once:
|
(`JAVA_HOME`), and the Android SDK. To provision the SDK once:
|
||||||
|
|||||||
@@ -147,6 +147,26 @@ The suite includes **property-based tests** ([CsCheck](https://github.com/Anthon
|
|||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
|
### Reproducible builds (Docker) — recommended for release binaries
|
||||||
|
|
||||||
|
All three distribution targets (Windows exe, Linux binary, Android apk) can be
|
||||||
|
built with one command inside Docker, with **no SDK installed on the host**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./docker/build.sh # interactive menu, or: ./docker/build.sh all
|
||||||
|
```
|
||||||
|
|
||||||
|
Why build this way: the whole toolchain is pinned in the Dockerfiles, so every
|
||||||
|
build uses exactly the same SDK versions regardless of the host machine — no
|
||||||
|
toolchain drift between releases — and the build environment itself is
|
||||||
|
reviewable in the repo. For a wallet this is a trust property, not a
|
||||||
|
convenience: anyone can rebuild the published binaries from source and check
|
||||||
|
they were produced by the process the repository declares.
|
||||||
|
|
||||||
|
See [docker/README.md](docker/README.md) for prerequisites, usage, how to run
|
||||||
|
each produced artifact, and troubleshooting. The sections below cover manual
|
||||||
|
builds with a locally installed SDK (the normal path during development).
|
||||||
|
|
||||||
### Development build
|
### Development build
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -162,7 +182,10 @@ dotnet build src/App.Desktop # desktop head only
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Windows — single self-contained .exe (output: src/App.Desktop/bin/Release/net10.0/win-x64/publish/PalladiumWallet.exe)
|
# Windows — single self-contained .exe (output: src/App.Desktop/bin/Release/net10.0/win-x64/publish/PalladiumWallet.exe)
|
||||||
dotnet publish src/App.Desktop -c Release -r win-x64 -p:PublishSingleFile=true --self-contained
|
# IncludeNativeLibrariesForSelfExtract embeds Avalonia's native libs (Skia, HarfBuzz, ANGLE):
|
||||||
|
# without it they stay as separate DLLs and the .exe alone silently fails to start.
|
||||||
|
dotnet publish src/App.Desktop -c Release -r win-x64 -p:PublishSingleFile=true \
|
||||||
|
-p:IncludeNativeLibrariesForSelfExtract=true --self-contained
|
||||||
|
|
||||||
# Linux — self-contained; AppImage then produced with PupNet Deploy
|
# Linux — self-contained; AppImage then produced with PupNet Deploy
|
||||||
# (output: src/App.Desktop/bin/Release/net10.0/linux-x64/publish/PalladiumWallet)
|
# (output: src/App.Desktop/bin/Release/net10.0/linux-x64/publish/PalladiumWallet)
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
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
|
||||||
|
# .NET 10 android workload compiles against API level 36 (see error XA5207
|
||||||
|
# if this drifts: the workload's Xamarin.Android.Tooling.targets dictates it).
|
||||||
|
ENV ANDROID_SDK_PLATFORM=36
|
||||||
|
ENV ANDROID_SDK_BUILD_TOOLS=36.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,183 @@
|
|||||||
|
# PalladiumWallet — Reproducible Builds via Docker
|
||||||
|
|
||||||
|
This folder builds all three distribution targets — **Windows**, **Linux**,
|
||||||
|
**Android** — inside Docker containers. The entire toolchain (.NET 10 SDK,
|
||||||
|
JDK, Android SDK, android workload) lives in the container images, pinned in
|
||||||
|
the Dockerfiles, so:
|
||||||
|
|
||||||
|
- **anyone can produce the official binaries** with a single command, on any
|
||||||
|
Linux machine, without installing any SDK on the host;
|
||||||
|
- **the toolchain never drifts**: every build uses exactly the same SDK
|
||||||
|
versions, regardless of what is installed (or updated) on the host;
|
||||||
|
- **the build environment is auditable**: the Dockerfiles in this folder are
|
||||||
|
the complete, reviewable definition of how release binaries are made — which
|
||||||
|
matters for a wallet, where users must be able to trust that the shipped
|
||||||
|
binary comes from the published source.
|
||||||
|
|
||||||
|
> **Scope note:** this pins the *build environment*. Bit-for-bit identical
|
||||||
|
> output across machines is a stronger property that .NET does not guarantee
|
||||||
|
> by default (embedded timestamps, signing); if two builds of the same commit
|
||||||
|
> differ, they differ only in those metadata, not in code.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
A Linux host (native, WSL2, or a VM) with **Docker Engine** installed and
|
||||||
|
running. Nothing else — no .NET SDK, no JDK, no Android SDK.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check that Docker works:
|
||||||
|
docker info
|
||||||
|
```
|
||||||
|
|
||||||
|
If Docker is missing, install it from <https://docs.docker.com/engine/install/>
|
||||||
|
(or `sudo apt install docker.io` on Debian/Ubuntu). If `docker info` fails
|
||||||
|
with a permission error, add yourself to the `docker` group and start a new
|
||||||
|
shell:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo usermod -aG docker $USER
|
||||||
|
```
|
||||||
|
|
||||||
|
**Disk space:** ~2 GB for the desktop image, ~7 GB for the Android image
|
||||||
|
(SDK + emulator-less toolchain). **First-run time:** the images are built
|
||||||
|
automatically on first use — a few minutes for desktop, 10–20 minutes for
|
||||||
|
Android (large downloads). Subsequent builds reuse the cached images and take
|
||||||
|
well under a minute (desktop) / a few minutes (Android).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From the repository root (or from the docker/ folder — both work):
|
||||||
|
./docker/build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Running without arguments shows an interactive menu — pick a single target or
|
||||||
|
`all`. Non-interactive usage:
|
||||||
|
|
||||||
|
```
|
||||||
|
./docker/build.sh [TARGET] [--rebuild]
|
||||||
|
|
||||||
|
Targets:
|
||||||
|
windows Win x64 single-file executable (native libs embedded)
|
||||||
|
linux Linux x64 single-file binary (runs as-is, nothing to install)
|
||||||
|
android Android APK (debug-signed)
|
||||||
|
all All three targets
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--rebuild Force rebuild of the Docker images (needed after editing a Dockerfile)
|
||||||
|
```
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./docker/build.sh all # build everything
|
||||||
|
./docker/build.sh windows # Windows only
|
||||||
|
./docker/build.sh android --rebuild # Android, rebuilding the image first
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Output — and how to use each artifact
|
||||||
|
|
||||||
|
All artifacts land in `dist/` at the repository root. The version number is
|
||||||
|
read automatically from `<Version>` in `src/App/PalladiumWallet.App.csproj`.
|
||||||
|
|
||||||
|
| Target | Path |
|
||||||
|
|---------|--------------------------------------------------|
|
||||||
|
| Windows | `dist/windows/PalladiumWallet-{ver}-win-x64.exe` |
|
||||||
|
| Linux | `dist/linux/PalladiumWallet-{ver}-linux-x64` |
|
||||||
|
| Android | `dist/android/PalladiumWallet-{ver}.apk` |
|
||||||
|
|
||||||
|
**Windows** — a single self-contained `.exe` (runtime and native libraries
|
||||||
|
embedded). Copy it to any 64-bit Windows 10/11 machine and double-click.
|
||||||
|
The first launch takes a few extra seconds (it unpacks native libraries to a
|
||||||
|
per-user cache); later launches are normal. SmartScreen may warn because the
|
||||||
|
binary is not code-signed — choose "Run anyway".
|
||||||
|
|
||||||
|
**Linux** — a single self-contained binary, already executable. Copy and run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./PalladiumWallet-{ver}-linux-x64
|
||||||
|
```
|
||||||
|
|
||||||
|
Works on any desktop distro with glibc, X11/Wayland and fontconfig (i.e.
|
||||||
|
effectively all of them); no .NET or other packages to install. If you
|
||||||
|
transfer it through a channel that strips permissions (e.g. a web download),
|
||||||
|
restore the execute bit with `chmod +x`.
|
||||||
|
|
||||||
|
**Android** — a debug-signed APK for sideloading: transfer it to the phone
|
||||||
|
and open it (enable "install from unknown sources" if prompted), or install
|
||||||
|
via `adb install dist/android/PalladiumWallet-*.apk`. Supports Android 6.0+
|
||||||
|
(API 23), arm64 phones and x86_64 emulators.
|
||||||
|
|
||||||
|
> **Signature caveat:** debug-signed APKs built on different machines carry
|
||||||
|
> different keys. If a previous build is already installed, Android refuses
|
||||||
|
> the update (`INSTALL_FAILED_UPDATE_INCOMPATIBLE`) — uninstall the old app
|
||||||
|
> first. **Uninstalling deletes the app's data: back up the wallet seed
|
||||||
|
> before doing this.** Release signing with a stable key is not set up yet.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
### Docker images
|
||||||
|
|
||||||
|
| Image | Dockerfile | Used for | Size |
|
||||||
|
|---------------------|----------------------|-----------------|---------|
|
||||||
|
| `plm-build-desktop` | `Dockerfile.desktop` | windows + linux | ~1.5 GB |
|
||||||
|
| `plm-build-android` | `Dockerfile.android` | android | ~5 GB |
|
||||||
|
|
||||||
|
Images are built automatically the first time a target needs them and reused
|
||||||
|
afterwards. Use `--rebuild` only after modifying a Dockerfile.
|
||||||
|
|
||||||
|
### Source isolation
|
||||||
|
|
||||||
|
The repository is mounted **read-only** inside the container; the build works
|
||||||
|
on a copy at `/tmp/build`. Your working tree is never touched — no stray
|
||||||
|
`bin/`/`obj/` directories, and a dirty working tree doesn't leak into the
|
||||||
|
build beyond the files it contains. Artifacts are written back through a
|
||||||
|
bind mount to `dist/` and chown'd to your user.
|
||||||
|
|
||||||
|
### NuGet cache
|
||||||
|
|
||||||
|
A Docker named volume `plm-nuget-cache` holds downloaded NuGet packages
|
||||||
|
across builds. To reclaim the space or force a clean re-download:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker volume rm plm-nuget-cache
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
- **`Docker daemon is not running`** — start it (`sudo systemctl start
|
||||||
|
docker`; on WSL2, start Docker Desktop or the docker service).
|
||||||
|
- **Android image build fails downloading `commandlinetools`** — Google
|
||||||
|
rotates the build number in the URL. Update the URL in
|
||||||
|
`Dockerfile.android` to the current one from
|
||||||
|
<https://developer.android.com/studio#command-tools> and rerun with
|
||||||
|
`--rebuild`.
|
||||||
|
- **`error XA5207: Could not find android.jar for API level N`** — the .NET
|
||||||
|
android workload moved to a newer API level. Bump
|
||||||
|
`ANDROID_SDK_PLATFORM` (and `ANDROID_SDK_BUILD_TOOLS`) in
|
||||||
|
`Dockerfile.android` to the level the error names, then `--rebuild`.
|
||||||
|
- **APK won't install over an existing app** — signature mismatch between
|
||||||
|
debug keys; see the signature caveat above.
|
||||||
|
- **Everything is broken / start from scratch** —
|
||||||
|
`docker system prune -a && docker volume rm plm-nuget-cache`, then rerun
|
||||||
|
the script (images and packages are re-downloaded).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Linux AppImage (future)
|
||||||
|
|
||||||
|
The Linux target currently produces a single-file self-contained binary.
|
||||||
|
Once a `pupnet.conf` is added to the repository, the `build_linux` function
|
||||||
|
in `build.sh` can be extended to call PupNet Deploy inside the same
|
||||||
|
`plm-build-desktop` image to also produce an AppImage with desktop
|
||||||
|
integration (icon, menu entry).
|
||||||
Executable
+201
@@ -0,0 +1,201 @@
|
|||||||
|
#!/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 (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}
|
||||||
|
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
|
||||||
|
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}/"
|
||||||
@@ -54,12 +54,12 @@ public sealed class Loc
|
|||||||
["menu.help"] = ["_Help", "_Help", "_Ayuda", "_Aide", "_Ajuda", "_Hilfe"],
|
["menu.help"] = ["_Help", "_Help", "_Ayuda", "_Aide", "_Ajuda", "_Hilfe"],
|
||||||
["help.title"] = ["Informazioni", "About", "Información", "À propos", "Sobre", "Über"],
|
["help.title"] = ["Informazioni", "About", "Información", "À propos", "Sobre", "Über"],
|
||||||
["help.info"] = [
|
["help.info"] = [
|
||||||
"Wallet SPV per la criptovaluta Palladium (PLM).",
|
"Wallet SPV leggero e non-custodiale per la rete Palladium (PLM). Sicurezza locale: seed e chiavi sempre cifrati, mai esposti in rete.",
|
||||||
"SPV wallet for the Palladium (PLM) cryptocurrency.",
|
"Lightweight, non-custodial SPV wallet for the Palladium (PLM) network. Local security: seed and keys always encrypted, never exposed on the wire.",
|
||||||
"Monedero SPV para la criptomoneda Palladium (PLM).",
|
"Monedero SPV ligero y sin custodia para la red Palladium (PLM). Seguridad local: semilla y claves siempre cifradas, nunca expuestas en la red.",
|
||||||
"Portefeuille SPV pour la cryptomonnaie Palladium (PLM).",
|
"Portefeuille SPV léger et non-custodial pour le réseau Palladium (PLM). Sécurité locale : graine et clés toujours chiffrées, jamais exposées sur le réseau.",
|
||||||
"Carteira SPV para a criptomoeda Palladium (PLM).",
|
"Carteira SPV leve e não custodial para a rede Palladium (PLM). Segurança local: semente e chaves sempre cifradas, nunca expostas na rede.",
|
||||||
"SPV-Wallet für die Kryptowährung Palladium (PLM)."],
|
"Leichtes, nicht-verwahrendes SPV-Wallet für das Palladium (PLM)-Netzwerk. Lokale Sicherheit: Seed und Schlüssel stets verschlüsselt, nie im Netzwerk exponiert."],
|
||||||
["help.tab.info"] = ["Info", "Info", "Info", "Info", "Info", "Info"],
|
["help.tab.info"] = ["Info", "Info", "Info", "Info", "Info", "Info"],
|
||||||
["help.tab.donate"] = ["Dona", "Donate", "Donar", "Faire un don", "Doar", "Spenden"],
|
["help.tab.donate"] = ["Dona", "Donate", "Donar", "Faire un don", "Doar", "Spenden"],
|
||||||
["help.bug.report"] = ["Segnala un bug", "Report a bug", "Informar un error", "Signaler un bug", "Reportar um bug", "Fehler melden"],
|
["help.bug.report"] = ["Segnala un bug", "Report a bug", "Informar un error", "Signaler un bug", "Reportar um bug", "Fehler melden"],
|
||||||
|
|||||||
Reference in New Issue
Block a user