use std::path::{Path, PathBuf};
fn main() {
println!("cargo::rerun-if-changed=src");
let root = PathBuf::from(std::env::var_os("CARGO_MANIFEST_DIR").expect("set by cargo"));
let fingerprint = source_fingerprint(&root.join("src"));
println!("cargo::rustc-env=RAZERI_PLUGIN_CONTRACT_SOURCE={fingerprint:016x}");
}
fn source_fingerprint(dir: &Path) -> u64 {
let mut files = Vec::new();
collect(dir, dir, &mut files);
files.sort();
let mut hash: u64 = 0xcbf2_9ce4_8422_2325;
let mut feed = |bytes: &[u8]| {
for &byte in bytes {
hash ^= u64::from(byte);
hash = hash.wrapping_mul(0x0000_0100_0000_01b3);
}
};
for (relative, path) in files {
feed(relative.as_bytes());
feed(&[0]);
let contents = std::fs::read(&path)
.unwrap_or_else(|e| panic!("cannot read {} to fingerprint it: {e}", path.display()));
let without_returns: Vec<u8> = contents.into_iter().filter(|&b| b != b'\r').collect();
feed(&without_returns);
feed(&[0]);
}
hash
}
fn collect(root: &Path, dir: &Path, files: &mut Vec<(String, PathBuf)>) {
let entries = std::fs::read_dir(dir)
.unwrap_or_else(|e| panic!("cannot read {} to fingerprint it: {e}", dir.display()));
for entry in entries {
let path = entry.expect("a directory entry").path();
if path.is_dir() {
collect(root, &path, files);
} else {
let relative = path.strip_prefix(root).expect("under the root");
let spelled: Vec<String> = relative
.components()
.map(|c| c.as_os_str().to_string_lossy().into_owned())
.collect();
files.push((spelled.join("/"), path));
}
}
}