upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/bin/git_remote_nostr/list.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2024-09-06 10:45:21 +0100
committerDanConwayDev <DanConwayDev@protonmail.com>2024-09-06 11:05:11 +0100
commit6e7e7bd3497d2a77fda34e27f65955b8ac09b3be (patch)
tree7d36f9feb568e63823e017b85d5a84443b1bb20c /src/bin/git_remote_nostr/list.rs
parent935bc0ca630d7964082966e4c0caeb255f5a4f57 (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.rs138
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 @@
1use core::str; 1use core::str;
2use std::collections::HashMap; 2use std::collections::HashMap;
3 3
4use anyhow::{Context, Result}; 4use anyhow::{anyhow, Context, Result};
5use auth_git2::GitAuthenticator; 5use auth_git2::GitAuthenticator;
6use client::get_state_from_cache; 6use client::get_state_from_cache;
7use git::RepoActions; 7use git::RepoActions;
8use git_events::{event_to_cover_letter, get_commit_id_from_patch}; 8use git_events::{event_to_cover_letter, get_commit_id_from_patch};
9use ngit::{client, git, git_events, login::get_curent_user, repo_ref}; 9use 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};
10use nostr_sdk::hashes::sha1::Hash as Sha1Hash; 19use nostr_sdk::hashes::sha1::Hash as Sha1Hash;
11use repo_ref::RepoRef; 20use repo_ref::RepoRef;
12 21
13use crate::{ 22use 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
20pub async fn run_list( 29pub 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(), 152pub 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
221fn 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
159fn list_from_remote( 243fn 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>> {