use std::path::{Path, PathBuf};
use std::process::Command;
fn main() {
let crate_root = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap_or_default());
let ui_dir = crate_root.join("ui");
let dist_dir = ui_dir.join("dist");
println!("cargo:rerun-if-env-changed=SKIP_UI_BUILD");
println!("cargo:rerun-if-changed=ui/package.json");
println!("cargo:rerun-if-changed=ui/vite.config.js");
println!("cargo:rerun-if-changed=ui/index.html");
println!("cargo:rerun-if-changed=ui/src");
build_svelte_ui(&ui_dir, &dist_dir, "trusty-memory");
}
fn build_svelte_ui(ui_dir: &Path, dist_dir: &Path, crate_name: &str) {
if std::env::var("SKIP_UI_BUILD").as_deref() == Ok("1") {
if !dist_dir.join("index.html").exists() {
println!(
"cargo:warning=SKIP_UI_BUILD=1 but {dist}/ is empty — \
run `pnpm --dir ui install && pnpm --dir ui build` before publishing.",
dist = dist_dir.display()
);
ensure_placeholder(dist_dir, crate_name);
}
return;
}
if !ui_dir.join("package.json").exists() {
ensure_placeholder(dist_dir, crate_name);
return;
}
let Some(pm) = detect_pm() else {
println!(
"cargo:warning={crate_name}: no pnpm/npm on PATH — skipping UI \
build (set SKIP_UI_BUILD=1 to silence, or install pnpm)."
);
ensure_placeholder(dist_dir, crate_name);
return;
};
let mut install_args = vec!["install"];
if pm == "pnpm" && ui_dir.join("pnpm-lock.yaml").exists() {
install_args.push("--frozen-lockfile");
}
let install_ok = Command::new(pm)
.args(&install_args)
.current_dir(ui_dir)
.status()
.map(|s| s.success())
.unwrap_or(false);
if !install_ok {
println!("cargo:warning={crate_name}: `{pm} install` failed — embedding placeholder UI.");
ensure_placeholder(dist_dir, crate_name);
return;
}
let build_ok = Command::new(pm)
.args(["run", "build"])
.current_dir(ui_dir)
.status()
.map(|s| s.success())
.unwrap_or(false);
if !build_ok {
println!("cargo:warning={crate_name}: `{pm} run build` failed — embedding placeholder UI.");
ensure_placeholder(dist_dir, crate_name);
}
}
fn ensure_placeholder(dist_dir: &Path, crate_name: &str) {
if dist_dir.join("index.html").exists() {
return;
}
let _ = std::fs::create_dir_all(dist_dir);
let html = format!(
"<!doctype html><html><body><p>{crate_name}: UI assets not built. \
Run <code>pnpm --dir ui install && pnpm --dir ui build</code> \
and rebuild.</p></body></html>"
);
let _ = std::fs::write(dist_dir.join("index.html"), html);
}
fn detect_pm() -> Option<&'static str> {
let ok = |bin: &str| {
Command::new(bin)
.arg("--version")
.output()
.map(|o| o.status.success())
.unwrap_or(false)
};
if ok("pnpm") {
Some("pnpm")
} else if ok("npm") {
Some("npm")
} else {
None
}
}