diff --git a/gitmirror/src/git.rs b/gitmirror/src/git.rs index c668e1940..74135c1c9 100644 --- a/gitmirror/src/git.rs +++ b/gitmirror/src/git.rs @@ -16,8 +16,9 @@ pub(crate) struct TempRepository { } impl TempRepository { - fn new(repo: gix::Repository, dir: TempDir) -> Self { - Self { repo, _dir: dir } + pub fn open(dir: TempDir) -> Result { + let repo = gix::open(dir.path())?.with_object_memory(); + Ok(Self { repo, _dir: dir }) } } @@ -72,10 +73,7 @@ pub(crate) fn open_scratch( .join("\n"); std::fs::write(info_dir.join("alternates"), format!("{alternates}\n")).map_err(internal)?; - let repo = gix::open(scratch.path()) - .map_err(|e| XrpcError::Internal(e.to_string()))? - .with_object_memory(); - Ok(TempRepository::new(repo, scratch)) + TempRepository::open(scratch).map_err(|e| XrpcError::Internal(e.to_string())) } pub(crate) fn commit_log_walk<'repo>( @@ -125,8 +123,7 @@ mod tests { fn temp_repository_removes_scratch_dir_on_drop() { let dir = tempfile::tempdir().unwrap(); gix::init_bare(dir.path()).unwrap(); - let repo = gix::open(dir.path()).unwrap().with_object_memory(); - let temp = TempRepository::new(repo, dir); + let temp = TempRepository::open(dir).unwrap(); let path = temp.git_dir().to_path_buf(); assert!(path.exists()); // Derefs to gix::Repository. diff --git a/gitmirror/src/layout.rs b/gitmirror/src/layout.rs new file mode 100644 index 000000000..d0a097a1d --- /dev/null +++ b/gitmirror/src/layout.rs @@ -0,0 +1,58 @@ +use std::path::PathBuf; + +use jacquard_common::types::did::Did; +use tracing::error; + +use crate::git::TempRepository; + +#[derive(Debug, Clone)] +pub(crate) struct Layout { + scan_path: PathBuf, +} + +impl Layout { + pub fn new(scan_path: PathBuf) -> Self { + Self { scan_path } + } + + pub fn repo_path(&self, repo: &Did) -> PathBuf { + self.scan_path.join(repo.to_lowercase().as_str()) + } + + pub fn open_scratch(&self, dids: &[&Did]) -> anyhow::Result> { + let mut seen: Vec<&Did> = Vec::new(); + let mut object_dirs = Vec::new(); + for &did in dids { + if seen.contains(&did) { + continue; + } + seen.push(did); + let object_dir = match std::fs::canonicalize(self.repo_path(did).join("objects")) { + Ok(path) => path, + Err(err) => { + error!(error = %err, "repo not found"); + return Ok(None); + }, + }; + object_dirs.push(object_dir); + } + if object_dirs.is_empty() { + return Err(anyhow::anyhow!( + "open_scratch requires at least one repo".to_owned(), + )); + } + 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)?; + let alternates = object_dirs + .iter() + .map(|p| p.display().to_string()) + .collect::>() + .join("\n"); + std::fs::write(info_dir.join("alternates"), format!("{alternates}\n"))?; + + Ok(Some(TempRepository::open(scratch)?)) + } +} diff --git a/gitmirror/src/main.rs b/gitmirror/src/main.rs index f57f9d9b3..ef22364ff 100644 --- a/gitmirror/src/main.rs +++ b/gitmirror/src/main.rs @@ -5,6 +5,7 @@ use clap::{Parser, Subcommand}; mod diff; mod git; +mod layout; mod merge; mod xrpc;