use std::path::{Path, PathBuf};
use std::process::Command;
fn main() {
let crate_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let workspace_root = crate_dir.parent().unwrap().parent().unwrap();
let viz_dir = workspace_root.join("viz");
let dist_dir = crate_dir.join("dist-viz");
let dist_assets = dist_dir.join("assets");
println!("cargo:rerun-if-changed=../../viz/src");
println!("cargo:rerun-if-changed=../../viz/index.html");
println!("cargo:rerun-if-changed=../../viz/package.json");
println!("cargo:rerun-if-changed=../../viz/vite.config.ts");
println!("cargo:rerun-if-changed=../../viz/tsconfig.json");
let needs_build = !dist_dir.join("index.html").exists()
|| !dist_assets.join("main.js").exists()
|| !dist_assets.join("main.css").exists()
|| !dist_assets.join("webgl-device.js").exists();
if needs_build && viz_dir.exists() && which("npm").is_some() {
let node_modules = viz_dir.join("node_modules");
if !node_modules.exists() {
println!("cargo:warning=Installing viz npm dependencies (one-time, ~30s)…");
let status = Command::new("npm")
.arg("install")
.current_dir(&viz_dir)
.status();
if let Ok(s) = status {
if !s.success() {
println!("cargo:warning=npm install failed; using placeholder viz assets");
}
}
}
if node_modules.exists() {
println!("cargo:warning=Building viz frontend (npm run build)…");
let status = Command::new("npm")
.args(["run", "build"])
.current_dir(&viz_dir)
.status();
if let Ok(s) = status {
if !s.success() {
println!("cargo:warning=npm run build failed; using placeholder viz assets");
}
}
}
}
ensure_placeholder(&dist_dir, &dist_assets);
}
fn ensure_placeholder(dist_dir: &Path, dist_assets: &Path) {
let index = dist_dir.join("index.html");
let js = dist_assets.join("main.js");
let css = dist_assets.join("main.css");
let webgl = dist_assets.join("webgl-device.js");
if index.exists() && js.exists() && css.exists() && webgl.exists() {
return;
}
std::fs::create_dir_all(dist_assets).ok();
let placeholder_html = "<!doctype html><html><head><meta charset=\"utf-8\"><title>GitCortex Viz</title></head><body style=\"background:#06060a;color:#e6e6f0;font-family:monospace;padding:24px;\"><h2>Viz frontend not built</h2><p>Run <code>cd viz && npm install && npm run build</code> and rebuild <code>gcx</code>.</p></body></html>";
if !index.exists() {
std::fs::write(&index, placeholder_html).ok();
}
for f in [&js, &css, &webgl] {
if !f.exists() {
std::fs::write(f, "").ok();
}
}
}
fn which(cmd: &str) -> Option<PathBuf> {
let path = std::env::var_os("PATH")?;
for dir in std::env::split_paths(&path) {
let candidate = dir.join(cmd);
if candidate.is_file() {
return Some(candidate);
}
#[cfg(windows)]
{
let exe = dir.join(format!("{cmd}.exe"));
if exe.is_file() {
return Some(exe);
}
}
}
None
}