pub(crate) const BUILD_ID_EXTS: &[&str] = &["rs", "toml", "cu", "cuh", "h"];
pub(crate) const BUILD_ID_ROOT_FILES: &[&str] = &["Cargo.toml", "Cargo.lock"];
pub(crate) const BUILD_ID_SKIP_DIRS: &[&str] = &["target", ".git"];
pub(crate) const BUILD_ID_HEX: usize = 12;
pub(crate) const BUILD_ID_SRC_TREE: &str = "source-tree";
pub(crate) const BUILD_ID_SRC_DEGRADED: &str = "degraded";
const FNV_OFFSET: u128 = 0x6c62_272e_07bb_0142_62b8_2175_6295_c58d;
pub(crate) fn fnv1a128(bytes: &[u8], mut h: u128) -> u128 {
const PRIME: u128 = 0x0000_0000_0100_0000_0000_0000_0000_013B;
for b in bytes {
h ^= *b as u128;
h = h.wrapping_mul(PRIME);
}
h
}
pub(crate) fn render_build_id(h: u128) -> String {
let bits = (BUILD_ID_HEX * 4) as u32;
format!("{:0width$x}", h >> (128 - bits), width = BUILD_ID_HEX)
}
pub(crate) struct BuildIdScan {
pub(crate) id: String,
pub(crate) files: Vec<std::path::PathBuf>,
pub(crate) dirs: Vec<std::path::PathBuf>,
}
pub(crate) fn workspace_root(manifest_dir: &str) -> Option<std::path::PathBuf> {
let root = std::path::Path::new(manifest_dir).parent()?.parent()?;
(root.join("crates").is_dir() && root.join("Cargo.toml").is_file()).then(|| root.to_path_buf())
}
fn rel_key(root: &std::path::Path, path: &std::path::Path) -> Option<String> {
Some(
path.strip_prefix(root)
.ok()?
.to_str()?
.replace(std::path::MAIN_SEPARATOR, "/"),
)
}
fn collect(
dir: &std::path::Path,
files: &mut Vec<std::path::PathBuf>,
dirs: &mut Vec<std::path::PathBuf>,
) -> std::io::Result<()> {
dirs.push(dir.to_path_buf());
let mut entries: Vec<std::fs::DirEntry> =
std::fs::read_dir(dir)?.collect::<std::io::Result<Vec<_>>>()?;
entries.sort_by_key(|e| e.file_name());
for entry in entries {
let path = entry.path();
let file_type = entry.file_type()?;
if file_type.is_dir() {
let name = entry.file_name();
if BUILD_ID_SKIP_DIRS.contains(&name.to_string_lossy().as_ref()) {
continue;
}
collect(&path, files, dirs)?;
} else if file_type.is_file()
&& let Some(ext) = path.extension().and_then(|e| e.to_str())
&& BUILD_ID_EXTS.contains(&ext)
{
files.push(path);
}
}
Ok(())
}
pub(crate) fn content_id(root: &std::path::Path) -> Option<BuildIdScan> {
let crates = root.join("crates");
if !crates.is_dir() {
return None;
}
let mut files = Vec::new();
let mut dirs = Vec::new();
for name in BUILD_ID_ROOT_FILES {
let path = root.join(name);
if path.is_file() {
files.push(path);
}
}
collect(&crates, &mut files, &mut dirs).ok()?;
let mut keyed: Vec<(String, std::path::PathBuf)> = files
.into_iter()
.filter_map(|p| rel_key(root, &p).map(|k| (k, p)))
.collect();
keyed.sort();
keyed.dedup_by(|a, b| a.0 == b.0);
if keyed.is_empty() {
return None;
}
dirs.sort();
let mut h = FNV_OFFSET;
let mut hashed = Vec::with_capacity(keyed.len());
for (key, path) in keyed {
let bytes = std::fs::read(&path).ok()?;
h = fnv1a128(key.as_bytes(), h);
h = fnv1a128(&(bytes.len() as u64).to_le_bytes(), h);
h = fnv1a128(&bytes, h);
hashed.push(path);
}
Some(BuildIdScan {
id: render_build_id(h),
files: hashed,
dirs,
})
}
pub(crate) fn degraded_build_id(pkg_name: &str, pkg_version: &str) -> String {
let mut h = FNV_OFFSET;
h = fnv1a128(pkg_name.as_bytes(), h);
h = fnv1a128(b"\0", h);
h = fnv1a128(pkg_version.as_bytes(), h);
render_build_id(h)
}
pub(crate) fn fingerprint_is_well_formed(fp: &str) -> bool {
if fp.contains("unknown") {
return false;
}
let Some((head, id)) = fp.rsplit_once('-') else {
return false;
};
let Some(version) = head.strip_prefix("memra-") else {
return false;
};
let version_ok = version.starts_with(|c: char| c.is_ascii_digit())
&& version.split('.').count() >= 3
&& version
.chars()
.all(|c| c.is_ascii_alphanumeric() || c == '.' || c == '-' || c == '+');
let id_ok = id.len() == BUILD_ID_HEX
&& id
.chars()
.all(|c| c.is_ascii_digit() || ('a'..='f').contains(&c));
version_ok && id_ok
}