chore: migrate to hosted scalable CI (#3620)
What changed, and why it matters
This commit is an infrastructure change: Cake Wallet moved its automated build system from GitHub's standard runners to a third-party hosted service ('puzl-ubuntu-latest') and split the build into many smaller parallel jobs. It also adds a hard-coded developer test certificate and private key for CI builds. There is no direct change to the wallet's user-facing code, cryptography, or network behavior. The main security concern is that the new CI provider and the committed test signing material could, in theory, be misused if secrets or build outputs leak, but the commit itself does not introduce a known vulnerability in the app.
Treat this as a routine CI migration. Verify that the `puzl-ubuntu-latest` runner is from a trusted provider and that its images are hardened. Confirm the committed `dev-test-key.*` files are used only for debug/CI artifacts and are not referenced by release builds. Review repository branch protection rules so the removal of automatic integration-test runs on PRs does not bypass required checks. Rotate or remove the test key material if there is any chance it could be confused with production signing keys.
Security signals we found
Third-party CI runner label `puzl-ubuntu-latest` replaces GitHub-managed `ubuntu-24.04`
Committed RSA private key and self-signed certificate (`scripts/android/dev-test-key.pem`, `scripts/android/dev-test-key.crt`) used only for debug/CI keystores
CI jobs now log in to GHCR using `secrets.GITHUB_TOKEN` and run Docker with broad socket permissions (`sudo chmod 666 /var/run/docker.sock`)
Integration tests no longer run automatically on pull requests
No changes to wallet source, network code, encryption, or release signing keys
Evidence from the diff
The diff is a CI/CD refactor. Workflows switch from ubuntu-24.04 to puzl-ubuntu-latest, add concurrency controls, decompose monolithic Android/Linux builds into parallel Docker-based jobs, and introduce --only, --target, --coin, --merge, and --extract modes in scripts/android/docker/build.sh and scripts/linux/docker/build.sh. A new scripts/android/dev-test-key.crt and dev-test-key.pem are committed, plus generate_dev_keystore.sh to create a debug JKS from them. The integration test workflow is changed from pull_request trigger to workflow_dispatch only. No application source code, dependency versions, or cryptographic protocols are modified.
Changed components
.github/workflows/are_translations_sane.yml.github/workflows/compare_overrides.yml.github/workflows/integration_tests.yml.github/workflows/no_http_imports.yaml.github/workflows/no_print_in_dart.yaml.github/workflows/no_restricted_imports.yaml.github/workflows/pr_test_build_android.yml.github/workflows/pr_test_build_linux.yml.github/workflows/reusable-build.yml.github/workflows/reusable-integration-test.ymlscripts/android/build_monero_all.shscripts/android/dev-test-key.crtscripts/android/dev-test-key.pemscripts/android/docker/Dockerfile.decredscripts/android/docker/Dockerfile.moneroscripts/android/docker/Dockerfile.torchscripts/android/docker/build.shscripts/android/generate_dev_keystore.shscripts/linux/build_monero_all.shscripts/linux/build_torch.shscripts/linux/docker/Dockerfile.moneroscripts/linux/docker/Dockerfile.torchscripts/linux/docker/build.shInspect captured patch +1306 / −234
### .github/workflows/are_translations_sane.yml
@@ -4,7 +4,7 @@ on: [pull_request]
jobs:
PR_test_build:
- runs-on: ubuntu-24.04
+ runs-on: puzl-ubuntu-latest
steps:
- uses: actions/checkout@v4
### .github/workflows/compare_overrides.yml
@@ -10,7 +10,7 @@ permissions:
jobs:
compare-overrides:
- runs-on: ubuntu-24.04
+ runs-on: puzl-ubuntu-latest
steps:
- uses: actions/checkout@v4
### .github/workflows/integration_tests.yml
@@ -5,11 +5,6 @@ permissions:
packages: write
on:
- pull_request:
- branches: [dev]
- paths-ignore:
- - "**.md"
- - "docs/**"
workflow_dispatch:
concurrency:
### .github/workflows/no_http_imports.yaml
@@ -4,7 +4,7 @@ on: [pull_request]
jobs:
PR_test_build:
- runs-on: ubuntu-24.04
+ runs-on: puzl-ubuntu-latest
steps:
- uses: actions/checkout@v4
### .github/workflows/no_print_in_dart.yaml
@@ -4,7 +4,7 @@ on: [pull_request]
jobs:
PR_test_build:
- runs-on: ubuntu-24.04
+ runs-on: puzl-ubuntu-latest
steps:
- uses: actions/checkout@v4
### .github/workflows/no_restricted_imports.yaml
@@ -4,7 +4,7 @@ on: [pull_request]
jobs:
check_restricted_imports:
- runs-on: ubuntu-24.04
+ runs-on: puzl-ubuntu-latest
steps:
- uses: actions/checkout@v4
### .github/workflows/pr_test_build_android.yml
@@ -7,6 +7,10 @@ permissions:
contents: read
packages: write
+concurrency:
+ group: android-${{ github.event.pull_request.number }}
+ cancel-in-progress: true
+
jobs:
# -----------------------------------------
# PATH A: Internal PRs
### .github/workflows/pr_test_build_linux.yml
@@ -10,44 +10,242 @@ defaults:
run:
shell: bash
+env:
+ CW_DOCKER_REGISTRY: ghcr.io/cake-tech/cake_wallet
+ CW_DOCKER_USE_CLOUD: "true"
+
+concurrency:
+ group: linux-${{ github.event.pull_request.number }}
+ cancel-in-progress: true
+
jobs:
- PR_test_build:
+ guard:
# Fork PRs don't have access to repository secrets, so the generated
# lib/.secrets.g.dart would be empty and the build fails to compile.
# Skip for forks, mirroring the Android workflow's internal-build guard.
if: github.event.pull_request.head.repo.fork == false
- runs-on: [Linux, amd64, forlinux]
+ runs-on: puzl-ubuntu-latest
+ steps:
+ - run: echo "internal PR"
+
+ base:
+ needs: guard
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ repository: ${{ github.event.pull_request.head.repo.full_name }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build base
+ run: ./scripts/linux/docker/build.sh --only base
+
+ bitbox:
+ needs: base
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ repository: ${{ github.event.pull_request.head.repo.full_name }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build bitbox
+ run: ./scripts/linux/docker/build.sh --only bitbox
+
+ mwebd:
+ needs: base
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ repository: ${{ github.event.pull_request.head.repo.full_name }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build mwebd
+ run: ./scripts/linux/docker/build.sh --only mwebd
+
+ reown:
+ needs: base
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ repository: ${{ github.event.pull_request.head.repo.full_name }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build reown
+ run: ./scripts/linux/docker/build.sh --only reown
+
+ zcash:
+ needs: base
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ repository: ${{ github.event.pull_request.head.repo.full_name }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build zcash
+ run: ./scripts/linux/docker/build.sh --only zcash
+
+ torch:
+ needs: base
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ repository: ${{ github.event.pull_request.head.repo.full_name }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build torch
+ run: ./scripts/linux/docker/build.sh --only torch
+
+ monero:
+ needs: base
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ strategy:
+ matrix:
+ coin: [monero, wownero]
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ repository: ${{ github.event.pull_request.head.repo.full_name }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build monero
+ run: ./scripts/linux/docker/build.sh --only monero --coin ${{ matrix.coin }} --target x86_64-linux-gnu
+
+ monero_merge:
+ needs: monero
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ repository: ${{ github.event.pull_request.head.repo.full_name }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Merge monero
+ run: ./scripts/linux/docker/build.sh --only monero --merge
+
+ final:
+ needs: [bitbox, mwebd, reown, zcash, torch, monero_merge]
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ repository: ${{ github.event.pull_request.head.repo.full_name }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build final
+ run: ./scripts/linux/docker/build.sh --only final
+
+ app:
+ needs: final
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
container:
image: ghcr.io/cake-tech/cake_wallet:debian13-flutter3.41.9-ndkr28-go1.24.1-ruststablenightly
env:
STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet
- MONEROC_CACHE_DIR_ROOT: /opt/generic_cache
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
+ DESKTOP_FORCE_MOBILE: Y
volumes:
- - /opt/cw_cache_linux/root/.cache:/root/.cache
- - /opt/cw_cache_linux/root/.ccache:/root/.ccache
- - /opt/cw_cache_linux/root/.pub-cache/:/root/.pub-cache
- - /opt/cw_cache_linux/root/go/pkg:/root/go/pkg
- - /opt/cw_cache_linux/opt/generic_cache:/opt/generic_cache
- /var/run/docker.sock:/var/run/docker.sock
-
steps:
- name: Fix github actions messing up $HOME...
run: "echo HOME=/root | sudo tee -a $GITHUB_ENV"
- - name: Log in to GitHub Container Registry
- uses: docker/login-action@v3
- with:
- registry: ghcr.io
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
@@ -88,12 +286,8 @@ jobs:
echo "${{ secrets.MAIN_SECRETS_FILE }}" | base64 --decode > lib/.secrets.g.dart
- - name: Build dependencies utilizing ghcr cache
- run: |
- env \
- CW_DOCKER_REGISTRY=ghcr.io/cake-tech/cake_wallet \
- CW_DOCKER_USE_CLOUD=true \
- ./scripts/linux/docker/build.sh
+ - name: Extract native dependencies
+ run: ./scripts/linux/docker/build.sh --extract
- name: Execute Build and Setup Commands
run: |
@@ -134,7 +328,6 @@ jobs:
path: ${{ github.workspace }}/build/linux/x64/release/cakewallet_linux.zip
name: cakewallet_linux
- # Integration tests moved to integration_tests.yml
- name: Test [cw_core]
timeout-minutes: 15
run: cd cw_core && flutter test
### .github/workflows/reusable-build.yml
@@ -17,33 +17,276 @@ on:
defaults:
run:
shell: bash
+
+env:
+ CW_DOCKER_REGISTRY: ghcr.io/cake-tech/cake_wallet
+ CW_DOCKER_USE_CLOUD: "true"
+
jobs:
- PR_test_build:
- runs-on: [Linux, amd64, android]
+ base:
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ inputs.ref }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build base
+ run: ./scripts/android/docker/build.sh --only base
+
+ bitbox:
+ needs: base
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ inputs.ref }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build bitbox
+ run: ./scripts/android/docker/build.sh --only bitbox
+
+ mwebd:
+ needs: base
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ inputs.ref }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build mwebd
+ run: ./scripts/android/docker/build.sh --only mwebd
+
+ reown:
+ needs: base
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ inputs.ref }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build reown
+ run: ./scripts/android/docker/build.sh --only reown
+
+ zcash:
+ needs: base
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ inputs.ref }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build zcash
+ run: ./scripts/android/docker/build.sh --only zcash
+
+ torch:
+ needs: base
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ strategy:
+ matrix:
+ target:
+ - aarch64-linux-android
+ - armv7a-linux-androideabi
+ - x86_64-linux-android
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ inputs.ref }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build torch
+ run: ./scripts/android/docker/build.sh --only torch --target ${{ matrix.target }}
+
+ torch_merge:
+ needs: torch
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ inputs.ref }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Merge torch
+ run: ./scripts/android/docker/build.sh --only torch --merge
+
+ monero:
+ needs: base
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ strategy:
+ matrix:
+ coin: [monero, wownero, zano]
+ target:
+ - aarch64-linux-android
+ - armv7a-linux-androideabi
+ - x86_64-linux-android
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ inputs.ref }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build monero
+ run: ./scripts/android/docker/build.sh --only monero --coin ${{ matrix.coin }} --target ${{ matrix.target }}
+
+ monero_merge:
+ needs: monero
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ inputs.ref }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Merge monero
+ run: ./scripts/android/docker/build.sh --only monero --merge
+
+ decred:
+ needs: [base, torch_merge]
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ inputs.ref }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build decred
+ run: ./scripts/android/docker/build.sh --only decred
+
+ final:
+ needs: [bitbox, mwebd, reown, zcash, torch_merge, monero_merge, decred]
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
+ steps:
+ - uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
+ with:
+ ref: ${{ inputs.ref }}
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
+ - name: Log in to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Build final
+ run: ./scripts/android/docker/build.sh --only final
+
+ integration-test:
+ needs: final
+ uses: ./.github/workflows/reusable-integration-test.yml
+ with:
+ ref: ${{ inputs.ref }}
+ suite_dir: integration_test/suites
+ test_tier: tier0
+ slack_notify: true
+ extract_only: true
+ secrets: inherit
+
+ app:
+ needs: final
+ runs-on: puzl-ubuntu-latest
+ timeout-minutes: 360
container:
image: ghcr.io/cake-tech/cake_wallet:debian13-flutter3.41.9-ndkr28-go1.24.1-ruststablenightly
env:
STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet
- MONEROC_CACHE_DIR_ROOT: /opt/generic_cache
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
volumes:
- - /opt/cw_cache_android/root/.cache:/root/.cache
- - /opt/cw_cache_android/root/.ccache:/root/.ccache
- - /opt/cw_cache_android/root/.pub-cache/:/root/.pub-cache
- - /opt/cw_cache_android/root/.gradle/:/root/.gradle
- - /opt/cw_cache_android/root/.android/:/root/.android
- - /opt/cw_cache_android/root/go/pkg:/root/go/pkg
- - /opt/cw_cache_android/opt/generic_cache:/opt/generic_cache
- /var/run/docker.sock:/var/run/docker.sock
-
steps:
- name: Fix github actions messing up $HOME...
run: "echo HOME=/root | sudo tee -a $GITHUB_ENV"
- uses: actions/checkout@v4
+ if: ${{ env.ACT != 'true' }}
with:
ref: ${{ inputs.ref }}
-
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
@@ -88,22 +331,10 @@ jobs:
- name: Generate KeyStore
run: |
- pushd /opt/generic_cache
- if [[ ! -f key.jks ]];
- then
- keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass $STORE_PASS -keypass $KEY_PASS
- else
- echo "$PWD/key.jks exist, not generating"
- fi
- popd
- cp /opt/generic_cache/key.jks android/app
+ ./scripts/android/generate_dev_keystore.sh android/app/key.jks
- - name: Build dependencies utilizing ghcr cache
- run: |
- env \
- CW_DOCKER_REGISTRY=ghcr.io/cake-tech/cake_wallet \
- CW_DOCKER_USE_CLOUD=true \
- ./scripts/android/docker/build.sh
+ - name: Extract native dependencies
+ run: ./scripts/android/docker/build.sh --extract
- name: Execute Build and Setup Commands
run: |
@@ -121,7 +352,6 @@ jobs:
run: |
./model_generator.sh
-
- name: Generate key properties
run: |
dart run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS
### .github/workflows/reusable-integration-test.yml
@@ -42,6 +42,10 @@ on:
required: false
type: boolean
default: false
+ extract_only:
+ required: false
+ type: boolean
+ default: false
defaults:
run:
@@ -61,24 +65,33 @@ jobs:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref }}
+ - name: Authenticate git for package clones
+ run: |
+ git config --global --unset-all credential.helper || true
+ git config --global url."https://x-access-token:${{ github.token }}@github.com/".insteadOf "https://github.com/"
- name: Free disk space
run: |
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/.ghcup /usr/local/lib/node_modules /opt/hostedtoolcache/CodeQL
sudo rm -rf /usr/share/swift /usr/local/share/powershell /usr/share/miniconda /opt/az /usr/local/graalvm
sudo docker image prune -af > /dev/null
df -h /
-
- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
+ sudo chmod 666 /dev/kvm || true
if [[ ! -c /dev/kvm ]]; then
echo "::error::/dev/kvm is not a character device, this runner has no usable KVM"
exit 1
fi
+ - name: Install protobuf compiler
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y protobuf-compiler
+
- uses: actions/setup-java@v4
with:
distribution: temurin
@@ -121,9 +134,8 @@ jobs:
key: pub-cache-${{ runner.os }}-${{ hashFiles('pubspec_base.yaml', 'cw_*/pubspec.yaml') }}
restore-keys: pub-cache-${{ runner.os }}-
- - name: Add rust android targets
- run: |
- rustup target add x86_64-linux-android aarch64-linux-android armv7-linux-androideabi i686-linux-android
+ - name: Docker sock permissions
+ run: sudo chmod 666 /var/run/docker.sock || true
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
@@ -165,44 +177,26 @@ jobs:
echo "${{ secrets.FUNDS_SECRETS_FILE }}" | base64 --decode > integration_test/core/funded_wallets.dart
- name: Build dependencies utilizing ghcr cache
+ if: ${{ !inputs.extract_only }}
run: |
env \
CW_DOCKER_REGISTRY=ghcr.io/cake-tech/cake_wallet \
CW_DOCKER_USE_CLOUD=true \
./scripts/android/docker/build.sh
+ - name: Extract native dependencies
+ if: ${{ inputs.extract_only }}
+ run: |
+ env \
+ CW_DOCKER_REGISTRY=ghcr.io/cake-tech/cake_wallet \
+ CW_DOCKER_USE_CLOUD=true \
+ ./scripts/android/docker/build.sh --extract
+
- name: Reclaim the space the dependency images took
run: |
docker system prune -af --volumes > /dev/null
df -h /
- - name: Regenerate mweb bindings
- run: |
- git checkout -- cw_mweb/pubspec.yaml
- rm -f cw_mweb/pubspec.lock
- rm -rf cw_mweb/.dart_tool
-
- # Hosted runners ship libclang, only install when it is actually missing
- if ! ldconfig -p | grep -q libclang; then
- sudo apt-get install -y --no-install-recommends libclang-dev > /dev/null
- fi
-
- if ! command -v protoc > /dev/null ||
- [[ ! -f /usr/include/google/protobuf/descriptor.proto ]]; then
- sudo apt-get install -y --no-install-recommends protobuf-compiler libprotobuf-dev > /dev/null
- fi
-
- pushd cw_mweb
- flutter pub get
- dart run ffigen --config ffigen_config.yaml
- popd
-
- # Fail here in seconds rather than minutes into the gradle build
- if ! grep -q "final class GoSlice" cw_mweb/lib/generated_bindings.g.dart; then
- echo "::error::mweb bindings regenerated without class modifiers, ffigen resolved too old"
- exit 1
- fi
-
- name: Execute Build and Setup Commands
run: |
pushd scripts/android
### scripts/android/build_monero_all.sh
@@ -9,11 +9,23 @@ cd "$(dirname "$0")"
../prepare_moneroc.sh
-for COIN in monero wownero zano;
+if [[ -n "${COIN:-}" ]]; then
+ COINS=("$COIN")
+else
+ COINS=(monero wownero zano)
+fi
+
+if [[ -n "${TARGET:-}" ]]; then
+ TARGETS=("$TARGET")
+else
+ TARGETS=(x86_64-linux-android aarch64-linux-android armv7a-linux-androideabi)
+fi
+
+for COIN in "${COINS[@]}";
do
pushd ../monero_c
monero_c_tag=$(git describe --tags)
- for target in {x86_64,aarch64}-linux-android armv7a-linux-androideabi
+ for target in "${TARGETS[@]}"
do
if [[ -f "release/${monero_c_tag}/${target}/${COIN}_libwallet2_api_c.so" ]];
then
### scripts/android/dev-test-key.crt
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIUO9LtTFYNTLeRJ0Vs/BoW/RHanY4wDQYJKoZIhvcNAQEL
+BQAwcDELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0FtZXJpY2ExEDAOBgNVBAcMB0Zs
+b3JpZGExEzARBgNVBAoMCkNha2VXYWxsZXQxEzARBgNVBAsMCkNha2VXYWxsZXQx
+EzARBgNVBAMMCkNha2VXYWxsZXQwIBcNMjYwOTEwMDgwMzU5WhgPMjA1NDAxMjYw
+ODAzNTlaMHAxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdBbWVyaWNhMRAwDgYDVQQH
+DAdGbG9yaWRhMRMwEQYDVQQKDApDYWtlV2FsbGV0MRMwEQYDVQQLDApDYWtlV2Fs
+bGV0MRMwEQYDVQQDDApDYWtlV2FsbGV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAlHYehgoK7D3/ga26LlYMQhVqyokmUZQ9E6+S2utKQixTwHlJsAe7
+IWY0TpUhz1iDSq8XG/IQdnos8o/SEHY8EVO+STzOjbYIk4J6mm6jqZa59y+l2Brk
+4IEZYe8HsIjMBFmbn8WlLhhT9PewcMZxutW3D0+swx+8azpfYHBY/5a6PaKAstey
+HKSejD7atfcI7xZbWzzPGwS0hDjAcqGcfyYH/r2ziIbvEU2xDeOBYBm9yE1B6sEn
+dI2KB2Q5HtKfNV8Vw1vSLvFEIAJh/vmuO7RoW+tPdUfORTydCeNvDIK8DGe1ka8/
+ZmQraNgGgTxA5YpJKZsTYgc5eMWyxIHBlwIDAQABo1MwUTAdBgNVHQ4EFgQUSTWY
+iEWvKz3YwrB0bufUbxcZ2YgwHwYDVR0jBBgwFoAUSTWYiEWvKz3YwrB0bufUbxcZ
+2YgwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAZ+21ksy5plnb
+ZCTYifmk8E8M+sGWS2m5eLTjzAl4iEEr30Eit4ghQvt7YG5r62HLHBFirv4z6k01
+5mhjU+BJp0NU1e8XOVq6M0EnMKF8OIz3lUy4aUnr6olCdEbSsRyd0l7Ht21Ci0HH
+BkFbZ+HlqwXTPA5kUWMkJ0JlrMhaeyRMpA0jsE1fhgjWmrB2keeFP8CwA3GnQhq1
+HEkN6izdaobnUHnTE7dH3Eixkt0L4XwpkCsw7IV3aVt7+tsc0zICod8JS0ib4Lrw
+XHVWIRtcTGwDLqYlknacR0Mh7JeDYU3JtfxvCB7jstDI9CmYnPOiAsO4NccnbzD5
+WIbD9bRlYg==
+-----END CERTIFICATE-----
### scripts/android/dev-test-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCUdh6GCgrsPf+B
+rbouVgxCFWrKiSZRlD0Tr5La60pCLFPAeUmwB7shZjROlSHPWINKrxcb8hB2eizy
+j9IQdjwRU75JPM6NtgiTgnqabqOplrn3L6XYGuTggRlh7wewiMwEWZufxaUuGFP0
+97BwxnG61bcPT6zDH7xrOl9gcFj/lro9ooCy17IcpJ6MPtq19wjvFltbPM8bBLSE
+OMByoZx/Jgf+vbOIhu8RTbEN44FgGb3ITUHqwSd0jYoHZDke0p81XxXDW9Iu8UQg
+AmH++a47tGhb6091R85FPJ0J428MgrwMZ7WRrz9mZCto2AaBPEDlikkpmxNiBzl4
+xbLEgcGXAgMBAAECggEAILrz2sg/BTtb58qVx95noHAZVaKsBINCfeMQ5NvHyNP9
++OqkgL8Llf7y3DpLtGtGssHsPdh9oako3KcxgDiY4JcOVhYmUZ7GwEKdZgurYFmf
+ESx7iyvOtuIvZuRsVRKrq+/Xe/92fbWWWOT8jLhrXW39iE4f//qwrxE08s2CCYLq
+zQFUIrICN6/7te+qTessWO4Z2zscqhzTMae2kWksUMiU0mYv9BJ6Lzb1Mj2kqSir
+CMBxmxvQmjmE4+29rKulmAQlKNb+rwKgsmdk5+oYcCdMHP0VeXL8RZ+IcOkOv4JU
+xj+isHr8S9mmGMmpM5aAnZoS7tF3aLDH4aojN6MNfQKBgQDQ44cB+SDoKujnfMsK
+1ci21HB2R7qobbspJVGHNQx25XYJdAw1CTsnN8FwziXGR8/tpSJMHQin0M7ZLHqn
+u/aTZLT+7VAmFNUOOY4mbBrQzTA21r2l0kMloXyqmO6ec820L+9bqeAZ6N4y1iNt
+iQ8yVYOuS1SMi+QfqerxbXwg4wKBgQC18byTn58edwprsqWs48u7hB/zI3SLoXOn
+qHPke9uCo4ynV6yEmLa/yN9iyXL2UjY7KjzbpFLhrFYE5JxXfCfCgOk3N1nF8953
+2K95/3uFrasbRSRDi2ROVmDYD1stqN+euHfx3N15uZ/E/Ol8e7GhBMIWo9WIyqJ7
+3GiU9ce+vQKBgDmTfVL96CQWL7wemZiS9I/wXk871ic2l6/vqVkrNhRPiwlwAy1b
+LgLRS3BcYe0VPiqyqZFxL0GSPHF/4Q76sCxQRdM+dikI9PDGzHeqtHl5FSEIb52V
+JwzoRgR/wsXKBZj03XTWjf6WQSih/YHjlVy6VWFlQhi7NlXD8A47r0shAoGAX+Pj
+qzn5NqkuiMxCnPgBq/ZakF4jUmPo/He/fK/6ZMOloZyHg+qohjNr6Dibqk5x3oTI
+Rko4lE+rljCWZVU97zjZsQwu+DErEqbU9Ms9YprBD0JFdoPEfbTwnW6ac1oJYTF/
+pazt3PWDyuIwfDcEywQi9qOqKsoBEJ59T+SpPVECgYBzT9XnT01Eh5MGYxoC/8cu
+c19gWNqHNnvTeUYNI6y8+bUSSbP3vJ8Bytb0VuBega5QQYrT9EYILJIVu9oKSHJE
+v5rSGMmM9hNbWmROGEad/afO82AilvfOR0fx6Tmyk3Sf3tg3JltA3tAzPgo/BOlc
+GqVhDf37ULi8YBLGLkNOZA==
+-----END PRIVATE KEY-----
### scripts/android/docker/Dockerfile.decred
@@ -10,6 +10,7 @@ RUN mkdir -p /w/cw_decred/lib/api
COPY --from=torch_source /w/scripts/torch_dart /w/scripts/torch_dart
COPY cw_core/pubspec.yaml /w/cw_core/pubspec.yaml
COPY cw_decred/pubspec.yaml /w/cw_decred/pubspec.yaml
+COPY pubspec_overrides.yaml /w/cw_decred/pubspec_overrides.yaml
COPY scripts/android/build_decred.sh /w/scripts/android/build_decred.sh
RUN /w/scripts/android/build_decred.sh
### scripts/android/docker/Dockerfile.monero
@@ -2,8 +2,13 @@ ARG BASE_IMAGE
FROM --platform=linux/amd64 ${BASE_IMAGE} AS build
RUN mkdir -p /w/scripts/android
+COPY scripts/functions.sh /w/scripts/functions.sh
COPY scripts/prepare_moneroc.sh /w/scripts/prepare_moneroc.sh
COPY scripts/android/build_monero_all.sh /w/scripts/android/build_monero_all.sh
+ARG COIN
+ARG TARGET
+ENV COIN=$COIN
+ENV TARGET=$TARGET
RUN /w/scripts/android/build_monero_all.sh \
&& rm -rf /w/scripts/monero_c/contrib \
/w/scripts/monero_c/.git \
### scripts/android/docker/Dockerfile.torch
@@ -13,7 +13,13 @@ RUN groupadd -g "$GID" "$USER" && \
RUN sudo chown $UID:$GID -R /w /root
USER builder
-RUN /w/scripts/android/build_torch.sh && rm -rf /w/scripts/torch_dart/simplybs
+ARG TARGET
+RUN if [ -n "$TARGET" ]; then \
+ /w/scripts/android/build_torch.sh "$TARGET"; \
+ else \
+ /w/scripts/android/build_torch.sh; \
+ fi \
+ && rm -rf /w/scripts/torch_dart/simplybs
FROM --platform=linux/amd64 alpine
COPY --from=build /w /w
### scripts/android/docker/build.sh
@@ -4,116 +4,387 @@ cd "$(dirname $0)"
CW_DOCKER_REGISTRY="${CW_DOCKER_REGISTRY:-localhost/cake-tech/cake_wallet}"
CW_DOCKER_USE_CLOUD="${CW_DOCKER_USE_CLOUD:-}"
+IMAGE_PREFIX="android-deps"
SCRIPT_DIR="$(pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
+ONLY=""
+TARGET=""
+COIN=""
+MERGE=false
+EXTRACT=false
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --only)
+ ONLY="$2"
+ shift 2
+ ;;
+ --target)
+ TARGET="$2"
+ shift 2
+ ;;
+ --coin)
+ COIN="$2"
+ shift 2
+ ;;
+ --merge)
+ MERGE=true
+ shift
+ ;;
+ --extract)
+ EXTRACT=true
+ shift
+ ;;
+ -h|--help)
+ echo "Usage: $0 [--only NAME] [--target TRIPLE] [--coin COIN] [--merge] [--extract]"
+ exit 0
+ ;;
+ *)
+ echo "Unknown argument: $1" >&2
+ exit 1
+ ;;
+ esac
+done
+
+TORCH_TARGETS=(
+ aarch64-linux-android
+ armv7a-linux-androideabi
+ x86_64-linux-android
+)
+MONERO_COINS=(monero wownero zano)
+MONERO_TARGETS=(
+ aarch64-linux-android
+ armv7a-linux-androideabi
+ x86_64-linux-android
+)
+
image_exists() {
docker image inspect "$1" &>/dev/null
}
tinysha() {
- cat "$@" | sha256sum | cut -c1-6
+ cat "$@" | sha256sum | cut -c1-6
+}
+
+slice_extra() {
+ if [[ -n "$COIN" && -n "$TARGET" ]]; then
+ echo "-${COIN}-${TARGET}"
+ elif [[ -n "$TARGET" ]]; then
+ echo "-${TARGET}"
+ else
+ echo ""
+ fi
+}
+
+# Distinct from the unsuffixed all-in-one tag. The hash of slice suffixes
+# invalidates the merge image if a coin or target is added or removed.
+assembled_extra() {
+ local tmp
+ tmp="$(mktemp)"
+ printf '%s\n' "$@" > "$tmp"
+ echo "-merged-$(tinysha "$tmp")"
+ rm -f "$tmp"
+}
+
+torch_assembled_extra() {
+ local extras=()
+ local t
+ for t in "${TORCH_TARGETS[@]}"; do
+ extras+=("-$t")
+ done
+ assembled_extra "${extras[@]}"
+}
+
+monero_assembled_extra() {
+ local extras=()
+ local coin t
+ for coin in "${MONERO_COINS[@]}"; do
+ for t in "${MONERO_TARGETS[@]}"; do
+ extras+=("-${coin}-${t}")
+ done
+ done
+ assembled_extra "${extras[@]}"
+}
+
+component_extra() {
+ local name="$1"
+ local sliced
+ sliced="$(slice_extra)"
+ if [[ -n "$sliced" ]]; then
+ echo "$sliced"
+ return
+ fi
+ case "$name" in
+ torch) torch_assembled_extra ;;
+ monero) monero_assembled_extra ;;
+ *) echo "" ;;
+ esac
+}
+
+img() {
+ local name="$1"
+ local version="$2"
+ local extra="${3:-}"
+ echo "$CW_DOCKER_REGISTRY:${IMAGE_PREFIX}-${name}-$(tinysha "$SCRIPT_DIR/Dockerfile.${name}")-${version}${extra}"
+}
+
+remote_exists() {
+ local tag="$1"
+ if docker buildx version >/dev/null 2>&1; then
+ docker buildx imagetools inspect "$tag" >/dev/null 2>&1
+ return
+ fi
+ DOCKER_CLI_EXPERIMENTAL=enabled docker manifest inspect "$tag" >/dev/null 2>&1
+}
+
+cached() {
+ local tag="$1"
+ if image_exists "$tag"; then
+ return 0
+ fi
+ if [[ "x$CW_DOCKER_USE_CLOUD" == "xtrue" ]] && remote_exists "$tag"; then
+ return 0
+ fi
+ return 1
+}
+
+maybe_push() {
+ local tag="$1"
+ if [[ "x$CW_DOCKER_USE_CLOUD" == "xtrue" ]]; then
+ docker push "$tag"
+ fi
}
build() {
local name="$1"; shift
local version=$1; shift
- if [[ "x$CW_DOCKER_USE_CLOUD" == "xtrue" ]]
- then
- set +e
- docker images --format "{{.Repository}}:{{.Tag}} {{.ID}}" | \
- grep "^${CW_DOCKER_REGISTRY}:android-deps-" | \
- awk '{print $2}' | \
- xargs -r docker rmi
- docker pull "$CW_DOCKER_REGISTRY:android-deps-${name}-$(tinysha "$SCRIPT_DIR/Dockerfile.${name}")-${version}"
- set -e
- fi
- if image_exists "$CW_DOCKER_REGISTRY:android-deps-${name}-$(tinysha "$SCRIPT_DIR/Dockerfile.${name}")-${version}"; then
- echo "==> skipping $name (image already exists)"
+ local extra
+ extra="$(component_extra "$name")"
+ local tag
+ tag="$(img "$name" "$version" "$extra")"
+ if cached "$tag"; then
+ echo "==> skipping $name (cached: $tag)"
return 0
fi
- echo "==> building $name"
+ echo "==> building $name${extra}"
docker build \
--platform linux/amd64 \
--file "$SCRIPT_DIR/Dockerfile.${name}" \
- --tag "$CW_DOCKER_REGISTRY:android-deps-${name}-$(tinysha "$SCRIPT_DIR/Dockerfile.${name}")-${version}" \
+ --tag "$tag" \
"$@" \
"$REPO_ROOT"
- if [[ "x$CW_DOCKER_USE_CLOUD" == "xtrue" ]]
- then
- docker push "$CW_DOCKER_REGISTRY:android-deps-${name}-$(tinysha "$SCRIPT_DIR/Dockerfile.${name}")-${version}"
- fi
+ maybe_push "$tag"
}
-img() {
- echo "$CW_DOCKER_REGISTRY:android-deps-${1}-$(tinysha "$SCRIPT_DIR/Dockerfile.${1}")-${2}"
+merge_slices() {
+ local name="$1"
+ local version="$2"
+ local extra="$3"
+ shift 3
+ local dest
+ dest="$(img "$name" "$version" "$extra")"
+ if cached "$dest"; then
+ echo "==> skipping merge $name (cached: $dest)"
+ return 0
+ fi
+
+ local slices=("$@")
+ if [[ ${#slices[@]} -eq 0 ]]; then
+ echo "merge_slices: no slice images given" >&2
+ exit 1
+ fi
+
+ local dockerfile
+ dockerfile="$(mktemp)"
+ local build_args=()
+ local i=0
+ for slice in "${slices[@]}"; do
+ echo "ARG SRC${i}" >> "$dockerfile"
+ i=$((i + 1))
+ done
+ i=0
+ for slice in "${slices[@]}"; do
+ if ! cached "$slice"; then
+ echo "merge_slices: missing slice $slice" >&2
+ rm -f "$dockerfile"
+ exit 1
+ fi
+ echo "FROM --platform=linux/amd64 \${SRC${i}} AS s${i}" >> "$dockerfile"
+ build_args+=(--build-arg "SRC${i}=$slice")
+ i=$((i + 1))
+ done
+ echo "FROM --platform=linux/amd64 alpine" >> "$dockerfile"
+ i=0
+ for slice in "${slices[@]}"; do
+ echo "COPY --from=s${i} /w /w" >> "$dockerfile"
+ i=$((i + 1))
+ done
+
+ echo "==> merging $name from ${#slices[@]} slices -> $dest"
+ docker build \
+ --platform linux/amd64 \
+ --file "$dockerfile" \
+ --tag "$dest" \
+ "${build_args[@]}" \
+ "$SCRIPT_DIR"
+ rm -f "$dockerfile"
+ maybe_push "$dest"
}
base_ver="latest"
torch_ver="$(tinysha $SCRIPT_DIR/Dockerfile.torch $REPO_ROOT/scripts/prepare_torch.sh $REPO_ROOT/scripts/android/build_torch.sh)"
reown_ver=$(tinysha $SCRIPT_DIR/Dockerfile.reown $REPO_ROOT/scripts/prepare_reown.sh $REPO_ROOT/scripts/android/build_reown_deps.sh)
bitbox_ver=$(tinysha $SCRIPT_DIR/Dockerfile.bitbox $REPO_ROOT/scripts/build_bitbox_flutter.sh)
monero_ver=$(tinysha $SCRIPT_DIR/Dockerfile.monero $REPO_ROOT/scripts/prepare_moneroc.sh $REPO_ROOT/scripts/android/build_monero_all.sh)
-mwebd_ver=$(tinysha $SCRIPT_DIR/Dockerfile.mwebd $REPO_ROOT/pubspec_overrides.yaml $(find $REPO_ROOT/cw_mweb/go -type f))
+mwebd_ver=$(tinysha $SCRIPT_DIR/Dockerfile.mwebd $REPO_ROOT/pubspec_overrides.yaml $(find $REPO_ROOT/cw_mweb/go -type f | sort))
zcash_ver=$(tinysha $SCRIPT_DIR/Dockerfile.zcash $REPO_ROOT/scripts/prepare_zcash.sh $REPO_ROOT/scripts/android/build_zcash.sh)
-decred_ver=$(tinysha $SCRIPT_DIR/Dockerfile.torch $SCRIPT_DIR/Dockerfile.decred $REPO_ROOT/scripts/android/build_decred.sh $REPO_ROOT/cw_decred/pubspec.yaml)
-echo $base_ver $torch_ver $reown_ver $bitbox_ver $monero_ver $mwebd_ver $zcash_ver $decred_ver > /tmp/docker_build_versions
+torch_assembled_extra > /tmp/cw_torch_assembled_extra
+decred_ver=$(tinysha $SCRIPT_DIR/Dockerfile.torch $SCRIPT_DIR/Dockerfile.decred $REPO_ROOT/scripts/android/build_decred.sh $REPO_ROOT/cw_decred/pubspec.yaml $REPO_ROOT/pubspec_overrides.yaml /tmp/cw_torch_assembled_extra)
+echo $base_ver $torch_ver $reown_ver $bitbox_ver $monero_ver $mwebd_ver $zcash_ver $decred_ver "$(torch_assembled_extra)" "$(monero_assembled_extra)" > /tmp/docker_build_versions
final_ver=$(tinysha /tmp/docker_build_versions)
-docker create --name temp_extract $(img final $final_ver) \
-&& cd $REPO_ROOT \
-&& docker cp temp_extract:/w.top w.top \
-&& rsync -av w.top/ . \
-&& rm -rf w.top \
-&& docker rm temp_extract \
-&& echo "cache ok" \
-&& exit 0 \
-|| echo "cache miss oh"
-
-docker rm temp_extract || true
+extract_final() {
+ local required="${1:-}"
+ local tag
+ tag="$(img final "$final_ver")"
+ if ! image_exists "$tag" && [[ "x$CW_DOCKER_USE_CLOUD" == "xtrue" ]] && remote_exists "$tag"; then
+ docker pull "$tag"
+ fi
+ docker rm -f temp_extract >/dev/null 2>&1 || true
+ if docker create --name temp_extract "$tag"; then
+ cd "$REPO_ROOT"
+ docker cp temp_extract:/w.top w.top
+ rsync -av w.top/ .
+ rm -rf w.top
+ docker rm temp_extract
+ echo "cache ok"
+ echo "$tag" > /tmp/cakewallet_docker
+ return 0
+ fi
+ docker rm -f temp_extract >/dev/null 2>&1 || true
+ echo "cache miss oh"
+ if [[ "$required" == "required" ]]; then
+ echo "final image missing: $tag" >&2
+ exit 1
+ fi
+ return 1
+}
-build base "$base_ver"
+build_base() {
+ build base "$base_ver"
+}
-build bitbox "$bitbox_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+build_bitbox() {
+ build bitbox "$bitbox_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+}
-build mwebd "$mwebd_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+build_mwebd() {
+ build mwebd "$mwebd_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+}
-build reown "$reown_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+build_reown() {
+ build reown "$reown_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+}
-build monero "$monero_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+build_zcash() {
+ build zcash "$zcash_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+}
-build zcash "$zcash_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+build_torch() {
+ if [[ "$MERGE" == true ]]; then
+ local slices=()
+ local t
+ for t in "${TORCH_TARGETS[@]}"; do
+ slices+=("$(img torch "$torch_ver" "-$t")")
+ done
+ merge_slices torch "$torch_ver" "$(torch_assembled_extra)" "${slices[@]}"
+ return 0
+ fi
+ build torch "$torch_ver" \
+ --build-arg BASE_IMAGE="$(img base "$base_ver")" \
+ --build-arg TARGET="${TARGET}"
+}
-build torch "$torch_ver" \
- --build-arg BASE_IMAGE="$(img base "$base_ver")"
+build_monero() {
+ if [[ "$MERGE" == true ]]; then
+ local slices=()
+ local coin t
+ for coin in "${MONERO_COINS[@]}"; do
+ for t in "${MONERO_TARGETS[@]}"; do
+ slices+=("$(img monero "$monero_ver" "-${coin}-${t}")")
+ done
+ done
+ merge_slices monero "$monero_ver" "$(monero_assembled_extra)" "${slices[@]}"
+ return 0
+ fi
+ build monero "$monero_ver" \
+ --build-arg BASE_IMAGE="$(img base "$base_ver")" \
+ --build-arg COIN="${COIN}" \
+ --build-arg TARGET="${TARGET}"
+}
-build decred "$decred_ver" \
- --build-arg BASE_IMAGE="$(img base "$base_ver")" \
- --build-arg TORCH_IMAGE="$(img torch "$torch_ver")"
+build_decred() {
+ build decred "$decred_ver" \
+ --build-arg BASE_IMAGE="$(img base "$base_ver")" \
+ --build-arg TORCH_IMAGE="$(img torch "$torch_ver" "$(torch_assembled_extra)")"
+}
-build final $final_ver \
- --build-arg BASE_IMAGE="$(img base $base_ver)" \
- --build-arg TORCH_IMAGE="$(img torch $torch_ver)" \
- --build-arg REOWN_IMAGE="$(img reown $reown_ver)" \
- --build-arg BITBOX_IMAGE="$(img bitbox $bitbox_ver)" \
- --build-arg MONERO_IMAGE="$(img monero $monero_ver)" \
- --build-arg DECRED_IMAGE="$(img decred $decred_ver)" \
- --build-arg MWEBD_IMAGE="$(img mwebd $mwebd_ver)" \
- --build-arg ZCASH_IMAGE="$(img zcash $zcash_ver)"
+build_final() {
+ build final "$final_ver" \
+ --build-arg BASE_IMAGE="$(img base "$base_ver")" \
+ --build-arg TORCH_IMAGE="$(img torch "$torch_ver" "$(torch_assembled_extra)")" \
+ --build-arg REOWN_IMAGE="$(img reown "$reown_ver")" \
+ --build-arg BITBOX_IMAGE="$(img bitbox "$bitbox_ver")" \
+ --build-arg MONERO_IMAGE="$(img monero "$monero_ver" "$(monero_assembled_extra)")" \
+ --build-arg DECRED_IMAGE="$(img decred "$decred_ver")" \
+ --build-arg MWEBD_IMAGE="$(img mwebd "$mwebd_ver")" \
+ --build-arg ZCASH_IMAGE="$(img zcash "$zcash_ver")"
+ echo "done: $(img final $final_ver)"
+ echo "$(img final $final_ver)" > /tmp/cakewallet_docker
+}
-echo "done: $(img final $final_ver)"
-echo $(img final $final_ver) > /tmp/cakewallet_docker
+run_one() {
+ case "$1" in
+ base) build_base ;;
+ bitbox) build_bitbox ;;
+ mwebd) build_mwebd ;;
+ reown) build_reown ;;
+ zcash) build_zcash ;;
+ torch) build_torch ;;
+ monero) build_monero ;;
+ decred) build_decred ;;
+ final) build_final ;;
+ *)
+ echo "Unknown component: $1" >&2
+ exit 1
+ ;;
+ esac
+}
+if [[ "$EXTRACT" == true ]]; then
+ extract_final required
+ exit 0
+fi
-docker create --name temp_extract $(img final $final_ver) \
-&& cd $REPO_ROOT \
-&& docker cp temp_extract:/w.top w.top \
-&& rsync -av w.top/ . \
-&& rm -rf w.top \
-&& docker rm temp_extract \
-&& echo "cache ok" \
-&& exit 0
+if [[ -z "$ONLY" ]]; then
+ extract_final && exit 0 || true
+ ONLY=""
+ TARGET=""
+ COIN=""
+ MERGE=false
+ build_base
+ build_bitbox
+ build_mwebd
+ build_reown
+ build_monero
+ build_zcash
+ build_torch
+ build_decred
+ build_final
+ extract_final required
+ exit 0
+fi
-echo idk.
-exit 1
+run_one "$ONLY"
### scripts/android/generate_dev_keystore.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+set -euo pipefail
+
+cd "$(dirname "$0")"
+
+STORE_PASS="${STORE_PASS:-test@cake_wallet}"
+KEY_PASS="${KEY_PASS:-test@cake_wallet}"
+DEST="${1:-}"
+
+if [[ -z "$DEST" ]]; then
+ DEST="$(cd ../.. && pwd)/android/app/key.jks"
+elif [[ "$DEST" != /* ]]; then
+ DEST="$(cd ../.. && pwd)/$DEST"
+fi
+
+P12="$(mktemp /tmp/cakewallet-dev-XXXXXX.p12)"
+cleanup() { rm -f "$P12"; }
+trap cleanup EXIT
+
+openssl pkcs12 -export \
+ -inkey "$PWD/dev-test-key.pem" \
+ -in "$PWD/dev-test-key.crt" \
+ -out "$P12" \
+ -name testKey \
+ -passout "pass:${STORE_PASS}" \
+ -certpbe PBE-SHA1-3DES \
+ -keypbe PBE-SHA1-3DES \
+ -macalg sha1
+
+mkdir -p "$(dirname "$DEST")"
+rm -f "$DEST"
+
+keytool -importkeystore \
+ -srckeystore "$P12" \
+ -srcstoretype PKCS12 \
+ -srcstorepass "$STORE_PASS" \
+ -destkeystore "$DEST" \
+ -deststoretype JKS \
+ -deststorepass "$STORE_PASS" \
+ -destkeypass "$KEY_PASS" \
+ -srcalias testKey \
+ -destalias testKey \
+ -noprompt
+
+echo "Wrote $DEST"
### scripts/linux/build_monero_all.sh
@@ -7,16 +7,23 @@ cd "$(dirname "$0")"
../prepare_moneroc.sh
-for COIN in monero wownero;
+if [[ -n "${COIN:-}" ]]; then
+ COINS=("$COIN")
+else
+ COINS=(monero wownero)
+fi
+
+if [[ -n "${TARGET:-}" ]]; then
+ target="$TARGET"
+elif [[ $(uname -m) == "arm64" || $(uname -m) == "aarch64" ]]; then
+ target="aarch64-linux-gnu"
+else
+ target="x86_64-linux-gnu"
+fi
+
+for COIN in "${COINS[@]}";
do
pushd ../monero_c
- # Determine target architecture based on system architecture
- if [[ $(uname -m) == "arm64" || $(uname -m) == "aarch64" ]]; then
- target="aarch64-linux-gnu"
- else
- target="x86_64-linux-gnu"
- fi
-
./build_single.sh ${COIN} $target -j$MAKE_JOB_COUNT
popd
done
### scripts/linux/build_torch.sh
@@ -2,8 +2,18 @@
set -x -e
cd "$(dirname "$0")"
+DEFAULT_TARGETS=(
+ "x86_64-linux-gnu"
+)
+
+if [ "$#" -gt 0 ]; then
+ TARGETS=("$@")
+else
+ TARGETS=("${DEFAULT_TARGETS[@]}")
+fi
+
../prepare_torch.sh
cd ../torch_dart
-./build.sh x86_64-linux-gnu
+./build.sh "${TARGETS[@]}"
### scripts/linux/docker/Dockerfile.monero
@@ -13,6 +13,10 @@ RUN mkdir -p /w/scripts/linux
COPY scripts/prepare_moneroc.sh /w/scripts/prepare_moneroc.sh
COPY scripts/linux/build_monero_all.sh /w/scripts/linux/build_monero_all.sh
COPY scripts/functions.sh /w/scripts/functions.sh
+ARG COIN
+ARG TARGET
+ENV COIN=$COIN
+ENV TARGET=$TARGET
RUN /w/scripts/linux/build_monero_all.sh \
&& rm -rf /w/scripts/monero_c/contrib/depends/simplybs \
/w/scripts/monero_c/monero_libwallet2_api_c/build \
### scripts/linux/docker/Dockerfile.torch
@@ -14,7 +14,13 @@ RUN groupadd -g "$GID" "$USER" && \
RUN sudo chown $UID:$GID -R /w /root
USER builder
-RUN /w/scripts/linux/build_torch.sh && rm -rf /w/scripts/torch_dart/simplybs
+ARG TARGET
+RUN if [ -n "$TARGET" ]; then \
+ /w/scripts/linux/build_torch.sh "$TARGET"; \
+ else \
+ /w/scripts/linux/build_torch.sh; \
+ fi \
+ && rm -rf /w/scripts/torch_dart/simplybs
FROM --platform=linux/amd64 alpine
COPY --from=build /w /w
### scripts/linux/docker/build.sh
@@ -4,110 +4,348 @@ cd "$(dirname $0)"
CW_DOCKER_REGISTRY="${CW_DOCKER_REGISTRY:-localhost/cake-tech/cake_wallet}"
CW_DOCKER_USE_CLOUD="${CW_DOCKER_USE_CLOUD:-}"
+IMAGE_PREFIX="linux-deps-amd64"
SCRIPT_DIR="$(pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
+ONLY=""
+TARGET=""
+COIN=""
+MERGE=false
+EXTRACT=false
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --only)
+ ONLY="$2"
+ shift 2
+ ;;
+ --target)
+ TARGET="$2"
+ shift 2
+ ;;
+ --coin)
+ COIN="$2"
+ shift 2
+ ;;
+ --merge)
+ MERGE=true
+ shift
+ ;;
+ --extract)
+ EXTRACT=true
+ shift
+ ;;
+ -h|--help)
+ echo "Usage: $0 [--only NAME] [--target TRIPLE] [--coin COIN] [--merge] [--extract]"
+ exit 0
+ ;;
+ *)
+ echo "Unknown argument: $1" >&2
+ exit 1
+ ;;
+ esac
+done
+
+MONERO_COINS=(monero wownero)
+MONERO_TARGETS=(x86_64-linux-gnu)
+
image_exists() {
docker image inspect "$1" &>/dev/null
}
tinysha() {
- cat "$@" | sha256sum | cut -c1-6
+ cat "$@" | sha256sum | cut -c1-6
+}
+
+slice_extra() {
+ if [[ -n "$COIN" && -n "$TARGET" ]]; then
+ echo "-${COIN}-${TARGET}"
+ elif [[ -n "$TARGET" ]]; then
+ echo "-${TARGET}"
+ else
+ echo ""
+ fi
+}
+
+# Distinct from the unsuffixed all-in-one tag. The hash of slice suffixes
+# invalidates the merge image if a coin or target is added or removed.
+assembled_extra() {
+ local tmp
+ tmp="$(mktemp)"
+ printf '%s\n' "$@" > "$tmp"
+ echo "-merged-$(tinysha "$tmp")"
+ rm -f "$tmp"
+}
+
+monero_assembled_extra() {
+ local extras=()
+ local coin t
+ for coin in "${MONERO_COINS[@]}"; do
+ for t in "${MONERO_TARGETS[@]}"; do
+ extras+=("-${coin}-${t}")
+ done
+ done
+ assembled_extra "${extras[@]}"
+}
+
+component_extra() {
+ local name="$1"
+ local sliced
+ sliced="$(slice_extra)"
+ if [[ -n "$sliced" ]]; then
+ echo "$sliced"
+ return
+ fi
+ case "$name" in
+ monero) monero_assembled_extra ;;
+ *) echo "" ;;
+ esac
+}
+
+img() {
+ local name="$1"
+ local version="$2"
+ local extra="${3:-}"
+ echo "$CW_DOCKER_REGISTRY:${IMAGE_PREFIX}-${name}-$(tinysha "$SCRIPT_DIR/Dockerfile.${name}")-${version}${extra}"
+}
+
+remote_exists() {
+ local tag="$1"
+ if docker buildx version >/dev/null 2>&1; then
+ docker buildx imagetools inspect "$tag" >/dev/null 2>&1
+ return
+ fi
+ DOCKER_CLI_EXPERIMENTAL=enabled docker manifest inspect "$tag" >/dev/null 2>&1
+}
+
+cached() {
+ local tag="$1"
+ if image_exists "$tag"; then
+ return 0
+ fi
+ if [[ "x$CW_DOCKER_USE_CLOUD" == "xtrue" ]] && remote_exists "$tag"; then
+ return 0
+ fi
+ return 1
+}
+
+maybe_push() {
+ local tag="$1"
+ if [[ "x$CW_DOCKER_USE_CLOUD" == "xtrue" ]]; then
+ docker push "$tag"
+ fi
}
build() {
local name="$1"; shift
local version=$1; shift
- if [[ "x$CW_DOCKER_USE_CLOUD" == "xtrue" ]]
- then
- set +e
- docker images --format "{{.Repository}}:{{.Tag}} {{.ID}}" | \
- grep "^${CW_DOCKER_REGISTRY}:linux-deps-amd64-" | \
- awk '{print $2}' | \
- xargs -r docker rmi
- docker pull "$CW_DOCKER_REGISTRY:linux-deps-amd64-${name}-$(tinysha "$SCRIPT_DIR/Dockerfile.${name}")-${version}"
- set -e
- fi
- if image_exists "$CW_DOCKER_REGISTRY:linux-deps-amd64-${name}-$(tinysha "$SCRIPT_DIR/Dockerfile.${name}")-${version}"; then
- echo "==> skipping $name (image already exists)"
+ local extra
+ extra="$(component_extra "$name")"
+ local tag
+ tag="$(img "$name" "$version" "$extra")"
+ if cached "$tag"; then
+ echo "==> skipping $name (cached: $tag)"
return 0
fi
- echo "==> building $name"
+ echo "==> building $name${extra}"
docker build \
--platform linux/amd64 \
--file "$SCRIPT_DIR/Dockerfile.${name}" \
- --tag "$CW_DOCKER_REGISTRY:linux-deps-amd64-${name}-$(tinysha "$SCRIPT_DIR/Dockerfile.${name}")-${version}" \
+ --tag "$tag" \
"$@" \
"$REPO_ROOT"
- if [[ "x$CW_DOCKER_USE_CLOUD" == "xtrue" ]]
- then
- docker push "$CW_DOCKER_REGISTRY:linux-deps-amd64-${name}-$(tinysha "$SCRIPT_DIR/Dockerfile.${name}")-${version}"
- fi
+ maybe_push "$tag"
}
-img() {
- echo "$CW_DOCKER_REGISTRY:linux-deps-amd64-${1}-$(tinysha "$SCRIPT_DIR/Dockerfile.${1}")-${2}"
+merge_slices() {
+ local name="$1"
+ local version="$2"
+ local extra="$3"
+ shift 3
+ local dest
+ dest="$(img "$name" "$version" "$extra")"
+ if cached "$dest"; then
+ echo "==> skipping merge $name (cached: $dest)"
+ return 0
+ fi
+
+ local slices=("$@")
+ if [[ ${#slices[@]} -eq 0 ]]; then
+ echo "merge_slices: no slice images given" >&2
+ exit 1
+ fi
+
+ local dockerfile
+ dockerfile="$(mktemp)"
+ local build_args=()
+ local i=0
+ for slice in "${slices[@]}"; do
+ echo "ARG SRC${i}" >> "$dockerfile"
+ i=$((i + 1))
+ done
+ i=0
+ for slice in "${slices[@]}"; do
+ if ! cached "$slice"; then
+ echo "merge_slices: missing slice $slice" >&2
+ rm -f "$dockerfile"
+ exit 1
+ fi
+ echo "FROM --platform=linux/amd64 \${SRC${i}} AS s${i}" >> "$dockerfile"
+ build_args+=(--build-arg "SRC${i}=$slice")
+ i=$((i + 1))
+ done
+ echo "FROM --platform=linux/amd64 alpine" >> "$dockerfile"
+ i=0
+ for slice in "${slices[@]}"; do
+ echo "COPY --from=s${i} /w /w" >> "$dockerfile"
+ i=$((i + 1))
+ done
+
+ echo "==> merging $name from ${#slices[@]} slices -> $dest"
+ docker build \
+ --platform linux/amd64 \
+ --file "$dockerfile" \
+ --tag "$dest" \
+ "${build_args[@]}" \
+ "$SCRIPT_DIR"
+ rm -f "$dockerfile"
+ maybe_push "$dest"
}
base_ver="latest"
torch_ver="$(tinysha $SCRIPT_DIR/Dockerfile.torch $REPO_ROOT/scripts/prepare_torch.sh $REPO_ROOT/scripts/linux/build_torch.sh)"
reown_ver=$(tinysha $SCRIPT_DIR/Dockerfile.reown $REPO_ROOT/scripts/prepare_reown.sh $REPO_ROOT/scripts/android/build_reown_deps.sh)
bitbox_ver=$(tinysha $SCRIPT_DIR/Dockerfile.bitbox $REPO_ROOT/scripts/build_bitbox_flutter.sh)
monero_ver=$(tinysha $SCRIPT_DIR/Dockerfile.monero $REPO_ROOT/scripts/prepare_moneroc.sh $REPO_ROOT/scripts/linux/build_monero_all.sh)
-mwebd_ver=$(tinysha $SCRIPT_DIR/Dockerfile.mwebd $REPO_ROOT/pubspec_overrides.yaml $(find $REPO_ROOT/cw_mweb/go -type f))
+mwebd_ver=$(tinysha $SCRIPT_DIR/Dockerfile.mwebd $REPO_ROOT/pubspec_overrides.yaml $(find $REPO_ROOT/cw_mweb/go -type f | sort))
zcash_ver=$(tinysha $SCRIPT_DIR/Dockerfile.zcash $REPO_ROOT/scripts/prepare_zcash.sh $REPO_ROOT/scripts/linux/build_zcash.sh)
-echo $base_ver $torch_ver $reown_ver $bitbox_ver $monero_ver $mwebd_ver $zcash_ver > /tmp/docker_build_versions
+echo $base_ver $torch_ver $reown_ver $bitbox_ver $monero_ver $mwebd_ver $zcash_ver "$(monero_assembled_extra)" > /tmp/docker_build_versions
final_ver=$(tinysha /tmp/docker_build_versions)
-docker create --name temp_extract $(img final $final_ver) \
-&& cd $REPO_ROOT \
-&& docker cp temp_extract:/w.top w.top \
-&& rsync -av w.top/ . \
-&& rm -rf w.top \
-&& docker rm temp_extract \
-&& echo "cache ok" \
-&& exit 0 \
-|| echo "cache miss oh"
-
-docker rm temp_extract || true
+extract_final() {
+ local required="${1:-}"
+ local tag
+ tag="$(img final "$final_ver")"
+ if ! image_exists "$tag" && [[ "x$CW_DOCKER_USE_CLOUD" == "xtrue" ]] && remote_exists "$tag"; then
+ docker pull "$tag"
+ fi
+ docker rm -f temp_extract >/dev/null 2>&1 || true
+ if docker create --name temp_extract "$tag"; then
+ cd "$REPO_ROOT"
+ docker cp temp_extract:/w.top w.top
+ rsync -av w.top/ .
+ rm -rf w.top
+ docker rm temp_extract
+ echo "cache ok"
+ echo "$tag" > /tmp/cakewallet_docker
+ return 0
+ fi
+ docker rm -f temp_extract >/dev/null 2>&1 || true
+ echo "cache miss oh"
+ if [[ "$required" == "required" ]]; then
+ echo "final image missing: $tag" >&2
+ exit 1
+ fi
+ return 1
+}
-build base "$base_ver"
+build_base() {
+ build base "$base_ver"
+}
-build bitbox "$bitbox_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+build_bitbox() {
+ build bitbox "$bitbox_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+}
-build mwebd "$mwebd_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+build_mwebd() {
+ build mwebd "$mwebd_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+}
-build reown "$reown_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+build_reown() {
+ build reown "$reown_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+}
-build monero "$monero_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+build_zcash() {
+ build zcash "$zcash_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+}
-build zcash "$zcash_ver" --build-arg BASE_IMAGE="$(img base "$base_ver")"
+build_torch() {
+ build torch "$torch_ver" \
+ --build-arg BASE_IMAGE="$(img base "$base_ver")" \
+ --build-arg TARGET="${TARGET}"
+}
-build torch "$torch_ver" \
- --build-arg BASE_IMAGE="$(img base "$base_ver")"
+build_monero() {
+ if [[ "$MERGE" == true ]]; then
+ local slices=()
+ local coin t
+ for coin in "${MONERO_COINS[@]}"; do
+ for t in "${MONERO_TARGETS[@]}"; do
+ slices+=("$(img monero "$monero_ver" "-${coin}-${t}")")
+ done
+ done
+ merge_slices monero "$monero_ver" "$(monero_assembled_extra)" "${slices[@]}"
+ return 0
+ fi
+ build monero "$monero_ver" \
+ --build-arg BASE_IMAGE="$(img base "$base_ver")" \
+ --build-arg COIN="${COIN}" \
+ --build-arg TARGET="${TARGET}"
+}
-build final $final_ver \
- --build-arg BASE_IMAGE="$(img base $base_ver)" \
- --build-arg TORCH_IMAGE="$(img torch $torch_ver)" \
- --build-arg REOWN_IMAGE="$(img reown $reown_ver)" \
- --build-arg BITBOX_IMAGE="$(img bitbox $bitbox_ver)" \
- --build-arg MONERO_IMAGE="$(img monero $monero_ver)" \
- --build-arg MWEBD_IMAGE="$(img mwebd $mwebd_ver)" \
- --build-arg ZCASH_IMAGE="$(img zcash $zcash_ver)"
+build_final() {
+ build final "$final_ver" \
+ --build-arg BASE_IMAGE="$(img base "$base_ver")" \
+ --build-arg TORCH_IMAGE="$(img torch "$torch_ver")" \
+ --build-arg REOWN_IMAGE="$(img reown "$reown_ver")" \
+ --build-arg BITBOX_IMAGE="$(img bitbox "$bitbox_ver")" \
+ --build-arg MONERO_IMAGE="$(img monero "$monero_ver" "$(monero_assembled_extra)")" \
+ --build-arg MWEBD_IMAGE="$(img mwebd "$mwebd_ver")" \
+ --build-arg ZCASH_IMAGE="$(img zcash "$zcash_ver")"
+ echo "done: $(img final $final_ver)"
+ echo "$(img final $final_ver)" > /tmp/cakewallet_docker
+}
-echo "done: $(img final $final_ver)"
-echo $(img final $final_ver) > /tmp/cakewallet_docker
+run_one() {
+ case "$1" in
+ base) build_base ;;
+ bitbox) build_bitbox ;;
+ mwebd) build_mwebd ;;
+ reown) build_reown ;;
+ zcash) build_zcash ;;
+ torch) build_torch ;;
+ monero) build_monero ;;
+ final) build_final ;;
+ *)
+ echo "Unknown component: $1" >&2
+ exit 1
+ ;;
+ esac
+}
+if [[ "$EXTRACT" == true ]]; then
+ extract_final required
+ exit 0
+fi
-docker create --name temp_extract $(img final $final_ver) \
-&& cd $REPO_ROOT \
-&& docker cp temp_extract:/w.top w.top \
-&& rsync -av w.top/ . \
-&& rm -rf w.top \
-&& docker rm temp_extract \
-&& echo "cache ok" \
-&& exit 0
+if [[ -z "$ONLY" ]]; then
+ extract_final && exit 0 || true
+ ONLY=""
+ TARGET=""
+ COIN=""
+ MERGE=false
+ build_base
+ build_bitbox
+ build_mwebd
+ build_reown
+ build_monero
+ build_zcash
+ build_torch
+ build_final
+ extract_final required
+ exit 0
+fi
-echo idk.
-exit 1
+run_one "$ONLY"Why this scored 16/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.