A component now declares its ways of being built in one list -- `modes: ["release", "debug"]`, the first the default -- and every command it runs is handed the mode as its last argument, so a project whose script takes `release` or `debug` names that script once. A field may instead be written per mode, which is the escape hatch for the commands that cannot take the word: cargo takes `--release` or nothing, and its profile for the unoptimised build is called `dev` while the directory it writes is called `debug`, so no single word serves as both the flag and the path. A command written per mode is not handed the word as well; it already is the answer, and a stray argument to a service binary is a process that will not start. One list rather than gathering names from whichever fields happened to mention them is what makes a mode missing from one part unsayable: every per-mode map is checked against it, so a gap is named rather than resolved to some other mode's command. Which mode to build in and whether to strip are the build machine's -- there is one checkout and one set of outputs, so a per-device mode would have two phones rebuilding over each other silently. Which of the finished builds a phone installs stays that phone's. Neither choice is part of the acceptance gate, so both have to be carried across the components list being rewritten, by acceptance and by the self entry's startup reconciliation alike; without the second a mode chosen for this server's own component would not survive the restart that applies it. A mode switch moves no commit, so `builtMode` is recorded beside `builtFrom`. Without it a component built in debug and switched to release reads as current and serves the debug build for ever -- and for an APK nothing else notices, because the "never built at all" check finds any variant under the component's directory. Each component card gains a settings sheet behind a gear at the row's right-hand end, holding the mode, which build to install, strip, and an Enrol button. The variant picker moved into it: on the card the two read as one choice, both saying debug and release, and they are not. The row's text is now bounded and truncates, so a long status can no longer push the log and settings buttons off the edge. `enroll:` is a declared command whose one line of stdout is a URL for the phone to open after installing -- generic on purpose, run per press since such a link is one-shot and carries a credential, and in the acceptance gate because it runs on the build machine. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
79 lines
4.0 KiB
Plaintext
79 lines
4.0 KiB
Plaintext
// Read by Dev Updater -- this project's entry in its own list. Structured
|
|
// as the body of the config: no outer parentheses, so nothing here is
|
|
// indented for the sake of a wrapper.
|
|
|
|
// What to call this project before there is a build to read a label from.
|
|
label: "Dev Updater",
|
|
|
|
// Where this project's own resources live. Read off the request path and
|
|
// cached, because the `Script` variant would otherwise put a process
|
|
// spawn on the manifest -- see `server/src/resources.rs`.
|
|
resources: Ron("resources.ron"),
|
|
|
|
// Walked in order, and the order is the point: the binary is built first
|
|
// so that a failing APK build leaves the phone the APK it already had
|
|
// rather than half of a matched pair.
|
|
//
|
|
// The server component is this process. That changes how it is *delivered*
|
|
// -- restarting means exec-ing the binary just built, not asking the
|
|
// script below to stop and start the code that is running (see
|
|
// `restart.rs`) -- but nothing about how it is declared, installed or
|
|
// reported on. The card is an ordinary one.
|
|
components: [
|
|
Server(
|
|
name: "server",
|
|
// No cwd: this component is built and run from the checkout root,
|
|
// which is where the server looks for its own project. That is
|
|
// also what the generated unit takes as its working directory --
|
|
// started anywhere else this server finds no checkout of its own,
|
|
// and its card silently loses the branch line, its commit count
|
|
// and the Pull button.
|
|
// The ways this component can be built, declared in one place.
|
|
// Release first, because the first is the default: what this
|
|
// server serves to a phone should be the optimised build unless
|
|
// somebody says otherwise, and debug is here for the times when
|
|
// a stack trace matters more than the speed.
|
|
modes: ["release", "debug"],
|
|
// Written per mode rather than handed the mode as an argument,
|
|
// which is the escape hatch and this is what it is for: cargo
|
|
// takes `--release` or nothing, and its *profile* for the
|
|
// unoptimised build is called `dev` while the directory it
|
|
// writes is called `debug`. So no single word can serve as both
|
|
// the flag and the path, and a project that wants one would have
|
|
// to carry a wrapper script to translate.
|
|
build: {
|
|
"release": "cargo build --release --manifest-path server/Cargo.toml",
|
|
"debug": "cargo build --manifest-path server/Cargo.toml",
|
|
},
|
|
// Managed, like anything else that just wants its binary kept
|
|
// running. Nothing about restarting *this* server lives in the
|
|
// script -- that is `restart.rs`, which defers the hand-over past
|
|
// the reply and spawns it detached. So there was nothing left for
|
|
// a script of its own to say.
|
|
// And the same for the binary, which is the pairing that makes
|
|
// per-mode worth having at all: built with `--release` and
|
|
// started from `target/debug/`, this server would go on running
|
|
// last week's build with nothing anywhere saying so.
|
|
service: Managed({
|
|
"release": "server/target/release/dev-updater",
|
|
"debug": "server/target/debug/dev-updater",
|
|
}),
|
|
),
|
|
Apk(
|
|
name: "app",
|
|
// The command resolves against the project root and `cwd` says
|
|
// where to run it -- two different things, which is why this is
|
|
// not `./build-apk.sh`.
|
|
//
|
|
// Deliberately one mode. A release build of *this* app would be
|
|
// signed with a different key from the debug one, and Android
|
|
// refuses to install a differently-signed APK over an installed
|
|
// package -- which for this app means the copy on the phone can
|
|
// no longer be updated through the server it updates itself
|
|
// from. Every other project can switch freely; this is the one
|
|
// that cannot, because it is the way back.
|
|
build: "app/build-apk.sh",
|
|
cwd: "app",
|
|
),
|
|
],
|