git: extract GitFetchImpl that holds implementation-specific objects

This could be a trait object, but we only need a single fetch() function per
implementation.
This commit is contained in:
Yuya Nishihara 2025-02-01 14:32:01 +09:00
parent 6e3c7fcf2d
commit 8cad3ac95a

View File

@ -1528,7 +1528,7 @@ struct FetchedBranches {
/// Helper struct to execute multiple `git fetch` operations /// Helper struct to execute multiple `git fetch` operations
pub struct GitFetch<'a> { pub struct GitFetch<'a> {
mut_repo: &'a mut MutableRepo, mut_repo: &'a mut MutableRepo,
git_repo: git2::Repository, fetch_impl: GitFetchImpl<'a>,
git_settings: &'a GitSettings, git_settings: &'a GitSettings,
fetched: Vec<FetchedBranches>, fetched: Vec<FetchedBranches>,
} }
@ -1538,10 +1538,10 @@ impl<'a> GitFetch<'a> {
mut_repo: &'a mut MutableRepo, mut_repo: &'a mut MutableRepo,
git_settings: &'a GitSettings, git_settings: &'a GitSettings,
) -> Result<Self, GitFetchPrepareError> { ) -> Result<Self, GitFetchPrepareError> {
let git_repo = get_git_backend(mut_repo.store())?.open_git_repo()?; let fetch_impl = GitFetchImpl::new(mut_repo.store(), git_settings)?;
Ok(GitFetch { Ok(GitFetch {
mut_repo, mut_repo,
git_repo, fetch_impl,
git_settings, git_settings,
fetched: vec![], fetched: vec![],
}) })
@ -1560,25 +1560,14 @@ impl<'a> GitFetch<'a> {
callbacks: RemoteCallbacks<'_>, callbacks: RemoteCallbacks<'_>,
depth: Option<NonZeroU32>, depth: Option<NonZeroU32>,
) -> Result<Option<String>, GitFetchError> { ) -> Result<Option<String>, GitFetchError> {
let default_branch = if self.git_settings.subprocess { let default_branch = self
subprocess_fetch( .fetch_impl
&self.git_repo, .fetch(remote_name, branch_names, callbacks, depth)?;
remote_name,
branch_names,
callbacks,
depth,
&self.git_settings.executable_path,
)
} else {
git2_fetch(&self.git_repo, remote_name, branch_names, callbacks, depth)
};
self.fetched.push(FetchedBranches { self.fetched.push(FetchedBranches {
remote: remote_name.to_string(), remote: remote_name.to_string(),
branches: branch_names.to_vec(), branches: branch_names.to_vec(),
}); });
Ok(default_branch)
default_branch
} }
/// Import the previously fetched remote-tracking branches into the jj repo /// Import the previously fetched remote-tracking branches into the jj repo
@ -1644,6 +1633,50 @@ fn expand_fetch_refspecs(
.collect() .collect()
} }
enum GitFetchImpl<'a> {
Git2 {
git_repo: git2::Repository,
},
Subprocess {
git_repo: git2::Repository,
git_ctx: GitSubprocessContext<'a>,
},
}
impl<'a> GitFetchImpl<'a> {
fn new(store: &Store, git_settings: &'a GitSettings) -> Result<Self, GitFetchPrepareError> {
let git_repo = get_git_backend(store)?.open_git_repo()?;
if git_settings.subprocess {
let git_ctx = GitSubprocessContext::from_git2(&git_repo, &git_settings.executable_path);
Ok(GitFetchImpl::Subprocess { git_repo, git_ctx })
} else {
Ok(GitFetchImpl::Git2 { git_repo })
}
}
fn fetch(
&self,
remote_name: &str,
branch_names: &[StringPattern],
callbacks: RemoteCallbacks<'_>,
depth: Option<NonZeroU32>,
) -> Result<Option<String>, GitFetchError> {
match self {
GitFetchImpl::Git2 { git_repo } => {
git2_fetch(git_repo, remote_name, branch_names, callbacks, depth)
}
GitFetchImpl::Subprocess { git_repo, git_ctx } => subprocess_fetch(
git_repo,
git_ctx,
remote_name,
branch_names,
callbacks,
depth,
),
}
}
}
fn git2_fetch( fn git2_fetch(
git_repo: &git2::Repository, git_repo: &git2::Repository,
remote_name: &str, remote_name: &str,
@ -1702,11 +1735,11 @@ fn git2_fetch(
fn subprocess_fetch( fn subprocess_fetch(
git_repo: &git2::Repository, git_repo: &git2::Repository,
git_ctx: &GitSubprocessContext,
remote_name: &str, remote_name: &str,
branch_names: &[StringPattern], branch_names: &[StringPattern],
mut callbacks: RemoteCallbacks<'_>, mut callbacks: RemoteCallbacks<'_>,
depth: Option<NonZeroU32>, depth: Option<NonZeroU32>,
git_executable_path: &Path,
) -> Result<Option<String>, GitFetchError> { ) -> Result<Option<String>, GitFetchError> {
// check the remote exists // check the remote exists
// TODO: we should ideally find a way to do this without git2 // TODO: we should ideally find a way to do this without git2
@ -1725,8 +1758,6 @@ fn subprocess_fetch(
return Ok(None); return Ok(None);
} }
let git_ctx = GitSubprocessContext::from_git2(git_repo, git_executable_path);
let mut branches_to_prune = Vec::new(); let mut branches_to_prune = Vec::new();
// git unfortunately errors out if one of the many refspecs is not found // git unfortunately errors out if one of the many refspecs is not found
// //