From e209070272d06c02d53521e203360950f42a495c Mon Sep 17 00:00:00 2001 From: Robert M1 <50460704+githubrobbi@users.noreply.github.com> Date: Wed, 17 Jun 2026 08:01:18 -0700 Subject: [PATCH] feat(update): single source of truth for the core binary set + `uffs --update bins` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The UFFS core binary set was hardcoded in two places that could drift: `binaries::KNOWN_BINARIES` (Rust) and `BINS=(…)` in `just/build.just` (shell). Centralize on the Rust definition (now documented as the single source of truth — it already includes uffs-mft, so KNOWN ≡ the core set) and expose it to tooling via a new `uffs --update bins` action that prints the platform-appropriate stems (uffs-broker only on Windows), one per line. `just/build.just`'s `copy-binary` now queries `uffs --update bins` instead of keeping its own list, so adding/removing a core binary is a one-line change in one place and every flow picks it up. (`use-local` was already dynamic.) Host clippy (strict) clean; uffs-cli tests pass. Co-Authored-By: Claude Opus 4.8 --- .../uffs-cli/src/commands/update/binaries.rs | 21 ++++++++++++++++++- crates/uffs-cli/src/commands/update/mod.rs | 17 ++++++++++++--- just/build.just | 14 +++++++++---- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/crates/uffs-cli/src/commands/update/binaries.rs b/crates/uffs-cli/src/commands/update/binaries.rs index aadd9a280..e147bcf06 100644 --- a/crates/uffs-cli/src/commands/update/binaries.rs +++ b/crates/uffs-cli/src/commands/update/binaries.rs @@ -16,7 +16,15 @@ use super::model::BinaryInfo; /// Logical stems of every UFFS binary the updater knows about — i.e. the /// engine binaries this repo builds and publishes as release assets, so -/// each can be acquired + swapped. The platform `.exe` suffix is added by +/// each can be acquired + swapped. +/// +/// **This is the single source of truth for the UFFS core binary set.** +/// Every flow honours it: detection, self-update completeness, and tooling +/// (the `just` deploy recipes query it via `uffs --update bins` rather than +/// keeping their own list). Do not hardcode this set anywhere else — add a +/// stem here and all flows pick it up. +/// +/// The platform `.exe` suffix is added by /// [`exe_file_name`]. /// /// `uffs-tui` is deliberately **excluded**: it ships from the separate @@ -58,6 +66,17 @@ pub(crate) fn exe_file_name(stem: &str) -> String { } } +/// Print the canonical core binary stems, one per line (platform-aware: +/// `uffs-broker` only on Windows). The machine-readable accessor behind +/// `uffs --update bins`, so shell tooling (the `just` deploy recipes) reads +/// the set from here instead of keeping a hardcoded copy that can drift. +#[expect(clippy::print_stdout, reason = "machine-readable list for scripts")] +pub(crate) fn print_core_stems() { + for stem in KNOWN_BINARIES { + println!("{stem}"); + } +} + /// Enumerate the UFFS binaries actually present in `dir`, probing each /// one's version. Binaries that are not present are simply absent from /// the result (honor-what-is-installed). diff --git a/crates/uffs-cli/src/commands/update/mod.rs b/crates/uffs-cli/src/commands/update/mod.rs index 4814f0763..00dbc945a 100644 --- a/crates/uffs-cli/src/commands/update/mod.rs +++ b/crates/uffs-cli/src/commands/update/mod.rs @@ -66,11 +66,11 @@ pub(crate) fn run_update(args: &[String]) -> Result<()> { if let Some(act) = action && !matches!( act, - "check" | "snapshot" | "acquire" | "apply" | "doctor" | "repair" | "recover" + "check" | "snapshot" | "acquire" | "apply" | "doctor" | "repair" | "recover" | "bins" ) { bail!( - "unknown `--update` action `{act}` — expected: check | snapshot | acquire | apply | doctor | repair | recover" + "unknown `--update` action `{act}` — expected: check | snapshot | acquire | apply | doctor | repair | recover | bins" ); } @@ -79,6 +79,15 @@ pub(crate) fn run_update(args: &[String]) -> Result<()> { // a few plain-language lines for someone who just wants the gist. let verbose = args.iter().any(|arg| arg == "-v" || arg == "--verbose"); + // `bins` prints the canonical core binary stems (the single source of + // truth in `binaries::KNOWN_BINARIES`) for tooling — e.g. the `just` + // deploy recipes read the set from here instead of hardcoding it. + // Pure + non-mutating: no detection needed. + if action == Some("bins") { + binaries::print_core_stems(); + return Ok(()); + } + // `recover` finishes (or rolls back) an interrupted update in the // foreground — the on-demand twin of the startup best-effort self-heal. if action == Some("recover") { @@ -439,7 +448,9 @@ fn print_help() { \x20 resume/roll back an interrupted update, sweep\n\ \x20 stale backups, restart stopped services.\n\ \x20 recover Finish or roll back an interrupted update now\n\ - \x20 (foreground; the on-demand self-heal).\n\n\ + \x20 (foreground; the on-demand self-heal).\n\ + \x20 bins Print the core binary stems (one per line) —\n\ + \x20 the canonical set, for scripts/tooling.\n\n\ OPTIONS:\n\ \x20 -v, --verbose Show the full breakdown — per-binary versions,\n\ \x20 PIDs, launch commands, every doctor check.\n\ diff --git a/just/build.just b/just/build.just index e452c9ff7..402317ed3 100644 --- a/just/build.just +++ b/just/build.just @@ -92,10 +92,16 @@ copy-binary profile: if [[ "$OSTYPE" == "msys"* ]] || [[ "$OSTYPE" == "cygwin"* ]] || [[ -n "$WINDIR" ]]; then EXT=".exe"; printf "\033[0;34m → Windows detected\033[0m\n"; else EXT=""; printf "\033[0;34m → Unix-like system detected\033[0m\n"; fi SOURCE_DIR="target/{{ profile }}" mkdir -p ~/bin - # uffs-update is the self-update helper (`uffs update` spawns it as a - # sibling). uffs-broker is the elevated handle service — Windows only. - BINS=(uffs uffsd uffsmcp uffs-mft uffs-update) - if [[ -n "$EXT" ]]; then BINS+=(uffs-broker); fi + # The core binary set is owned by `uffs --update bins` (single source of + # truth in uffs-cli) — query the just-built binary instead of hardcoding, + # so this list never drifts. The printer is platform-aware: it emits + # uffs-broker only on Windows (the self-update helper + elevated handle + # service are included automatically). + UFFS_BIN="$SOURCE_DIR/uffs${EXT}" + if [[ ! -x "$UFFS_BIN" ]]; then + printf "\033[0;31m❌ %s not built — run a build first\033[0m\n" "$UFFS_BIN"; exit 1 + fi + mapfile -t BINS < <("$UFFS_BIN" --update bins) for BIN in "${BINS[@]}"; do SOURCE_PATH="$SOURCE_DIR/${BIN}${EXT}" DEST_PATH="$HOME/bin/${BIN}${EXT}"