use std::path::{Path, PathBuf};
use std::process::Command;
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_API_SOURCE={fingerprint:016x}");
println!("cargo::rustc-env=RAZERI_PLUGIN_API_COMPILER={}", compiler());
}
fn compiler() -> String {
let rustc = std::env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
let output = Command::new(&rustc)
.arg("-V")
.output()
.unwrap_or_else(|e| panic!("cannot ask {} for its version: {e}", rustc.display()));
let version = String::from_utf8_lossy(&output.stdout).trim().to_string();
assert!(
output.status.success() && !version.is_empty(),
"{} -V answered nothing, so this build cannot say which compiler made it",
rustc.display()
);
version
}
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));
}
}
}