Generalize Git URL handling and fix repository creation flow
This commit is contained in:
@@ -5,14 +5,14 @@ use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{Context as AnyhowContext, Error, anyhow, bail};
|
||||
use anyhow::{Error, anyhow, bail};
|
||||
use bitcoin_hashes::sha1::Hash as Sha1Hash;
|
||||
use gpui::{App, AppContext, Context, Entity, EventEmitter, Global, Task};
|
||||
use nostr::event::IntoEventBuilder;
|
||||
use nostr_connect::prelude::*;
|
||||
use nostr_sdk::client::SyncSummary;
|
||||
use nostr_sdk::prelude::*;
|
||||
use signed_core::{Announcement, RepoAddr, build_state, filters, identifier_from_name, repo_addr};
|
||||
use signed_core::{Announcement, RepoAddr, build_state, filters, identifier_from_name};
|
||||
use signed_nostr::{SignedAuthUrlHandler, UniversalSigner, Update};
|
||||
|
||||
use crate::git_store::GitStore;
|
||||
@@ -420,18 +420,27 @@ impl Backend {
|
||||
)));
|
||||
}
|
||||
|
||||
let addr = repo_addr(public_key, repo_id.clone());
|
||||
let cache = GitStore::global(cx).cache().clone();
|
||||
let path = cache.repo_path(&addr);
|
||||
let owner = public_key.to_bech32().unwrap();
|
||||
let servers = grasp_servers.clone();
|
||||
let client = self.client.clone();
|
||||
|
||||
// Initialize directly at the user's chosen destination.
|
||||
// No mirror is pre-populated: `GitCache::ensure_clone` lazily clones
|
||||
// from the grasp server the first time the repo detail view needs it,
|
||||
// exactly like every other repository.
|
||||
let destination = {
|
||||
let dir_name = signed_git::sanitize_path_component(&name);
|
||||
let dir_name = if dir_name.is_empty() {
|
||||
"repository".to_owned()
|
||||
} else {
|
||||
dir_name
|
||||
};
|
||||
folder.join(dir_name)
|
||||
};
|
||||
|
||||
cx.spawn(async move |this, cx| {
|
||||
// Initialize the local clone and create the user's working copy from it.
|
||||
let work = cx.background_spawn({
|
||||
let path = path.clone();
|
||||
let folder = folder.clone();
|
||||
let destination = destination.clone();
|
||||
let name = name.clone();
|
||||
let description = description.clone();
|
||||
let owner = owner.clone();
|
||||
@@ -439,53 +448,22 @@ impl Backend {
|
||||
let servers = servers.clone();
|
||||
|
||||
async move {
|
||||
let parent = path
|
||||
.parent()
|
||||
.ok_or_else(|| anyhow!("invalid repository path"))?;
|
||||
std::fs::create_dir_all(parent)?;
|
||||
let commit = signed_git::init_repository(&path, &name, &description)?;
|
||||
|
||||
// Point `origin` at the first grasp server.
|
||||
// Later fetches and pushes have a target, like ngit.
|
||||
if let Some(base) = servers.first().and_then(grasp_base_url) {
|
||||
let url = format!("{base}/{owner}/{repo_id}.git");
|
||||
signed_git::ensure_origin(&path, &url).ok();
|
||||
if destination.exists() {
|
||||
bail!("destination {} already exists", destination.display());
|
||||
}
|
||||
|
||||
// A working copy at `<folder>/<name>`, like the header's Clone action.
|
||||
// Cloned from the mirror above so it shares the announced history.
|
||||
// `origin` is set to the first grasp server, not the mirror path.
|
||||
let destination = {
|
||||
let dir_name = signed_git::sanitize_path_component(&name);
|
||||
let dir_name = if dir_name.is_empty() {
|
||||
"repository".to_owned()
|
||||
} else {
|
||||
dir_name
|
||||
};
|
||||
folder.join(dir_name)
|
||||
};
|
||||
|
||||
let mirror_url = Url::from_file_path(&path)
|
||||
.map_err(|_| anyhow!("invalid mirror path"))?
|
||||
.to_string();
|
||||
|
||||
signed_git::clone_repo(&[mirror_url], &destination).with_context(|| {
|
||||
format!(
|
||||
"failed to create the working copy at {}",
|
||||
destination.display()
|
||||
)
|
||||
})?;
|
||||
let commit = signed_git::init_repository(&destination, &name, &description)?;
|
||||
|
||||
if let Some(base) = servers.first().and_then(grasp_base_url) {
|
||||
let url = format!("{base}/{owner}/{repo_id}.git");
|
||||
signed_git::set_origin(&destination, &url)?;
|
||||
}
|
||||
|
||||
Ok::<_, Error>((commit, destination))
|
||||
Ok::<_, Error>(commit)
|
||||
}
|
||||
});
|
||||
|
||||
let (commit, checkout_path) = work.await?;
|
||||
let commit = work.await?;
|
||||
let commit_sha = Sha1Hash::from_str(&commit).map_err(|_| anyhow!("invalid id"))?;
|
||||
|
||||
// The nostr client queues events until each relay is connected.
|
||||
@@ -525,7 +503,7 @@ impl Backend {
|
||||
let push = cx.background_spawn({
|
||||
let client = client.clone();
|
||||
let signer = signer.clone();
|
||||
let path = path.clone();
|
||||
let destination = destination.clone();
|
||||
let owner = owner.clone();
|
||||
let repo_id = repo_id.clone();
|
||||
let servers = servers.clone();
|
||||
@@ -537,7 +515,7 @@ impl Backend {
|
||||
&repo_id,
|
||||
&refs,
|
||||
Some("main"),
|
||||
&path,
|
||||
&destination,
|
||||
&owner,
|
||||
&servers,
|
||||
signed_git::push_main,
|
||||
@@ -577,7 +555,7 @@ impl Backend {
|
||||
let announcement = Announcement::from_event(&event)
|
||||
.ok_or_else(|| anyhow!("failed to parse announcement"))?;
|
||||
|
||||
Ok((announcement, checkout_path))
|
||||
Ok((announcement, destination))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -999,10 +999,10 @@ impl RepoStore {
|
||||
let cache = GitStore::global(cx).cache().clone();
|
||||
let addr = self.addr.clone();
|
||||
|
||||
let clone_urls: Vec<String> = self
|
||||
let clone_urls: Vec<Url> = self
|
||||
.announcement
|
||||
.as_ref()
|
||||
.map(|a| a.clone.iter().map(ToString::to_string).collect())
|
||||
.map(|a| a.clone.clone())
|
||||
.unwrap_or_default();
|
||||
|
||||
let patch = pull_request_patch(root, self.patches.iter());
|
||||
@@ -1222,7 +1222,7 @@ impl RepoStore {
|
||||
return self.action_error("Repository announcement is not loaded yet", cx);
|
||||
};
|
||||
|
||||
let clone_urls: Vec<String> = announcement.clone.iter().map(ToString::to_string).collect();
|
||||
let clone_urls = announcement.clone.clone();
|
||||
let addr = self.addr.clone();
|
||||
|
||||
self.cloning = true;
|
||||
|
||||
Reference in New Issue
Block a user