diff options
Diffstat (limited to 'src/bin/git_remote_nostr/fetch.rs')
| -rw-r--r-- | src/bin/git_remote_nostr/fetch.rs | 116 |
1 files changed, 34 insertions, 82 deletions
diff --git a/src/bin/git_remote_nostr/fetch.rs b/src/bin/git_remote_nostr/fetch.rs index 6836456..f591fed 100644 --- a/src/bin/git_remote_nostr/fetch.rs +++ b/src/bin/git_remote_nostr/fetch.rs | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | use std::io::Stdin; | 1 | use std::io::Stdin; |
| 2 | 2 | ||
| 3 | use anyhow::{anyhow, bail, Context, Result}; | 3 | use anyhow::{bail, Result}; |
| 4 | use auth_git2::GitAuthenticator; | 4 | use auth_git2::GitAuthenticator; |
| 5 | use git2::Repository; | 5 | use git2::Repository; |
| 6 | use ngit::{ | 6 | use ngit::{ |
| @@ -16,6 +16,7 @@ use ngit::{ | |||
| 16 | 16 | ||
| 17 | use crate::utils::{ | 17 | use crate::utils::{ |
| 18 | find_proposal_and_patches_by_branch_name, get_oids_from_fetch_batch, get_open_proposals, | 18 | find_proposal_and_patches_by_branch_name, get_oids_from_fetch_batch, get_open_proposals, |
| 19 | get_read_protocols_to_try, join_with_and, | ||
| 19 | }; | 20 | }; |
| 20 | 21 | ||
| 21 | pub async fn run_fetch( | 22 | pub async fn run_fetch( |
| @@ -58,10 +59,10 @@ pub async fn run_fetch( | |||
| 58 | && !errors.is_empty() | 59 | && !errors.is_empty() |
| 59 | { | 60 | { |
| 60 | bail!( | 61 | bail!( |
| 61 | "failed to fetch objects in nostr state event from:\r\n{}", | 62 | "fetch: failed to fetch objects in nostr state event from:\r\n{}", |
| 62 | errors | 63 | errors |
| 63 | .iter() | 64 | .iter() |
| 64 | .map(std::string::ToString::to_string) | 65 | .map(|e| format!(" - {e}")) |
| 65 | .collect::<Vec<String>>() | 66 | .collect::<Vec<String>>() |
| 66 | .join("\r\n") | 67 | .join("\r\n") |
| 67 | ); | 68 | ); |
| @@ -114,97 +115,45 @@ fn fetch_from_git_server( | |||
| 114 | ) -> Result<()> { | 115 | ) -> Result<()> { |
| 115 | let server_url = git_server_url.parse::<CloneUrl>()?; | 116 | let server_url = git_server_url.parse::<CloneUrl>()?; |
| 116 | 117 | ||
| 117 | // if protocol is local - just try local | 118 | let protocols_to_attempt = get_read_protocols_to_try(&server_url, decoded_nostr_url); |
| 118 | if server_url.protocol() == ServerProtocol::Local { | ||
| 119 | let formatted_url = server_url.format_as(&ServerProtocol::Local, &None)?; | ||
| 120 | term.write_line(format!("fetching from {formatted_url}...").as_str())?; | ||
| 121 | if let Err(error) = fetch_from_git_server_url(git_repo, oids, &formatted_url) { | ||
| 122 | term.write_line( | ||
| 123 | format!("WARNING: failed to fetch from {formatted_url} error:{error}").as_str(), | ||
| 124 | )?; | ||
| 125 | return Err(error).context(format!("{formatted_url}: failed to fetch")); | ||
| 126 | } | ||
| 127 | return Ok(()); | ||
| 128 | } | ||
| 129 | 119 | ||
| 130 | term.write_line(format!("fetching from {}...", server_url.domain()).as_str())?; | 120 | let mut failed_protocols = vec![]; |
| 121 | let mut success = false; | ||
| 122 | for protocol in &protocols_to_attempt { | ||
| 123 | term.write_line( | ||
| 124 | format!("fetching from {} over {protocol}...", server_url.domain(),).as_str(), | ||
| 125 | )?; | ||
| 131 | 126 | ||
| 132 | // use overide protocol if specified | ||
| 133 | if let Some(protocol) = &decoded_nostr_url.protocol { | ||
| 134 | let formatted_url = server_url.format_as(protocol, &decoded_nostr_url.user)?; | 127 | let formatted_url = server_url.format_as(protocol, &decoded_nostr_url.user)?; |
| 135 | let res = fetch_from_git_server_url(git_repo, oids, &formatted_url); | 128 | let res = if [ServerProtocol::UnauthHttps, ServerProtocol::UnauthHttp].contains(protocol) { |
| 129 | fetch_from_git_server_url_unauthenticated(git_repo, oids, &formatted_url) | ||
| 130 | } else { | ||
| 131 | fetch_from_git_server_url(git_repo, oids, &formatted_url) | ||
| 132 | }; | ||
| 136 | term.clear_last_lines(1)?; | 133 | term.clear_last_lines(1)?; |
| 137 | if let Err(error) = res { | 134 | if let Err(error) = res { |
| 138 | term.write_line( | 135 | term.write_line( |
| 139 | format!( | 136 | format!("fetch: {formatted_url} failed over {protocol}: {error}").as_str(), |
| 140 | "WARNING: {formatted_url} failed to fetch over {protocol}{} as specified in nostr url. error:{error}", | ||
| 141 | if let Some(user) = &decoded_nostr_url.user { | ||
| 142 | format!(" with user '{user}'") | ||
| 143 | } else { | ||
| 144 | String::new() | ||
| 145 | } | ||
| 146 | ).as_str(), | ||
| 147 | )?; | 137 | )?; |
| 148 | return Err(error).context(format!("{formatted_url}: failed to fetch")); | 138 | failed_protocols.push(protocol); |
| 149 | } | 139 | } else { |
| 150 | return Ok(()); | 140 | success = true; |
| 151 | } | 141 | if !failed_protocols.is_empty() { |
| 152 | 142 | term.write_line(format!("fetch: succeeded over {protocol}").as_str())?; | |
| 153 | // Try https unauthenticated | ||
| 154 | let formatted_url = server_url.format_as(&ServerProtocol::Https, &None)?; | ||
| 155 | let res = fetch_from_git_server_url_unauthenticated(git_repo, oids, &formatted_url); | ||
| 156 | term.clear_last_lines(1)?; | ||
| 157 | if let Err(unauth_error) = res { | ||
| 158 | term.write_line( | ||
| 159 | format!( | ||
| 160 | "WARNING: {formatted_url} failed to fetch over unauthenticated https. {unauth_error}", | ||
| 161 | ).as_str(), | ||
| 162 | )?; | ||
| 163 | // TODO what about timeout errors? | ||
| 164 | // try over ssh | ||
| 165 | let mut ssh_error = None; | ||
| 166 | if check_ssh_keys() { | ||
| 167 | term.write_line(format!("fetching from {} over ssh...", server_url.domain()).as_str())?; | ||
| 168 | let formatted_url = server_url.format_as(&ServerProtocol::Ssh, &None)?; | ||
| 169 | let res = fetch_from_git_server_url(git_repo, oids, &formatted_url); | ||
| 170 | term.clear_last_lines(1)?; | ||
| 171 | if let Err(error) = res { | ||
| 172 | term.write_line( | ||
| 173 | format!("WARNING: {formatted_url} failed to fetch over ssh. error:{error}") | ||
| 174 | .as_str(), | ||
| 175 | )?; | ||
| 176 | term.write_line( | ||
| 177 | format!("fetching from {} over ssh...", server_url.domain()).as_str(), | ||
| 178 | )?; | ||
| 179 | ssh_error = Some(error); | ||
| 180 | } else { | ||
| 181 | return Ok(()); | ||
| 182 | } | 143 | } |
| 183 | } | 144 | } |
| 184 | // try over https authenticated | 145 | } |
| 185 | term.write_line( | 146 | if !success { |
| 186 | format!( | 147 | if decoded_nostr_url.protocol.is_some() { |
| 187 | "fetching from {} over authenticated https...", | ||
| 188 | server_url.domain() | ||
| 189 | ) | ||
| 190 | .as_str(), | ||
| 191 | )?; | ||
| 192 | let formatted_url = server_url.format_as(&ServerProtocol::Ssh, &None)?; | ||
| 193 | let res = fetch_from_git_server_url(git_repo, oids, &formatted_url); | ||
| 194 | term.clear_last_lines(1)?; | ||
| 195 | if let Err(auth_https_error) = res { | ||
| 196 | term.write_line( | 148 | term.write_line( |
| 197 | format!("WARNING: {formatted_url} failed to fetch over authenticated https. error:{auth_https_error}",) | 149 | "fetch: protocol override in nostr url so not attempting with any other protocols", |
| 198 | .as_str(), | ||
| 199 | )?; | 150 | )?; |
| 200 | let error_message = format!( | ||
| 201 | "{} failed to fetch over unauthenticated https ({unauth_error}), ssh ({}) and authenticated https ({auth_https_error})", | ||
| 202 | server_url.format_as(&ServerProtocol::Unspecified, &None)?, | ||
| 203 | ssh_error.unwrap_or(anyhow!("no keys found")) | ||
| 204 | ); | ||
| 205 | |||
| 206 | bail!(error_message) | ||
| 207 | } | 151 | } |
| 152 | bail!( | ||
| 153 | "{} failed over {}", | ||
| 154 | server_url.domain(), | ||
| 155 | join_with_and(&failed_protocols) | ||
| 156 | ); | ||
| 208 | } | 157 | } |
| 209 | Ok(()) | 158 | Ok(()) |
| 210 | } | 159 | } |
| @@ -214,6 +163,9 @@ fn fetch_from_git_server_url( | |||
| 214 | oids: &[String], | 163 | oids: &[String], |
| 215 | git_server_url: &str, | 164 | git_server_url: &str, |
| 216 | ) -> Result<()> { | 165 | ) -> Result<()> { |
| 166 | if git_server_url.parse::<CloneUrl>()?.protocol() == ServerProtocol::Ssh && !check_ssh_keys() { | ||
| 167 | bail!("no ssh keys found"); | ||
| 168 | } | ||
| 217 | let git_config = git_repo.config()?; | 169 | let git_config = git_repo.config()?; |
| 218 | let mut git_server_remote = git_repo.remote_anonymous(git_server_url)?; | 170 | let mut git_server_remote = git_repo.remote_anonymous(git_server_url)?; |
| 219 | let auth = GitAuthenticator::default(); | 171 | let auth = GitAuthenticator::default(); |