git-next-core 0.14.1

core for git-next, the trunk-based development manager
Documentation
//
use crate::{
    git::{
        self,
        repository::{
            open::{oreal::RealOpenRepository, OpenRepositoryLike},
            Direction, Result,
        },
        RepoDetails,
    },
    s,
};

use secrecy::ExposeSecret as _;

use std::sync::{atomic::AtomicBool, Arc, RwLock};

#[allow(clippy::module_name_repetitions)]
#[mockall::automock]
pub trait RepositoryFactory: std::fmt::Debug + Sync + Send {
    fn duplicate(&self) -> Box<dyn RepositoryFactory>;

    /// Opens the repository.
    ///
    /// # Errors
    ///
    /// Will return an `Err` if the repository can't be opened.
    fn open(&self, repo_details: &RepoDetails) -> Result<Box<dyn OpenRepositoryLike>>;

    /// Clones the git repository from the remote server.
    ///
    /// # Errors
    ///
    /// Will return an `Err` if there are any network connectivity issues
    /// connecting with the server.
    fn git_clone(&self, repo_details: &RepoDetails) -> Result<Box<dyn OpenRepositoryLike>>;
}

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

#[must_use]
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| git::repository::Error::Open(s!(e)))?;
        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");
        let (gix_repo, _outcome) =
            gix::prepare_clone_bare(repo_details.origin().expose_secret(), &*repo_details.gitdir)?
                .fetch_only(gix::progress::Discard, &AtomicBool::new(false))?;
        tracing::info!("created");
        let repo = RealOpenRepository::new(
            Arc::new(RwLock::new(gix_repo.into())),
            repo_details.forge.clone(),
        );
        Ok(Box::new(repo))
    }

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