1use git2::{Repository, RepositoryInitOptions};
6use std::path::{Path, PathBuf};
7
8use crate::git_config::DEFAULT_GIT_BRANCH;
9
10#[allow(dead_code)]
11#[derive(thiserror::Error, Debug)]
12pub(crate) enum PrepareLocalRepoError {
13 #[error("libgit2 Error {0}")]
14 Libgit2(#[from] git2::Error),
15}
16
17#[derive(Clone, Debug)]
24pub struct LocalRepositoryBuilder {
25 pub base_dir: PathBuf,
27 pub head: String,
29 pub description: Option<String>,
31}
32
33impl LocalRepositoryBuilder {
35 pub fn new(base_dir: &Path) -> Self {
37 LocalRepositoryBuilder {
38 base_dir: base_dir.to_path_buf(),
39 head: DEFAULT_GIT_BRANCH.to_string(),
40 description: None,
41 }
42 }
43
44 pub fn git_directory_is_initialized(&self, dir: &Path) -> bool {
47 let test_paths = [
48 dir.join("git-repository/HEAD"),
49 dir.join("git-repository/config"),
50 dir.join("git-repository/objects"),
51 ];
52 test_paths
53 .iter()
54 .all(|file_path| std::fs::metadata(file_path.as_path()).is_ok())
55 }
56
57 pub fn head(mut self, head: Option<String>) -> Self {
59 self.head = if let Some(head) = head {
60 head
61 } else {
62 DEFAULT_GIT_BRANCH.to_string()
63 };
64 self
65 }
66
67 pub fn description(mut self, description: Option<String>) -> Self {
69 self.description = description;
70 self
71 }
72
73 #[tracing::instrument(name = "local::build", skip_all)]
78 pub fn build(self, repo_path: &str) -> Result<(), git2::Error> {
79 let dir = PathBuf::from(format!(
80 "{}/{}/git-repository",
81 self.base_dir.display(),
82 repo_path
83 ));
84 if !self.git_directory_is_initialized(&dir) {
85 tracing::debug!("Creating repository at {:?}...", &dir);
86
87 let mut opts = RepositoryInitOptions::new();
88 opts.bare(true);
89 opts.workdir_path(&dir);
90 opts.initial_head(&self.head);
91 if let Some(description) = self.description {
92 opts.description(&description);
93 }
94
95 let repo = Repository::init_opts(dir, &opts)?;
96 repo.config()?.set_bool("lorry.managed", true)?;
97 }
98 Ok(())
99 }
100}
101
102#[cfg(test)]
103mod test {
104
105 use tempfile::tempdir;
106
107 use crate::local::LocalRepositoryBuilder;
108
109 #[tokio::test]
110 async fn test_initialize_local_repository() {
111 let temp_dir = tempdir().unwrap();
112 let path = temp_dir.path().join("a/asdf/mirrors");
113 let repo_path = "foo/bar";
114 LocalRepositoryBuilder::new(&path).build(repo_path).unwrap();
115
116 assert!(path.join("foo/bar/git-repository/HEAD").exists());
117 assert!(path.join("foo/bar/git-repository/description").exists());
118 assert!(path.join("foo/bar/git-repository/refs/heads").exists())
119 }
120}