use std::path::{Path, PathBuf};
use anyhow::{bail, Result};
pub fn root() -> Result<PathBuf> {
Ok(dirs::home_dir()
.ok_or_else(|| anyhow::anyhow!("Could not determine Arete cache directory"))?
.join(".arete")
.join("cache")
.join("registry")
.join("v1"))
}
pub fn file(root: &Path, kind: &str, hash: &str) -> Result<PathBuf> {
if hash.is_empty()
|| !hash
.bytes()
.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b':' | b'-' | b'_'))
{
bail!("Cannot cache invalid {kind} identity '{hash}'");
}
Ok(root.join(kind).join(format!("{hash}.json")))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn artifact_files_are_named_by_their_content_identity() {
let root = Path::new("/cache");
assert_eq!(
file(root, "live-spec", "arete:h1:live-spec:sha256:abc").unwrap(),
root.join("live-spec/arete:h1:live-spec:sha256:abc.json")
);
for hash in ["", "../escape", "a/b", "a b", "a.json"] {
assert!(file(root, "live-spec", hash).is_err(), "{hash:?}");
}
}
}