1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
use super::RepoDetails;
use super::Result;
pub use crate::repository::open::OpenRepositoryLike;
use crate::repository::{Direction, RealOpenRepository};
use derive_more::Deref as _;
use std::sync::{atomic::AtomicBool, Arc, RwLock};

#[mockall::automock]
pub trait RepositoryFactory: std::fmt::Debug + Sync + Send {
    fn duplicate(&self) -> Box<dyn RepositoryFactory>;
    fn open(&self, repo_details: &RepoDetails) -> Result<Box<dyn OpenRepositoryLike>>;
    fn git_clone(&self, repo_details: &RepoDetails) -> Result<Box<dyn OpenRepositoryLike>>;
}

pub fn real() -> Box<dyn RepositoryFactory> {
    Box::new(RealRepositoryFactory)
}

pub fn mock() -> Box<MockRepositoryFactory> {
    Box::new(MockRepositoryFactory::new())
}

#[derive(Debug, Clone)]
struct RealRepositoryFactory;

#[cfg(not(tarpaulin_include))] // requires network access to either clone new and/or fetch.
impl RepositoryFactory for RealRepositoryFactory {
    fn open(&self, repo_details: &RepoDetails) -> Result<Box<dyn OpenRepositoryLike>> {
        let repo = repo_details
            .open()
            .map_err(|e| crate::repository::Error::Open(e.to_string()))?;
        let found = repo.find_default_remote(Direction::Fetch);
        repo_details.assert_remote_url(found)?;

        Ok(Box::new(repo))
    }

    fn git_clone(&self, repo_details: &RepoDetails) -> Result<Box<dyn OpenRepositoryLike>> {
        tracing::info!("creating");
        use secrecy::ExposeSecret;
        let (gix_repo, _outcome) = gix::prepare_clone_bare(
            repo_details.origin().expose_secret().as_str(),
            repo_details.gitdir.deref(),
        )?
        .fetch_only(gix::progress::Discard, &AtomicBool::new(false))?;
        tracing::info!("created");
        let repo = RealOpenRepository::new(Arc::new(RwLock::new(gix_repo.into())));
        Ok(Box::new(repo))
    }

    fn duplicate(&self) -> Box<dyn RepositoryFactory> {
        Box::new(self.clone())
    }
}