use sha2::{Digest, Sha256};
pub fn derive_subtree_cache_key(
ecosystem: &str,
package_name: &str,
resolved_version: &str,
transitive_dep_hashes: &[String],
target_arch_triple: &str,
) -> String {
let mut sorted_deps = transitive_dep_hashes.to_vec();
sorted_deps.sort();
let mut merkle_hasher = Sha256::new();
for dep_hash in &sorted_deps {
merkle_hasher.update(dep_hash.as_bytes());
}
let merkle_root = hex::encode(merkle_hasher.finalize());
let raw = format!(
"{}:{}:{}:{}:{}",
ecosystem, package_name, resolved_version, merkle_root, target_arch_triple
);
let mut hasher = Sha256::new();
hasher.update(raw.as_bytes());
format!("sha256:{}", hex::encode(hasher.finalize()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_subtree_cache_key_determinism() {
let deps = vec!["sha256:dep1".to_string(), "sha256:dep2".to_string()];
let key1 = derive_subtree_cache_key(
"python",
"torch",
"2.1.0",
&deps,
"x86_64-unknown-linux-gnu",
);
let key2 = derive_subtree_cache_key(
"python",
"torch",
"2.1.0",
&deps,
"x86_64-unknown-linux-gnu",
);
assert_eq!(key1, key2);
assert!(key1.starts_with("sha256:"));
}
}