use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::process::Command; use std::{fs, path::Path}; fn main() { // Set GIT_HASH env var for compile-time inclusion via option_env!() let hash = Command::new("git") .args(["rev-parse", "--short", "HEAD"]) .output() .ok() .filter(|o| o.status.success()) .and_then(|o| String::from_utf8(o.stdout).ok()) .map(|s| s.trim().to_string()) .unwrap_or_default(); println!("cargo::rustc-env=GIT_HASH={}", hash); // Only re-run when HEAD changes println!("cargo::rerun-if-changed=.git/HEAD"); // --- Static asset fingerprinting --- // Hash the content of key static files to produce a version suffix. // When any watched file changes, URLs in templates get a new ?v= param, // busting browser caches automatically. let static_files = [ "static/style.css", "static/htmx.min.js", "static/upload.js", "static/passkey.js", "static/insertions.js", ]; let mut hasher = DefaultHasher::new(); for path in &static_files { println!("cargo::rerun-if-changed={}", path); if let Ok(content) = fs::read(path) { content.hash(&mut hasher); } } let static_hash = format!("{:016x}", hasher.finish()); let version = &static_hash[..8]; // Generate a template partial with versioned asset URLs. // base.html includes this via {% include "_head_assets.html" %} let partial = format!( r#" "#, v = version, ); let out_path = Path::new("templates/_head_assets.html"); // Only write if content changed (avoids unnecessary recompilation) let needs_write = fs::read_to_string(out_path) .map(|existing| existing != partial) .unwrap_or(true); if needs_write { fs::write(out_path, &partial).expect("failed to write _head_assets.html"); } }