holger-ui 3.1.2

Holger's web console: `cargo install holger-ui`, point it at a Holger with HOLGER_UI_HOLGER, open http://127.0.0.1:3210/ and sign in. It serves the console bundle and a same-origin pass-through to that Holger, and nothing else.
//! Embeds the built console bundle into the `holger-ui` program, when one is there.
//!
//! The bundle is trunk's output (`cargo xtask console` builds it and copies it to
//! `console/` in this crate, where a published crate carries it). Looked for, in order:
//! `$HOLGER_UI_CONSOLE`, `console/` beside this file, and a holger-ui checkout's `dist/`.
//! None found: the program carries no bundle and serves the pass-through alone (it says so
//! at start, and `HOLGER_UI_DIR` still names a bundle on disk). Pure std, no subprocess.
//!
//! It also stamps `HOLGER_UI_GIT_HASH`, the commit `holger-ui --version` names (lane
//! HOL-310-CHECK): a published package takes it from the `.cargo_vcs_info.json` cargo writes
//! into every package (crates.io's copy has no `.git`), a checkout from its git plumbing, else
//! `unknown`. A real publish says `"dirty": true` there, and that is expected: the console
//! bundle in `console/` is gitignored and copied in before the publish (`--allow-dirty`); the
//! sha is still the commit the source came from.
//!
//! **A package's console names the commit it was built from** (lane hol-312fix, field test
//! F11: holger-ui 3.1.0 and 3.1.1 shipped the 3.0.0 console, a copy left in the gitignored
//! `console/` by an older publish). `cargo xtask console` writes `console/BUILT_FROM`, the
//! holger-ui commit it built. A PACKAGE build (the one `cargo publish` verifies, and every
//! `cargo install holger-ui`) that embeds its own `console/` refuses it unless BUILT_FROM names
//! the package's `.cargo_vcs_info.json` commit (`[holger-ui-console-stale]`). In a checkout a
//! console from another commit is only a warning. `HOLGER_UI_CONSOLE` is the builder's own
//! choice and is not checked.

use std::path::{Path, PathBuf};

/// The stamp `cargo xtask console` writes into the bundle: the holger-ui commit it built.
const BUILT_FROM: &str = "BUILT_FROM";

fn main() {
    let packaged = packaged_sha();
    let head = git_head();
    let hash = packaged
        .as_deref()
        .or(head.as_deref())
        .map(|s| s[..7].to_string())
        .unwrap_or_else(|| "unknown".to_string());
    println!("cargo:rustc-env=HOLGER_UI_GIT_HASH={hash}");
    println!("cargo:rerun-if-env-changed=HOLGER_UI_CONSOLE");
    let here =
        PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").expect("cargo sets CARGO_MANIFEST_DIR"));
    let candidates: Vec<PathBuf> = std::env::var_os("HOLGER_UI_CONSOLE")
        .map(PathBuf::from)
        .into_iter()
        .chain([here.join("console"), here.join("../../dist")])
        .collect();
    for c in &candidates {
        println!("cargo:rerun-if-changed={}", c.display());
    }
    let dir = candidates.iter().find(|d| d.join("index.html").is_file());
    if let Some(d) = dir.filter(|d| *d == &here.join("console")) {
        check_built_from(d, packaged.as_deref(), head.as_deref());
    }
    let mut files = Vec::new();
    if let Some(d) = dir {
        walk(d, d, &mut files);
    }
    files.sort();
    let mut out = String::from("/// The console bundle built into this program: (path in the bundle, bytes).\npub static CONSOLE: &[(&str, &[u8])] = &[\n");
    for (rel, abs) in &files {
        out.push_str(&format!(
            "    ({rel:?}, include_bytes!({:?})),\n",
            abs.display().to_string()
        ));
    }
    out.push_str("];\n");
    out.push_str(&format!("/// Where the build took it from (empty: no bundle).\npub static CONSOLE_FROM: &str = {:?};\n", dir.map(|d| d.display().to_string()).unwrap_or_default()));
    let dest =
        PathBuf::from(std::env::var("OUT_DIR").expect("cargo sets OUT_DIR")).join("console.rs");
    std::fs::write(&dest, out).expect("write console.rs");
}

fn walk(root: &Path, dir: &Path, out: &mut Vec<(String, PathBuf)>) {
    let Ok(entries) = std::fs::read_dir(dir) else {
        return;
    };
    for e in entries.flatten() {
        let p = e.path();
        if p.is_dir() {
            walk(root, &p, out);
        } else if dir == root && e.file_name() == BUILT_FROM {
            // The stamp is the build's evidence, not a file the console serves.
        } else if let Ok(rel) = p.strip_prefix(root) {
            let abs = p.canonicalize().unwrap_or(p.clone());
            out.push((rel.to_string_lossy().replace('\\', "/"), abs));
        }
    }
}

/// **The package's console must be the one built from the package's commit**
/// (`[holger-ui-console-stale]`). `packaged` is the `.cargo_vcs_info.json` commit (a package
/// build: refused), `head` the checkout's HEAD (a checkout build: a warning only).
fn check_built_from(console: &Path, packaged: Option<&str>, head: Option<&str>) {
    let stamp_path = console.join(BUILT_FROM);
    println!("cargo:rerun-if-changed={}", stamp_path.display());
    let stamp = std::fs::read_to_string(&stamp_path)
        .ok()
        .map(|s| s.trim().to_string())
        .filter(|s| !s.is_empty());
    let fix = "rebuild it with `cargo xtask console` in the holger-ui checkout of that commit";
    match (packaged, stamp.as_deref()) {
        (Some(want), Some(got)) if got == want => {}
        (Some(want), got) => panic!(
            "[holger-ui-console-stale] this package of holger-ui commit {want} carries a console \
             bundle in {} that {}: a published holger-ui must carry the console built from its \
             own commit; {fix}",
            console.display(),
            match got {
                Some(g) => format!("was built from holger-ui commit {g} ({BUILT_FROM})"),
                None => format!("names no commit it was built from (no {BUILT_FROM})"),
            }
        ),
        (None, got) => {
            if let (Some(h), Some(g)) = (head, got) {
                if h != g {
                    println!(
                        "cargo:warning=holger-ui: the console in {} was built from {g}, not HEAD {h}; {fix}",
                        console.display()
                    );
                }
            }
        }
    }
}

/// The full sha of the commit a published package was made from, read from the
/// `.cargo_vcs_info.json` cargo writes into every package (absent in a checkout).
fn packaged_sha() -> Option<String> {
    let path =
        PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").ok()?).join(".cargo_vcs_info.json");
    println!("cargo:rerun-if-changed={}", path.display());
    let json = std::fs::read_to_string(&path).ok()?;
    let key = "\"sha1\"";
    let rest = json[json.find(key)? + key.len()..].trim_start();
    let rest = rest.strip_prefix(':')?.trim_start().strip_prefix('"')?;
    let sha = &rest[..rest.find('"')?];
    (sha.len() == 40 && sha.bytes().all(|b| b.is_ascii_hexdigit())).then(|| sha.to_string())
}

/// HEAD's full sha of the checkout this crate sits in, from the on-disk git plumbing.
fn git_head() -> Option<String> {
    let mut dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").ok()?);
    let git_dir = loop {
        let dot = dir.join(".git");
        if dot.is_dir() {
            break dot;
        }
        if dot.is_file() {
            // A worktree: `gitdir: <path>`.
            let text = std::fs::read_to_string(&dot).ok()?;
            let target = PathBuf::from(text.trim().strip_prefix("gitdir:")?.trim());
            break if target.is_absolute() {
                target
            } else {
                dir.join(target)
            };
        }
        if !dir.pop() {
            return None;
        }
    };
    let common = std::fs::read_to_string(git_dir.join("commondir"))
        .ok()
        .map(|c| {
            let c = PathBuf::from(c.trim());
            if c.is_absolute() {
                c
            } else {
                git_dir.join(c)
            }
        })
        .unwrap_or_else(|| git_dir.clone());
    let head_path = git_dir.join("HEAD");
    println!("cargo:rerun-if-changed={}", head_path.display());
    let head = std::fs::read_to_string(&head_path).ok()?;
    let head = head.trim();
    let sha = match head.strip_prefix("ref:") {
        None => head.to_string(),
        Some(name) => {
            let name = name.trim();
            for base in [&git_dir, &common] {
                let loose = base.join(name);
                if let Ok(s) = std::fs::read_to_string(&loose) {
                    println!("cargo:rerun-if-changed={}", loose.display());
                    return full(s.trim());
                }
            }
            let packed = common.join("packed-refs");
            println!("cargo:rerun-if-changed={}", packed.display());
            std::fs::read_to_string(&packed)
                .ok()?
                .lines()
                .find_map(|l| l.strip_suffix(name).map(|s| s.trim().to_string()))?
        }
    };
    full(&sha)
}

fn full(sha: &str) -> Option<String> {
    (sha.len() == 40 && sha.bytes().all(|b| b.is_ascii_hexdigit())).then(|| sha.to_string())
}