use std::path::PathBuf; use itertools::Itertools as _; use jacquard_common::types::did::Did; use crate::scratch::TempRepository; #[derive(Debug, Clone)] pub struct Layout { scan_path: PathBuf, } #[derive(Debug, thiserror::Error)] pub enum Error { #[error("repo not found")] RepoNotFound, #[error("open_scratch requires at least one repo")] NotEnoughRepos, #[error("scratch repo: {0}")] Io(#[from] std::io::Error), #[error("init scratch repo: {0}")] Init(#[from] gix::init::Error), #[error("open scratch repo: {0}")] Open(#[from] gix::open::Error), } impl Layout { pub fn new(scan_path: PathBuf) -> Self { Self { scan_path } } pub fn repo_path(&self, repo: &Did) -> PathBuf { // TODO: normalize DID like knot_git::Layout does. self.scan_path.join(repo.as_str()) } pub fn open(&self, repo: &Did) -> Result { gix::open(self.repo_path(repo)) } pub fn open_scratch(&self, dids: &[&Did]) -> Result { if dids.is_empty() { return Err(Error::NotEnoughRepos); } let alternates = dids .iter() .copied() .unique() .map(|did| { std::fs::canonicalize(self.repo_path(did).join("objects")) .map(|dir| format!("{}\n", dir.display())) .map_err(|_| Error::RepoNotFound) }) .collect::>()?; let scratch = tempfile::tempdir()?; gix::init_bare(scratch.path())?; let info_dir = scratch.path().join("objects").join("info"); std::fs::create_dir_all(&info_dir)?; std::fs::write(info_dir.join("alternates"), alternates)?; Ok(TempRepository::open(scratch)?) } }