diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2025-07-25 16:12:27 +0100 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2025-07-25 16:12:27 +0100 |
| commit | e89dbc142f5a0a517f197562f5f228681d9aed47 (patch) | |
| tree | 521dbec8d259f7c982345b40bb128a21795a2012 /src/bin/git_remote_nostr/fetch.rs | |
| parent | 419b827f7c0d826f5eedf574bce0cf9b85cab4ca (diff) | |
| parent | 0cad465dd3f78bd6c680067d12d396d4782829bf (diff) | |
Merge branch 'add-PR-feature-to-remote'
Diffstat (limited to 'src/bin/git_remote_nostr/fetch.rs')
| -rw-r--r-- | src/bin/git_remote_nostr/fetch.rs | 105 |
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 @@ | |||
| 1 | use core::str; | 1 | use core::str; |
| 2 | use std::{ | 2 | use 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 | ||
| 129 | async 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 | |||
| 88 | pub fn make_commits_for_proposal( | 159 | pub 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 | ||
| 131 | async fn fetch_open_or_draft_proposals( | 202 | async 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()?; |