Generalize Git URL handling and fix repository creation flow

This commit is contained in:
2026-09-10 07:56:33 +07:00
parent 18433ec239
commit 0e9f0a33ac
7 changed files with 94 additions and 75 deletions
+15 -9
View File
@@ -44,7 +44,11 @@ impl GitCache {
}
/// Open the existing clone, fetching it first.
pub fn ensure_clone(&self, addr: &RepoAddr, clone_urls: &[String]) -> Result<gix::Repository> {
pub fn ensure_clone<U: AsRef<str>>(
&self,
addr: &RepoAddr,
clone_urls: &[U],
) -> Result<gix::Repository> {
let path = self.repo_path(addr);
if let Some(repo) = self.open(addr)? {
@@ -122,7 +126,7 @@ pub fn find_git_repos(root: &Path) -> Vec<PathBuf> {
/// Clone into `path` from the first working URL in `clone_urls`.
///
/// Unlike [`GitCache::ensure_clone`], the clone is not kept in any cache.
pub fn clone_repo(clone_urls: &[String], path: &Path) -> Result<()> {
pub fn clone_repo<U: AsRef<str>>(clone_urls: &[U], path: &Path) -> Result<()> {
if path.exists() {
bail!("destination {} already exists", path.display());
}
@@ -347,14 +351,14 @@ fn transport_url(url: &str) -> String {
///
/// Returns the last error wrapped in `failed to {verb} from any mirror`,
/// or `no clone URLs provided` when the list is empty.
fn try_each_url<F>(urls: &[String], verb: &str, mut attempt: F) -> Result<()>
fn try_each_url<U: AsRef<str>, F>(urls: &[U], verb: &str, mut attempt: F) -> Result<()>
where
F: FnMut(&str) -> Result<()>,
{
let mut last_err: Option<anyhow::Error> = None;
for url in urls {
match attempt(url) {
match attempt(url.as_ref()) {
Ok(()) => return Ok(()),
Err(e) => last_err = Some(e),
}
@@ -698,7 +702,7 @@ fn edit_local_config(
/// When no URL works, the last error is returned.
///
/// Never touches the checked-out refs or the worktree.
pub fn fetch_repo_refs(repo_path: &Path, urls: &[String], refspec: &str) -> Result<()> {
pub fn fetch_repo_refs<U: AsRef<str>>(repo_path: &Path, urls: &[U], refspec: &str) -> Result<()> {
let repo = gix::open(repo_path)?;
let refspec = gix::refspec::parse(
gix::bstr::BStr::new(refspec),
@@ -2950,9 +2954,10 @@ mod tests {
#[test]
fn working_copy_cloned_from_the_mirror_matches_head_and_origin() {
// The mirror is a freshly initialized repository.
// Its `origin` points at the grasp server.
// `Backend::create_repository` leaves it in the GitCache.
// The mirror is a freshly initialized repository, standing in for
// the grasp server. Its `origin` points at the (fake) grasp server.
// `GitCache::ensure_clone` lazily clones from a URL shaped like this
// the first time a repository is opened.
let dir = tempfile::tempdir().expect("tempdir");
let mirror = dir.path().join("mirror");
let commit = init_repository(&mirror, "My Repo", "Does things.").expect("init");
@@ -3166,7 +3171,8 @@ mod tests {
assert!(err.to_string().contains("failed to fetch"));
// Without any URL there is nothing to try.
let err = fetch_repo_refs(dir, &[], "+refs/heads/*:refs/fork/x/*").expect_err("no URLs");
let err = fetch_repo_refs(dir, &[] as &[String], "+refs/heads/*:refs/fork/x/*")
.expect_err("no URLs");
assert!(err.to_string().contains("no clone URLs"));
}