The status bar gains the TUI's half of the same contract the web client got: a coloured dot plus the release the daemon is running, pinned right so a narrow terminal truncates the key hints rather than the release. `DaemonLink` mirrors web/src/daemonLink.ts — the events loop reports its connects and disconnects, a probe task polls `GET /api/info` while the daemon is unreachable, and past the grace window a modal covers the frame and locks the keyboard (quit excepted) until it answers. A daemon that comes back on a new commit cannot be reloaded into a running TUI binary, so the status bar says `updated: <hash> (restart tui)` instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
78 lines
2.9 KiB
Rust
78 lines
2.9 KiB
Rust
//! Stamps the daemon binary with the commit it was built from, so
|
|
//! `GET /api/info` can tell clients which release they are talking to.
|
|
//!
|
|
//! Two sources, in order:
|
|
//!
|
|
//! 1. `MAESTRO_BUILD_COMMIT` / `MAESTRO_BUILD_DATE` / `MAESTRO_BUILD_DIRTY` in
|
|
//! the environment. The Nix build has no `.git` in its source tree (crane
|
|
//! filters it out), so `flake.nix` passes the flake's own revision this way.
|
|
//! 2. The git checkout the crate is being compiled in.
|
|
//!
|
|
//! Neither available leaves the values empty; clients treat that as "unknown
|
|
//! release" rather than an error.
|
|
|
|
use std::path::PathBuf;
|
|
use std::process::Command;
|
|
|
|
fn main() {
|
|
println!("cargo:rerun-if-env-changed=MAESTRO_BUILD_COMMIT");
|
|
println!("cargo:rerun-if-env-changed=MAESTRO_BUILD_DATE");
|
|
println!("cargo:rerun-if-env-changed=MAESTRO_BUILD_DIRTY");
|
|
// Rebuild when HEAD moves, so a plain `cargo build` after a commit or a
|
|
// branch switch restamps instead of serving the previous hash.
|
|
for f in ["HEAD", "ORIG_HEAD"] {
|
|
if let Some(p) = git_dir().map(|d| d.join(f)) {
|
|
if p.exists() {
|
|
println!("cargo:rerun-if-changed={}", p.display());
|
|
}
|
|
}
|
|
}
|
|
|
|
let commit = env_or_git("MAESTRO_BUILD_COMMIT", &["rev-parse", "--short=12", "HEAD"]);
|
|
let date = env_or_git("MAESTRO_BUILD_DATE", &["log", "-1", "--format=%cI"]);
|
|
let dirty = match std::env::var("MAESTRO_BUILD_DIRTY") {
|
|
Ok(v) => v == "1" || v.eq_ignore_ascii_case("true"),
|
|
Err(_) => !git(&["status", "--porcelain"])
|
|
.unwrap_or_default()
|
|
.is_empty(),
|
|
};
|
|
|
|
println!("cargo:rustc-env=MAESTRO_BUILD_COMMIT={commit}");
|
|
println!("cargo:rustc-env=MAESTRO_BUILD_DATE={date}");
|
|
println!("cargo:rustc-env=MAESTRO_BUILD_DIRTY={dirty}");
|
|
}
|
|
|
|
/// The environment variable if set and non-empty, else what git reports, else
|
|
/// an empty string.
|
|
fn env_or_git(var: &str, args: &[&str]) -> String {
|
|
match std::env::var(var) {
|
|
Ok(v) if !v.trim().is_empty() => v.trim().to_string(),
|
|
_ => git(args).unwrap_or_default(),
|
|
}
|
|
}
|
|
|
|
/// Run `git` inside the crate's source tree. `None` when git is missing, the
|
|
/// tree is not a checkout, or the command fails — every one of which is a
|
|
/// legitimate way to build Maestro.
|
|
fn git(args: &[&str]) -> Option<String> {
|
|
let out = Command::new("git")
|
|
.args(args)
|
|
.current_dir(env!("CARGO_MANIFEST_DIR"))
|
|
.output()
|
|
.ok()?;
|
|
if !out.status.success() {
|
|
return None;
|
|
}
|
|
Some(String::from_utf8_lossy(&out.stdout).trim().to_string())
|
|
}
|
|
|
|
/// Absolute path of the `.git` directory (a worktree's `.git` is a file
|
|
/// pointing elsewhere, and `--git-common-dir` resolves both).
|
|
fn git_dir() -> Option<PathBuf> {
|
|
let dir = git(&["rev-parse", "--path-format=absolute", "--git-common-dir"])?;
|
|
if dir.is_empty() {
|
|
return None;
|
|
}
|
|
Some(PathBuf::from(dir))
|
|
}
|