diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2024-09-06 10:45:21 +0100 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2024-09-06 11:05:11 +0100 |
| commit | 6e7e7bd3497d2a77fda34e27f65955b8ac09b3be (patch) | |
| tree | 7d36f9feb568e63823e017b85d5a84443b1bb20c /src/bin/git_remote_nostr/list.rs | |
| parent | 935bc0ca630d7964082966e4c0caeb255f5a4f57 (diff) | |
fix(remote): `list` apply protocols selection
used in fetch and tweak the error reporting
Diffstat (limited to 'src/bin/git_remote_nostr/list.rs')
| -rw-r--r-- | src/bin/git_remote_nostr/list.rs | 138 |
1 files changed, 111 insertions, 27 deletions
diff --git a/src/bin/git_remote_nostr/list.rs b/src/bin/git_remote_nostr/list.rs index 097f070..26f699d 100644 --- a/src/bin/git_remote_nostr/list.rs +++ b/src/bin/git_remote_nostr/list.rs | |||
| @@ -1,25 +1,35 @@ | |||
| 1 | use core::str; | 1 | use core::str; |
| 2 | use std::collections::HashMap; | 2 | use std::collections::HashMap; |
| 3 | 3 | ||
| 4 | use anyhow::{Context, Result}; | 4 | use anyhow::{anyhow, Context, Result}; |
| 5 | use auth_git2::GitAuthenticator; | 5 | use auth_git2::GitAuthenticator; |
| 6 | use client::get_state_from_cache; | 6 | use client::get_state_from_cache; |
| 7 | use git::RepoActions; | 7 | use git::RepoActions; |
| 8 | use git_events::{event_to_cover_letter, get_commit_id_from_patch}; | 8 | use git_events::{event_to_cover_letter, get_commit_id_from_patch}; |
| 9 | use ngit::{client, git, git_events, login::get_curent_user, repo_ref}; | 9 | use ngit::{ |
| 10 | client, | ||
| 11 | git::{ | ||
| 12 | self, | ||
| 13 | nostr_url::{CloneUrl, NostrUrlDecoded, ServerProtocol}, | ||
| 14 | }, | ||
| 15 | git_events, | ||
| 16 | login::get_curent_user, | ||
| 17 | repo_ref, | ||
| 18 | }; | ||
| 10 | use nostr_sdk::hashes::sha1::Hash as Sha1Hash; | 19 | use nostr_sdk::hashes::sha1::Hash as Sha1Hash; |
| 11 | use repo_ref::RepoRef; | 20 | use repo_ref::RepoRef; |
| 12 | 21 | ||
| 13 | use crate::{ | 22 | use crate::{ |
| 14 | git::Repo, | 23 | git::Repo, |
| 15 | utils::{ | 24 | utils::{ |
| 16 | get_open_proposals, get_short_git_server_name, switch_clone_url_between_ssh_and_https, | 25 | get_open_proposals, get_read_protocols_to_try, get_short_git_server_name, join_with_and, |
| 17 | }, | 26 | }, |
| 18 | }; | 27 | }; |
| 19 | 28 | ||
| 20 | pub async fn run_list( | 29 | pub async fn run_list( |
| 21 | git_repo: &Repo, | 30 | git_repo: &Repo, |
| 22 | repo_ref: &RepoRef, | 31 | repo_ref: &RepoRef, |
| 32 | decoded_nostr_url: &NostrUrlDecoded, | ||
| 23 | for_push: bool, | 33 | for_push: bool, |
| 24 | ) -> Result<HashMap<String, HashMap<String, String>>> { | 34 | ) -> Result<HashMap<String, HashMap<String, String>>> { |
| 25 | let nostr_state = | 35 | let nostr_state = |
| @@ -31,7 +41,7 @@ pub async fn run_list( | |||
| 31 | 41 | ||
| 32 | let term = console::Term::stderr(); | 42 | let term = console::Term::stderr(); |
| 33 | 43 | ||
| 34 | let remote_states = list_from_remotes(&term, git_repo, &repo_ref.git_server)?; | 44 | let remote_states = list_from_remotes(&term, git_repo, &repo_ref.git_server, decoded_nostr_url); |
| 35 | 45 | ||
| 36 | let mut state = if let Some(nostr_state) = nostr_state { | 46 | let mut state = if let Some(nostr_state) = nostr_state { |
| 37 | for (name, value) in &nostr_state.state { | 47 | for (name, value) in &nostr_state.state { |
| @@ -122,41 +132,115 @@ pub fn list_from_remotes( | |||
| 122 | term: &console::Term, | 132 | term: &console::Term, |
| 123 | git_repo: &Repo, | 133 | git_repo: &Repo, |
| 124 | git_servers: &Vec<String>, | 134 | git_servers: &Vec<String>, |
| 125 | ) -> Result<HashMap<String, HashMap<String, String>>> { | 135 | decoded_nostr_url: &NostrUrlDecoded, // Add this parameter |
| 136 | ) -> HashMap<String, HashMap<String, String>> { | ||
| 126 | let mut remote_states = HashMap::new(); | 137 | let mut remote_states = HashMap::new(); |
| 138 | let mut errors = HashMap::new(); | ||
| 127 | for url in git_servers { | 139 | for url in git_servers { |
| 128 | let short_name = get_short_git_server_name(git_repo, url); | 140 | match list_from_remote(term, git_repo, url, decoded_nostr_url) { |
| 129 | term.write_line(format!("fetching refs list: {short_name}...").as_str())?; | 141 | Err(error) => { |
| 130 | match list_from_remote(git_repo, url) { | 142 | errors.insert(url, error); |
| 131 | Ok(remote_state) => { | ||
| 132 | remote_states.insert(url.clone(), remote_state); | ||
| 133 | } | 143 | } |
| 134 | Err(error1) => { | 144 | Ok(state) => { |
| 135 | if let Ok(alternative_url) = switch_clone_url_between_ssh_and_https(url) { | 145 | remote_states.insert(url.to_string(), state); |
| 136 | match list_from_remote(git_repo, &alternative_url) { | 146 | } |
| 137 | Ok(remote_state) => { | 147 | } |
| 138 | remote_states.insert(url.clone(), remote_state); | 148 | } |
| 139 | } | 149 | remote_states |
| 140 | Err(error2) => { | 150 | } |
| 141 | term.write_line( | 151 | |
| 142 | format!("WARNING: {short_name} failed to list refs error: {error1}\r\nand alternative protocol {alternative_url}: {error2}").as_str(), | 152 | pub fn list_from_remote( |
| 143 | )?; | 153 | term: &console::Term, |
| 144 | } | 154 | git_repo: &Repo, |
| 145 | } | 155 | git_server_url: &str, |
| 146 | } else { | 156 | decoded_nostr_url: &NostrUrlDecoded, // Add this parameter |
| 157 | ) -> Result<HashMap<String, String>> { | ||
| 158 | let server_url = git_server_url.parse::<CloneUrl>()?; | ||
| 159 | let protocols_to_attempt = get_read_protocols_to_try(&server_url, decoded_nostr_url); | ||
| 160 | |||
| 161 | let mut failed_protocols = vec![]; | ||
| 162 | let mut remote_state: Option<HashMap<String, String>> = None; | ||
| 163 | |||
| 164 | for protocol in &protocols_to_attempt { | ||
| 165 | term.write_line( | ||
| 166 | format!( | ||
| 167 | "fetching ref list from {} over {protocol}...", | ||
| 168 | server_url.domain(), | ||
| 169 | ) | ||
| 170 | .as_str(), | ||
| 171 | )?; | ||
| 172 | |||
| 173 | let formatted_url = server_url.format_as(protocol, &decoded_nostr_url.user)?; | ||
| 174 | let res = if [ServerProtocol::UnauthHttps, ServerProtocol::UnauthHttp].contains(protocol) { | ||
| 175 | list_from_remote_url_unauthenticated(git_repo, &formatted_url) | ||
| 176 | } else { | ||
| 177 | list_from_remote_url(git_repo, &formatted_url) | ||
| 178 | }; | ||
| 179 | |||
| 180 | match res { | ||
| 181 | Ok(state) => { | ||
| 182 | remote_state = Some(state); | ||
| 183 | if !failed_protocols.is_empty() { | ||
| 147 | term.write_line( | 184 | term.write_line( |
| 148 | format!("WARNING: {short_name} failed to list refs error: {error1}",) | 185 | format!( |
| 149 | .as_str(), | 186 | "list: succeeded over {protocol} for {}", |
| 187 | server_url.domain(), | ||
| 188 | ) | ||
| 189 | .as_str(), | ||
| 150 | )?; | 190 | )?; |
| 151 | } | 191 | } |
| 192 | break; | ||
| 193 | } | ||
| 194 | Err(error) => { | ||
| 195 | term.write_line( | ||
| 196 | format!("list: {formatted_url} failed over {protocol}: {error}").as_str(), | ||
| 197 | )?; | ||
| 198 | failed_protocols.push(protocol); | ||
| 152 | } | 199 | } |
| 153 | } | 200 | } |
| 154 | term.clear_last_lines(1)?; | 201 | term.clear_last_lines(1)?; |
| 155 | } | 202 | } |
| 156 | Ok(remote_states) | 203 | if let Some(remote_state) = remote_state { |
| 204 | Ok(remote_state) | ||
| 205 | } else { | ||
| 206 | let error = anyhow!( | ||
| 207 | "{} failed over {}{}", | ||
| 208 | server_url.domain(), | ||
| 209 | join_with_and(&failed_protocols), | ||
| 210 | if decoded_nostr_url.protocol.is_some() { | ||
| 211 | " and nostr url contains protocol override so no other protocols were attempted" | ||
| 212 | } else { | ||
| 213 | "" | ||
| 214 | }, | ||
| 215 | ); | ||
| 216 | term.write_line(format!("list: {error}").as_str())?; | ||
| 217 | Err(error) | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | fn list_from_remote_url_unauthenticated( | ||
| 222 | git_repo: &Repo, | ||
| 223 | git_server_remote_url: &str, | ||
| 224 | ) -> Result<HashMap<String, String>> { | ||
| 225 | let mut git_server_remote = git_repo.git_repo.remote_anonymous(git_server_remote_url)?; | ||
| 226 | let remote_callbacks = git2::RemoteCallbacks::new(); | ||
| 227 | git_server_remote.connect_auth(git2::Direction::Fetch, Some(remote_callbacks), None)?; | ||
| 228 | let mut state = HashMap::new(); | ||
| 229 | for head in git_server_remote.list()? { | ||
| 230 | if let Some(symbolic_reference) = head.symref_target() { | ||
| 231 | state.insert( | ||
| 232 | head.name().to_string(), | ||
| 233 | format!("ref: {symbolic_reference}"), | ||
| 234 | ); | ||
| 235 | } else { | ||
| 236 | state.insert(head.name().to_string(), head.oid().to_string()); | ||
| 237 | } | ||
| 238 | } | ||
| 239 | git_server_remote.disconnect()?; | ||
| 240 | Ok(state) | ||
| 157 | } | 241 | } |
| 158 | 242 | ||
| 159 | fn list_from_remote( | 243 | fn list_from_remote_url( |
| 160 | git_repo: &Repo, | 244 | git_repo: &Repo, |
| 161 | git_server_remote_url: &str, | 245 | git_server_remote_url: &str, |
| 162 | ) -> Result<HashMap<String, String>> { | 246 | ) -> Result<HashMap<String, String>> { |