upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/bin/git_remote_nostr/fetch.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/git_remote_nostr/fetch.rs')
-rw-r--r--src/bin/git_remote_nostr/fetch.rs105
1 files changed, 92 insertions, 13 deletions
diff --git a/src/bin/git_remote_nostr/fetch.rs b/src/bin/git_remote_nostr/fetch.rs
index b191850..f3d4362 100644
--- a/src/bin/git_remote_nostr/fetch.rs
+++ b/src/bin/git_remote_nostr/fetch.rs
@@ -1,6 +1,6 @@
1use core::str; 1use core::str;
2use std::{ 2use std::{
3 collections::HashMap, 3 collections::{HashMap, HashSet},
4 io::Stdin, 4 io::Stdin,
5 sync::{Arc, Mutex}, 5 sync::{Arc, Mutex},
6 time::Instant, 6 time::Instant,
@@ -16,7 +16,7 @@ use ngit::{
16 nostr_url::{CloneUrl, NostrUrlDecoded, ServerProtocol}, 16 nostr_url::{CloneUrl, NostrUrlDecoded, ServerProtocol},
17 utils::check_ssh_keys, 17 utils::check_ssh_keys,
18 }, 18 },
19 git_events::tag_value, 19 git_events::{KIND_PULL_REQUEST, KIND_PULL_REQUEST_UPDATE, tag_value},
20 login::get_curent_user, 20 login::get_curent_user,
21 repo_ref::{RepoRef, is_grasp_server}, 21 repo_ref::{RepoRef, is_grasp_server},
22}; 22};
@@ -37,38 +37,78 @@ pub async fn run_fetch(
37) -> Result<()> { 37) -> Result<()> {
38 let mut fetch_batch = get_oids_from_fetch_batch(stdin, oid, refstr)?; 38 let mut fetch_batch = get_oids_from_fetch_batch(stdin, oid, refstr)?;
39 39
40 let oids_from_git_servers = fetch_batch 40 let oids_from_state = fetch_batch
41 .iter() 41 .iter()
42 .filter(|(refstr, _)| !refstr.contains("refs/heads/pr/")) 42 .filter(|(refstr, _)| !refstr.contains("refs/heads/pr/"))
43 .map(|(_, oid)| oid.clone()) 43 .map(|(_, oid)| oid.clone())
44 .collect::<Vec<String>>(); 44 .collect::<Vec<String>>();
45 45
46 let pr_oid_clone_url_map = identify_clone_urls_for_oids_from_pr_pr_update_events(
47 fetch_batch.values().collect::<Vec<&String>>(),
48 git_repo,
49 repo_ref,
50 )
51 .await?;
52
53 let oids_to_fetch_from_git_servers = [
54 oids_from_state.clone(),
55 pr_oid_clone_url_map
56 .keys()
57 .cloned()
58 .collect::<Vec<String>>(),
59 ]
60 .concat();
61
62 let git_servers = {
63 let mut seen: HashSet<String> = HashSet::new();
64 let mut out: Vec<String> = vec![];
65 for server in &repo_ref.git_server {
66 if seen.insert(server.clone()) {
67 out.push(server.clone());
68 }
69 }
70 for url in pr_oid_clone_url_map.values().flatten() {
71 if seen.insert(url.clone()) {
72 out.push(url.clone());
73 }
74 }
75 out
76 };
77
46 let mut errors = vec![]; 78 let mut errors = vec![];
47 let term = console::Term::stderr(); 79 let term = console::Term::stderr();
48 80
49 for git_server_url in &repo_ref.git_server { 81 for git_server_url in &git_servers {
82 let oids_to_fetch_from_server = oids_to_fetch_from_git_servers
83 .clone()
84 .into_iter()
85 .filter(|oid| !git_repo.does_commit_exist(oid).unwrap_or(false))
86 .collect::<Vec<String>>();
87
88 if oids_to_fetch_from_server.is_empty() {
89 continue;
90 }
91
50 let term = console::Term::stderr(); 92 let term = console::Term::stderr();
51 if let Err(error) = fetch_from_git_server( 93 if let Err(error) = fetch_from_git_server(
52 git_repo, 94 git_repo,
53 &oids_from_git_servers, 95 &oids_from_state,
54 git_server_url, 96 git_server_url,
55 &repo_ref.to_nostr_git_url(&None), 97 &repo_ref.to_nostr_git_url(&None),
56 &term, 98 &term,
57 is_grasp_server(git_server_url, &repo_ref.grasp_servers()), 99 is_grasp_server(git_server_url, &repo_ref.grasp_servers()),
58 ) { 100 ) {
59 errors.push(error); 101 errors.push(error);
60 } else {
61 break;
62 } 102 }
63 } 103 }
64 104
65 if oids_from_git_servers 105 if oids_from_state
66 .iter() 106 .iter()
67 .any(|oid| !git_repo.does_commit_exist(oid).unwrap()) 107 .any(|oid| !git_repo.does_commit_exist(oid).unwrap())
68 && !errors.is_empty() 108 && !errors.is_empty()
69 { 109 {
70 bail!( 110 bail!(
71 "fetch: failed to fetch objects in nostr state event from:\r\n{}", 111 "fetch: failed to fetch objects from:\r\n{}",
72 errors 112 errors
73 .iter() 113 .iter()
74 .map(|e| format!(" - {e}")) 114 .map(|e| format!(" - {e}"))
@@ -79,12 +119,43 @@ pub async fn run_fetch(
79 119
80 fetch_batch.retain(|refstr, _| refstr.contains("refs/heads/pr/")); 120 fetch_batch.retain(|refstr, _| refstr.contains("refs/heads/pr/"));
81 121
82 fetch_open_or_draft_proposals(git_repo, &term, repo_ref, &fetch_batch).await?; 122 fetch_open_or_draft_proposals_from_patches(git_repo, &term, repo_ref, &fetch_batch).await?;
123 // TODO fetch_open_or_draft_proposals just needs to do it for patches
83 term.flush()?; 124 term.flush()?;
84 println!(); 125 println!();
85 Ok(()) 126 Ok(())
86} 127}
87 128
129async fn identify_clone_urls_for_oids_from_pr_pr_update_events(
130 oids: Vec<&String>,
131 git_repo: &Repo,
132 repo_ref: &RepoRef,
133) -> Result<HashMap<String, Vec<String>>> {
134 let mut map: HashMap<String, Vec<String>> = HashMap::new();
135
136 let open_and_draft_proposals = get_open_or_draft_proposals(git_repo, repo_ref).await?;
137
138 for (_, (_, events)) in open_and_draft_proposals {
139 for event in events {
140 if [KIND_PULL_REQUEST, KIND_PULL_REQUEST_UPDATE].contains(&event.kind) {
141 if let Ok(c) = tag_value(&event, "c") {
142 if oids.contains(&&c) {
143 for tag in event.tags.as_slice() {
144 if tag.kind().eq(&nostr::event::TagKind::Clone) {
145 for clone_url in tag.as_slice().iter().skip(1) {
146 map.entry(c.clone()).or_default().push(clone_url.clone());
147 }
148 }
149 }
150 }
151 }
152 }
153 }
154 }
155
156 Ok(map)
157}
158
88pub fn make_commits_for_proposal( 159pub fn make_commits_for_proposal(
89 git_repo: &Repo, 160 git_repo: &Repo,
90 repo_ref: &RepoRef, 161 repo_ref: &RepoRef,
@@ -128,7 +199,7 @@ pub fn make_commits_for_proposal(
128 Ok(tip_commit_id) 199 Ok(tip_commit_id)
129} 200}
130 201
131async fn fetch_open_or_draft_proposals( 202async fn fetch_open_or_draft_proposals_from_patches(
132 git_repo: &Repo, 203 git_repo: &Repo,
133 term: &console::Term, 204 term: &console::Term,
134 repo_ref: &RepoRef, 205 repo_ref: &RepoRef,
@@ -140,12 +211,19 @@ async fn fetch_open_or_draft_proposals(
140 let current_user = get_curent_user(git_repo)?; 211 let current_user = get_curent_user(git_repo)?;
141 212
142 for refstr in proposal_refs.keys() { 213 for refstr in proposal_refs.keys() {
143 if let Some((_, (_, patches))) = find_proposal_and_patches_by_branch_name( 214 if let Some((_, (_, events_to_apply))) = find_proposal_and_patches_by_branch_name(
144 refstr, 215 refstr,
145 &open_and_draft_proposals, 216 &open_and_draft_proposals,
146 current_user.as_ref(), 217 current_user.as_ref(),
147 ) { 218 ) {
148 if let Err(error) = make_commits_for_proposal(git_repo, repo_ref, patches) { 219 if events_to_apply
220 .iter()
221 .any(|e| e.kind.eq(&KIND_PULL_REQUEST) || e.kind.eq(&KIND_PULL_REQUEST_UPDATE))
222 {
223 // do nothing - we fetch these oids as part of run_fetch
224 } else if let Err(error) =
225 make_commits_for_proposal(git_repo, repo_ref, events_to_apply)
226 {
149 term.write_line( 227 term.write_line(
150 format!("WARNING: failed to create branch for {refstr}, error: {error}",) 228 format!("WARNING: failed to create branch for {refstr}, error: {error}",)
151 .as_str(), 229 .as_str(),
@@ -429,6 +507,7 @@ fn fetch_from_git_server_url(
429 remote_callbacks.credentials(auth.credentials(&git_config)); 507 remote_callbacks.credentials(auth.credentials(&git_config));
430 } 508 }
431 fetch_options.remote_callbacks(remote_callbacks); 509 fetch_options.remote_callbacks(remote_callbacks);
510
432 git_server_remote.download(oids, Some(&mut fetch_options))?; 511 git_server_remote.download(oids, Some(&mut fetch_options))?;
433 512
434 git_server_remote.disconnect()?; 513 git_server_remote.disconnect()?;