use std::fs;
use std::path::{Path, PathBuf};
fn main() {
println!("cargo:rerun-if-changed=src");
let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
let discriminator = if in_git_checkout(&manifest_dir) {
format!("-b{:016x}", hash_sources(&manifest_dir.join("src")))
} else {
String::new()
};
println!("cargo:rustc-env=TOKIE_BUILD_DISCRIMINATOR={discriminator}");
}
fn in_git_checkout(start: &Path) -> bool {
start.ancestors().any(|dir| dir.join(".git").exists())
}
fn hash_sources(src: &Path) -> u64 {
let mut files = Vec::new();
collect_rs_files(src, &mut files);
files.sort();
let mut hash: u64 = 0xcbf2_9ce4_8422_2325;
let mut update = |bytes: &[u8]| {
for &b in bytes {
hash ^= u64::from(b);
hash = hash.wrapping_mul(0x0000_0100_0000_01b3);
}
};
for file in &files {
let rel = file.strip_prefix(src).unwrap_or(file);
update(rel.to_string_lossy().as_bytes());
update(&fs::read(file).unwrap_or_default());
}
hash
}
fn collect_rs_files(dir: &Path, out: &mut Vec<PathBuf>) {
let Ok(entries) = fs::read_dir(dir) else { return };
for entry in entries.flatten() {
let path = entry.path();
let Ok(file_type) = entry.file_type() else { continue };
if file_type.is_dir() {
collect_rs_files(&path, out);
} else if file_type.is_file() && path.extension().is_some_and(|e| e == "rs") {
out.push(path);
}
}
}