diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2024-09-04 16:44:43 +0100 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2024-09-04 17:01:07 +0100 |
| commit | c4c262a5e9bfeb30bc0106d9ea51dfce7e4fa1f3 (patch) | |
| tree | d02ba9ab1d461147c6ae2ae5e98e785c553a999f /src/bin/git_remote_nostr/fetch.rs | |
| parent | 90c53e2dc859b47615ebaa08199b7460615ce3e4 (diff) | |
refactor(remote): split into modules
to make it easier to read
Diffstat (limited to 'src/bin/git_remote_nostr/fetch.rs')
| -rw-r--r-- | src/bin/git_remote_nostr/fetch.rs | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/src/bin/git_remote_nostr/fetch.rs b/src/bin/git_remote_nostr/fetch.rs new file mode 100644 index 0000000..5fd8816 --- /dev/null +++ b/src/bin/git_remote_nostr/fetch.rs | |||
| @@ -0,0 +1,145 @@ | |||
| 1 | use std::{collections::HashMap, io::Stdin}; | ||
| 2 | |||
| 3 | use anyhow::{anyhow, bail, Result}; | ||
| 4 | use auth_git2::GitAuthenticator; | ||
| 5 | use git2::Repository; | ||
| 6 | use ngit::{ | ||
| 7 | git::{Repo, RepoActions}, | ||
| 8 | git_events::tag_value, | ||
| 9 | login::get_curent_user, | ||
| 10 | repo_ref::RepoRef, | ||
| 11 | }; | ||
| 12 | |||
| 13 | use crate::utils::{ | ||
| 14 | find_proposal_and_patches_by_branch_name, get_oids_from_fetch_batch, get_open_proposals, | ||
| 15 | get_short_git_server_name, switch_clone_url_between_ssh_and_https, | ||
| 16 | }; | ||
| 17 | |||
| 18 | pub async fn run_fetch( | ||
| 19 | git_repo: &Repo, | ||
| 20 | repo_ref: &RepoRef, | ||
| 21 | stdin: &Stdin, | ||
| 22 | oid: &str, | ||
| 23 | refstr: &str, | ||
| 24 | ) -> Result<()> { | ||
| 25 | let mut fetch_batch = get_oids_from_fetch_batch(stdin, oid, refstr)?; | ||
| 26 | |||
| 27 | let oids_from_git_servers = fetch_batch | ||
| 28 | .iter() | ||
| 29 | .filter(|(refstr, _)| !refstr.contains("refs/heads/pr/")) | ||
| 30 | .map(|(_, oid)| oid.clone()) | ||
| 31 | .collect::<Vec<String>>(); | ||
| 32 | |||
| 33 | let mut errors = HashMap::new(); | ||
| 34 | let term = console::Term::stderr(); | ||
| 35 | |||
| 36 | for git_server_url in &repo_ref.git_server { | ||
| 37 | let term = console::Term::stderr(); | ||
| 38 | let short_name = get_short_git_server_name(git_repo, git_server_url); | ||
| 39 | term.write_line(format!("fetching from {short_name}...").as_str())?; | ||
| 40 | let res = fetch_from_git_server(&git_repo.git_repo, &oids_from_git_servers, git_server_url); | ||
| 41 | term.clear_last_lines(1)?; | ||
| 42 | if let Err(error1) = res { | ||
| 43 | if let Ok(alternative_url) = switch_clone_url_between_ssh_and_https(git_server_url) { | ||
| 44 | let res2 = fetch_from_git_server( | ||
| 45 | &git_repo.git_repo, | ||
| 46 | &oids_from_git_servers, | ||
| 47 | &alternative_url, | ||
| 48 | ); | ||
| 49 | if let Err(error2) = res2 { | ||
| 50 | term.write_line( | ||
| 51 | format!( | ||
| 52 | "WARNING: failed to fetch from {short_name} error:{error1}\r\nand using alternative protocol {alternative_url}: {error2}" | ||
| 53 | ).as_str() | ||
| 54 | )?; | ||
| 55 | errors.insert( | ||
| 56 | short_name.to_string(), | ||
| 57 | anyhow!( | ||
| 58 | "{error1} and using alternative protocol {alternative_url}: {error2}" | ||
| 59 | ), | ||
| 60 | ); | ||
| 61 | } else { | ||
| 62 | break; | ||
| 63 | } | ||
| 64 | } else { | ||
| 65 | term.write_line( | ||
| 66 | format!("WARNING: failed to fetch from {short_name} error:{error1}").as_str(), | ||
| 67 | )?; | ||
| 68 | errors.insert(short_name.to_string(), error1); | ||
| 69 | } | ||
| 70 | } else { | ||
| 71 | break; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | if oids_from_git_servers | ||
| 76 | .iter() | ||
| 77 | .any(|oid| !git_repo.does_commit_exist(oid).unwrap()) | ||
| 78 | && !errors.is_empty() | ||
| 79 | { | ||
| 80 | bail!( | ||
| 81 | "failed to fetch objects in nostr state event from:\r\n{}", | ||
| 82 | errors | ||
| 83 | .iter() | ||
| 84 | .map(|(url, error)| format!("{url}: {error}")) | ||
| 85 | .collect::<Vec<String>>() | ||
| 86 | .join("\r\n") | ||
| 87 | ); | ||
| 88 | } | ||
| 89 | |||
| 90 | fetch_batch.retain(|refstr, _| refstr.contains("refs/heads/pr/")); | ||
| 91 | |||
| 92 | if !fetch_batch.is_empty() { | ||
| 93 | let open_proposals = get_open_proposals(git_repo, repo_ref).await?; | ||
| 94 | |||
| 95 | let current_user = get_curent_user(git_repo)?; | ||
| 96 | |||
| 97 | for (refstr, oid) in fetch_batch { | ||
| 98 | if let Some((_, (_, patches))) = | ||
| 99 | find_proposal_and_patches_by_branch_name(&refstr, &open_proposals, ¤t_user) | ||
| 100 | { | ||
| 101 | if !git_repo.does_commit_exist(&oid)? { | ||
| 102 | let mut patches_ancestor_first = patches.clone(); | ||
| 103 | patches_ancestor_first.reverse(); | ||
| 104 | if git_repo.does_commit_exist(&tag_value( | ||
| 105 | patches_ancestor_first.first().unwrap(), | ||
| 106 | "parent-commit", | ||
| 107 | )?)? { | ||
| 108 | for patch in &patches_ancestor_first { | ||
| 109 | git_repo.create_commit_from_patch(patch)?; | ||
| 110 | } | ||
| 111 | } else { | ||
| 112 | term.write_line( | ||
| 113 | format!("WARNING: cannot find parent commit for {refstr}").as_str(), | ||
| 114 | )?; | ||
| 115 | } | ||
| 116 | } | ||
| 117 | } else { | ||
| 118 | term.write_line(format!("WARNING: cannot find proposal for {refstr}").as_str())?; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | term.flush()?; | ||
| 124 | println!(); | ||
| 125 | Ok(()) | ||
| 126 | } | ||
| 127 | |||
| 128 | fn fetch_from_git_server( | ||
| 129 | git_repo: &Repository, | ||
| 130 | oids: &[String], | ||
| 131 | git_server_url: &str, | ||
| 132 | ) -> Result<()> { | ||
| 133 | let git_config = git_repo.config()?; | ||
| 134 | |||
| 135 | let mut git_server_remote = git_repo.remote_anonymous(git_server_url)?; | ||
| 136 | // authentication may be required (and will be requird if clone url is ssh) | ||
| 137 | let auth = GitAuthenticator::default(); | ||
| 138 | let mut fetch_options = git2::FetchOptions::new(); | ||
| 139 | let mut remote_callbacks = git2::RemoteCallbacks::new(); | ||
| 140 | remote_callbacks.credentials(auth.credentials(&git_config)); | ||
| 141 | fetch_options.remote_callbacks(remote_callbacks); | ||
| 142 | git_server_remote.download(oids, Some(&mut fetch_options))?; | ||
| 143 | git_server_remote.disconnect()?; | ||
| 144 | Ok(()) | ||
| 145 | } | ||