use crate::{git, lockfile::LockedSkill, paths};
use anyhow::{bail, Result};
use std::path::PathBuf;
pub struct Ensured {
pub path: PathBuf,
pub fetched: bool,
}
pub fn ensure(locked: &LockedSkill) -> Result<Ensured> {
let repo_dir = paths::store_dir()?.join(&locked.store);
let fetched = !git::is_at_commit(&repo_dir, &locked.commit);
if fetched {
if repo_dir.exists() {
std::fs::remove_dir_all(&repo_dir)?;
}
std::fs::create_dir_all(repo_dir.parent().unwrap())?;
git::fetch_commit(&locked.git, &locked.commit, &repo_dir)?;
}
let content = match &locked.path {
Some(sub) => repo_dir.join(sub),
None => repo_dir.clone(),
};
if !content.exists() {
bail!(
"path `{}` not found in {}@{}",
locked.path.as_deref().unwrap_or("."),
locked.git,
&locked.commit[..locked.commit.len().min(8)]
);
}
let repo_canon = repo_dir.canonicalize()?;
let content_canon = content.canonicalize()?;
if !content_canon.starts_with(&repo_canon) {
bail!(
"path `{}` escapes the repository checkout for {}",
locked.path.as_deref().unwrap_or("."),
locked.git
);
}
Ok(Ensured {
path: content_canon,
fetched,
})
}