wolfskin/docker/README.md
justinzeus 221f623c87
All checks were successful
review/code-claude Approve: lock held across container, no deadlock, releases on all exits
Serialize Gradle containers sharing a cache volume
2026-10-27 15:30:44 +01:00

115 lines
5.8 KiB
Markdown

# Wolfskin TV container builds
Run from a full Git checkout with the upstream `v*` and `p*` tags available. The
host needs Docker, GNU Make, Bash, Git, and `flock` (util-linux), not Java or the
Android SDK.
```sh
git fetch origin --tags
make apk # clean, signed default release: three ABI splits + universal
make test # upstream testDefaultDebugUnitTest in the same image, no secrets
make apk-debug # default debug, no secrets; MPV stub and no extra codec decoders
```
APKs remain under `app/build/outputs/apk/default/{release,debug}/`. Debug builds
are not playback-complete and must not be distributed as releases. Upstream's
`.github/workflows` and dependency version catalog are unchanged; release builds
use the catalog's exact Wholphin extension version (currently `0.2.4`). Do not
place local extension AARs in `app/libs`: upstream prefers them over the pinned
GitHub Packages dependencies.
Upload release assets renamed to `Wolfskin.apk` / `Wolfskin-<abi>.apk` for the
in-app updater. Gradle outputs
`Wholphin-default-release-<versionName>-<versionCode>[-<abi>].apk`; strip the
flavor, version, and code as well as replacing the prefix.
Upstream enables JVM unit tests only for debug variants; there is no
`testDefaultReleaseUnitTest` task. `make test` uses the closest default-flavor
task without changing upstream's test configuration.
## Toolchain and disk use
`Dockerfile` pins Temurin JDK `21.0.11+10` by image digest, command-line tools
`23.0` and platform-tools `37.0.1` by archive and checksum, and build-tools
`36.0.0` by SDK package version. The SDK manager registers platform `37.0` and
its licenses; the build rejects any platform revision other than 2. An SDK
revision upgrade therefore requires a deliberate Dockerfile update.
Gradle comes from the committed wrapper. The image is built for `linux/amd64`;
the default local image tag is `wolfskin-build:sdk37-jdk21`.
Upstream's build timestamp means APKs are not byte-for-byte reproducible.
Gradle downloads and caches live in the named volume `wolfskin-gradle`, not
`/tmp`. Module outputs stay in the checkout. Builds run with the host UID/GID,
`--no-daemon`, and at most four workers. The repository's Git metadata is mounted
read-only, including when the checkout is a linked worktree.
Override `WOLFSKIN_BUILD_IMAGE` to change the locally built image tag and
`WOLFSKIN_GRADLE_VOLUME` to isolate a cache. `make build-image` builds only the
image. Do not delete shared caches during another build.
Every Gradle container holds a host-side exclusive lock for its entire run.
Concurrent targets sharing a cache queue rather than timing out on Gradle's
cross-container cache journal lock; a waiting invocation prints one line.
The default lock is `/var/tmp/${WOLFSKIN_GRADLE_VOLUME}.gradle.lock` (using
`wolfskin-gradle` when unset). Override `WOLFSKIN_GRADLE_LOCK_FILE` with a path
whose parent directory already exists. All callers sharing a volume must use
the same lock path on the Docker host. Do not delete the file while builds are
running or waiting. The lock releases automatically when the invocation exits.
## Release credentials
The default escrow is
`/opt/stacks/ventoy/machine-parity/manifest-tank/secrets/wolfskin/`. Check
`mountpoint -q /mnt/ventoy` before using that path. Set `WOLFSKIN_SECRETS_DIR`
to use another existing directory. Its required files are:
| File | Contents |
| --- | --- |
| `release.jks` | Separate Wolfskin PKCS12 keystore, RSA 4096, alias `wolfskin` |
| `release.properties` | Java properties `storePassword` and `keyPassword` |
| `github-packages-token` | GitHub token with `read:packages`, username `JustinZeus` |
The directory must be mode `0700`, each file mode `0600`, owned by the building
user. Never commit them or put their contents in logs. Back up the keystore and
passwords together: losing the release key forces a reinstall. Do not reuse
wolfskin-android's key or the gh CLI login token.
Release builds mount escrow read-only. The token is loaded inside the container
into upstream's `ORG_GRADLE_PROJECT_WholphinExtensionsUsername` and
`ORG_GRADLE_PROJECT_WholphinExtensionsPassword` environment hooks, never a Docker
command argument. The signing init script registers `wolfskin`; the nonsecret
`release-signing.properties` is mounted as `local.properties` so upstream's
`release.signing.config` hook selects it. Any host `local.properties` is hidden
only for the duration of this container. Keystore and passwords stay outside the
checkout and image. Missing credentials fail the release rather than silently
shipping the MPV stub.
## Versioning and local release markers
Upstream computes `versionName` from
`git describe --tags --long --match='v*'`, dropping the leading `v`, and computes
`versionCode` from the count of all local `v*` and `p*` tags. Preserve and fetch
those tags; a shallow or incomplete checkout can give an incorrect version.
Use the full `git describe` output as the human release name.
After committing the intended release, with a clean checkout and fetched tags:
```sh
make release-tag
make apk
```
The helper creates one lightweight `pwolfskin-YYYY_MM_DD` tag in UTC, appending
`_1`, `_2`, etc. on collision. Each marker adds one to `versionCode` without
changing upstream's `v*`-based version name. It never pushes tags, publishes a
release, or installs an APK. Do not delete published release markers. Tag
creation and publication must be serialized between release operators.
## Inspecting release artifacts
Use `apksigner verify --verbose --print-certs APK` and
`aapt2 dump badging APK` inside the build image. Compare the signer SHA-256 with
`keytool -list -v -alias wolfskin -keystore /path/to/release.jks` (enter its
password privately). Inspect APK ZIP entries for real native MPV and ffmpeg
libraries for each shipped ABI; a successful Java compilation alone does not
prove that codec extensions are included.