use std::collections::BTreeMap;
use std::path::PathBuf;
use anyhow::{Result, anyhow};
use crate::workspace::descriptor::{RepoSource, WorkspaceDescriptor};
pub fn git_cache_dir(workspace_name: &str, repo_name: &str) -> Result<PathBuf> {
let base = if let Some(d) = std::env::var_os("NORNIR_CACHE_DIR") {
PathBuf::from(d)
} else if let Some(d) = std::env::var_os("XDG_CACHE_HOME") {
PathBuf::from(d).join("nornir")
} else if let Some(home) = std::env::var_os("HOME") {
PathBuf::from(home).join(".cache").join("nornir")
} else {
return Err(anyhow!("no $HOME and no $NORNIR_CACHE_DIR — can't pick cache dir"));
};
Ok(base.join("workspaces").join(workspace_name).join(repo_name))
}
pub fn resolve_sources(desc: &WorkspaceDescriptor) -> Result<BTreeMap<String, PathBuf>> {
let mut out = BTreeMap::new();
for (name, src) in desc.sources()? {
let path = match src {
RepoSource::Path(p) => p,
RepoSource::Git { url, branch } => {
let cache = git_cache_dir(&desc.workspace.name, &name)?;
if !cache.join(".git").exists() {
let br = branch
.as_deref()
.map(|b| format!(" --branch {b}"))
.unwrap_or_default();
return Err(anyhow!(
"repo `{name}` is git-sourced and not yet in cache.\n\
Bootstrap once with:\n\
mkdir -p {parent}\n\
git clone{br} {url} {cache}\n\
(network clone via gix is not yet wired; \
once it is, `nornir workspace fetch {name}` will do this for you.)",
parent = cache.parent().unwrap().display(),
cache = cache.display(),
));
}
cache
}
};
out.insert(name, path);
}
Ok(out)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cache_dir_respects_explicit_env() {
let prev = std::env::var_os("NORNIR_CACHE_DIR");
unsafe { std::env::set_var("NORNIR_CACHE_DIR", "/tmp/nornir-cache-test"); }
let d = git_cache_dir("ws1", "repo1").unwrap();
assert_eq!(d, PathBuf::from("/tmp/nornir-cache-test/workspaces/ws1/repo1"));
unsafe {
match prev {
Some(v) => std::env::set_var("NORNIR_CACHE_DIR", v),
None => std::env::remove_var("NORNIR_CACHE_DIR"),
}
}
}
}