upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/bin
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/git_remote_nostr/fetch.rs10
-rw-r--r--src/bin/git_remote_nostr/list.rs5
-rw-r--r--src/bin/git_remote_nostr/push.rs5
-rw-r--r--src/bin/git_remote_nostr/utils.rs147
4 files changed, 132 insertions, 35 deletions
diff --git a/src/bin/git_remote_nostr/fetch.rs b/src/bin/git_remote_nostr/fetch.rs
index 33fd959..fed9925 100644
--- a/src/bin/git_remote_nostr/fetch.rs
+++ b/src/bin/git_remote_nostr/fetch.rs
@@ -22,6 +22,7 @@ use ngit::{
22use crate::utils::{ 22use crate::utils::{
23 fetch_or_list_error_is_not_authentication_failure, find_proposal_and_patches_by_branch_name, 23 fetch_or_list_error_is_not_authentication_failure, find_proposal_and_patches_by_branch_name,
24 get_oids_from_fetch_batch, get_open_proposals, get_read_protocols_to_try, join_with_and, 24 get_oids_from_fetch_batch, get_open_proposals, get_read_protocols_to_try, join_with_and,
25 set_protocol_preference, Direction,
25}; 26};
26 27
27pub async fn run_fetch( 28pub async fn run_fetch(
@@ -46,7 +47,7 @@ pub async fn run_fetch(
46 for git_server_url in &repo_ref.git_server { 47 for git_server_url in &repo_ref.git_server {
47 let term = console::Term::stderr(); 48 let term = console::Term::stderr();
48 if let Err(error) = fetch_from_git_server( 49 if let Err(error) = fetch_from_git_server(
49 &git_repo.git_repo, 50 git_repo,
50 &oids_from_git_servers, 51 &oids_from_git_servers,
51 git_server_url, 52 git_server_url,
52 decoded_nostr_url, 53 decoded_nostr_url,
@@ -112,7 +113,7 @@ pub async fn run_fetch(
112} 113}
113 114
114fn fetch_from_git_server( 115fn fetch_from_git_server(
115 git_repo: &Repository, 116 git_repo: &Repo,
116 oids: &[String], 117 oids: &[String],
117 git_server_url: &str, 118 git_server_url: &str,
118 decoded_nostr_url: &NostrUrlDecoded, 119 decoded_nostr_url: &NostrUrlDecoded,
@@ -120,7 +121,7 @@ fn fetch_from_git_server(
120) -> Result<()> { 121) -> Result<()> {
121 let server_url = git_server_url.parse::<CloneUrl>()?; 122 let server_url = git_server_url.parse::<CloneUrl>()?;
122 123
123 let protocols_to_attempt = get_read_protocols_to_try(&server_url, decoded_nostr_url); 124 let protocols_to_attempt = get_read_protocols_to_try(git_repo, &server_url, decoded_nostr_url);
124 125
125 let mut failed_protocols = vec![]; 126 let mut failed_protocols = vec![];
126 let mut success = false; 127 let mut success = false;
@@ -131,7 +132,7 @@ fn fetch_from_git_server(
131 132
132 let formatted_url = server_url.format_as(protocol, &decoded_nostr_url.user)?; 133 let formatted_url = server_url.format_as(protocol, &decoded_nostr_url.user)?;
133 let res = fetch_from_git_server_url( 134 let res = fetch_from_git_server_url(
134 git_repo, 135 &git_repo.git_repo,
135 oids, 136 oids,
136 &formatted_url, 137 &formatted_url,
137 [ServerProtocol::UnauthHttps, ServerProtocol::UnauthHttp].contains(protocol), 138 [ServerProtocol::UnauthHttps, ServerProtocol::UnauthHttp].contains(protocol),
@@ -152,6 +153,7 @@ fn fetch_from_git_server(
152 success = true; 153 success = true;
153 if !failed_protocols.is_empty() { 154 if !failed_protocols.is_empty() {
154 term.write_line(format!("fetch: succeeded over {protocol}").as_str())?; 155 term.write_line(format!("fetch: succeeded over {protocol}").as_str())?;
156 let _ = set_protocol_preference(git_repo, protocol, &server_url, &Direction::Push);
155 } 157 }
156 break; 158 break;
157 } 159 }
diff --git a/src/bin/git_remote_nostr/list.rs b/src/bin/git_remote_nostr/list.rs
index c2bd9d6..959b8c8 100644
--- a/src/bin/git_remote_nostr/list.rs
+++ b/src/bin/git_remote_nostr/list.rs
@@ -24,6 +24,7 @@ use crate::{
24 utils::{ 24 utils::{
25 fetch_or_list_error_is_not_authentication_failure, get_open_proposals, 25 fetch_or_list_error_is_not_authentication_failure, get_open_proposals,
26 get_read_protocols_to_try, get_short_git_server_name, join_with_and, 26 get_read_protocols_to_try, get_short_git_server_name, join_with_and,
27 set_protocol_preference, Direction,
27 }, 28 },
28}; 29};
29 30
@@ -157,7 +158,7 @@ pub fn list_from_remote(
157 decoded_nostr_url: &NostrUrlDecoded, // Add this parameter 158 decoded_nostr_url: &NostrUrlDecoded, // Add this parameter
158) -> Result<HashMap<String, String>> { 159) -> Result<HashMap<String, String>> {
159 let server_url = git_server_url.parse::<CloneUrl>()?; 160 let server_url = git_server_url.parse::<CloneUrl>()?;
160 let protocols_to_attempt = get_read_protocols_to_try(&server_url, decoded_nostr_url); 161 let protocols_to_attempt = get_read_protocols_to_try(git_repo, &server_url, decoded_nostr_url);
161 162
162 let mut failed_protocols = vec![]; 163 let mut failed_protocols = vec![];
163 let mut remote_state: Option<HashMap<String, String>> = None; 164 let mut remote_state: Option<HashMap<String, String>> = None;
@@ -191,6 +192,8 @@ pub fn list_from_remote(
191 ) 192 )
192 .as_str(), 193 .as_str(),
193 )?; 194 )?;
195 let _ =
196 set_protocol_preference(git_repo, protocol, &server_url, &Direction::Fetch);
194 } 197 }
195 break; 198 break;
196 } 199 }
diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs
index daa7973..de18828 100644
--- a/src/bin/git_remote_nostr/push.rs
+++ b/src/bin/git_remote_nostr/push.rs
@@ -41,7 +41,7 @@ use crate::{
41 utils::{ 41 utils::{
42 find_proposal_and_patches_by_branch_name, get_all_proposals, get_remote_name_by_url, 42 find_proposal_and_patches_by_branch_name, get_all_proposals, get_remote_name_by_url,
43 get_short_git_server_name, get_write_protocols_to_try, join_with_and, 43 get_short_git_server_name, get_write_protocols_to_try, join_with_and,
44 push_error_is_not_authentication_failure, read_line, 44 push_error_is_not_authentication_failure, read_line, set_protocol_preference, Direction,
45 }, 45 },
46}; 46};
47 47
@@ -351,7 +351,7 @@ fn push_to_remote(
351 term: &Term, 351 term: &Term,
352) -> Result<()> { 352) -> Result<()> {
353 let server_url = git_server_url.parse::<CloneUrl>()?; 353 let server_url = git_server_url.parse::<CloneUrl>()?;
354 let protocols_to_attempt = get_write_protocols_to_try(&server_url, decoded_nostr_url); 354 let protocols_to_attempt = get_write_protocols_to_try(git_repo, &server_url, decoded_nostr_url);
355 355
356 let mut failed_protocols = vec![]; 356 let mut failed_protocols = vec![];
357 let mut success = false; 357 let mut success = false;
@@ -373,6 +373,7 @@ fn push_to_remote(
373 success = true; 373 success = true;
374 if !failed_protocols.is_empty() { 374 if !failed_protocols.is_empty() {
375 term.write_line(format!("fetch: succeeded over {protocol}").as_str())?; 375 term.write_line(format!("fetch: succeeded over {protocol}").as_str())?;
376 let _ = set_protocol_preference(git_repo, protocol, &server_url, &Direction::Push);
376 } 377 }
377 } 378 }
378 term.clear_last_lines(1)?; 379 term.clear_last_lines(1)?;
diff --git a/src/bin/git_remote_nostr/utils.rs b/src/bin/git_remote_nostr/utils.rs
index a13d398..3ae1bab 100644
--- a/src/bin/git_remote_nostr/utils.rs
+++ b/src/bin/git_remote_nostr/utils.rs
@@ -1,7 +1,9 @@
1use core::str; 1use core::str;
2use std::{ 2use std::{
3 collections::HashMap, 3 collections::HashMap,
4 fmt,
4 io::{self, Stdin}, 5 io::{self, Stdin},
6 str::FromStr,
5}; 7};
6 8
7use anyhow::{bail, Context, Result}; 9use anyhow::{bail, Context, Result};
@@ -214,6 +216,7 @@ pub fn join_with_and<T: ToString>(items: &[T]) -> String {
214 216
215/// get an ordered vector of server protocols to attempt 217/// get an ordered vector of server protocols to attempt
216pub fn get_read_protocols_to_try( 218pub fn get_read_protocols_to_try(
219 git_repo: &Repo,
217 server_url: &CloneUrl, 220 server_url: &CloneUrl,
218 decoded_nostr_url: &NostrUrlDecoded, 221 decoded_nostr_url: &NostrUrlDecoded,
219) -> Vec<ServerProtocol> { 222) -> Vec<ServerProtocol> {
@@ -221,27 +224,37 @@ pub fn get_read_protocols_to_try(
221 vec![(ServerProtocol::Filesystem)] 224 vec![(ServerProtocol::Filesystem)]
222 } else if let Some(protocol) = &decoded_nostr_url.protocol { 225 } else if let Some(protocol) = &decoded_nostr_url.protocol {
223 vec![protocol.clone()] 226 vec![protocol.clone()]
224 } else if server_url.protocol() == ServerProtocol::Http {
225 vec![
226 ServerProtocol::UnauthHttp,
227 ServerProtocol::Ssh,
228 // note: list and fetch stop here if ssh was authenticated
229 ServerProtocol::Http,
230 ]
231 } else if server_url.protocol() == ServerProtocol::Ftp {
232 vec![ServerProtocol::Ftp, ServerProtocol::Ssh]
233 } else { 227 } else {
234 vec![ 228 let mut list = if server_url.protocol() == ServerProtocol::Http {
235 ServerProtocol::UnauthHttps, 229 vec![
236 ServerProtocol::Ssh, 230 ServerProtocol::UnauthHttp,
237 // note: list and fetch stop here if ssh was authenticated 231 ServerProtocol::Ssh,
238 ServerProtocol::Https, 232 // note: list and fetch stop here if ssh was authenticated
239 ] 233 ServerProtocol::Http,
234 ]
235 } else if server_url.protocol() == ServerProtocol::Ftp {
236 vec![ServerProtocol::Ftp, ServerProtocol::Ssh]
237 } else {
238 vec![
239 ServerProtocol::UnauthHttps,
240 ServerProtocol::Ssh,
241 // note: list and fetch stop here if ssh was authenticated
242 ServerProtocol::Https,
243 ]
244 };
245 if let Some(protocol) = get_protocol_preference(git_repo, server_url, &Direction::Fetch) {
246 if let Some(pos) = list.iter().position(|p| *p == protocol) {
247 list.remove(pos);
248 list.insert(0, protocol);
249 }
250 }
251 list
240 } 252 }
241} 253}
242 254
243/// get an ordered vector of server protocols to attempt 255/// get an ordered vector of server protocols to attempt
244pub fn get_write_protocols_to_try( 256pub fn get_write_protocols_to_try(
257 git_repo: &Repo,
245 server_url: &CloneUrl, 258 server_url: &CloneUrl,
246 decoded_nostr_url: &NostrUrlDecoded, 259 decoded_nostr_url: &NostrUrlDecoded,
247) -> Vec<ServerProtocol> { 260) -> Vec<ServerProtocol> {
@@ -249,23 +262,101 @@ pub fn get_write_protocols_to_try(
249 vec![(ServerProtocol::Filesystem)] 262 vec![(ServerProtocol::Filesystem)]
250 } else if let Some(protocol) = &decoded_nostr_url.protocol { 263 } else if let Some(protocol) = &decoded_nostr_url.protocol {
251 vec![protocol.clone()] 264 vec![protocol.clone()]
252 } else if server_url.protocol() == ServerProtocol::Http {
253 vec![
254 ServerProtocol::Ssh,
255 // note: list and fetch stop here if ssh was authenticated
256 ServerProtocol::Http,
257 ]
258 } else if server_url.protocol() == ServerProtocol::Ftp {
259 vec![ServerProtocol::Ssh, ServerProtocol::Ftp]
260 } else { 265 } else {
261 vec![ 266 let mut list = if server_url.protocol() == ServerProtocol::Http {
262 ServerProtocol::Ssh, 267 vec![
263 // note: list and fetch stop here if ssh was authenticated 268 ServerProtocol::Ssh,
264 ServerProtocol::Https, 269 // note: list and fetch stop here if ssh was authenticated
265 ] 270 ServerProtocol::Http,
271 ]
272 } else if server_url.protocol() == ServerProtocol::Ftp {
273 vec![ServerProtocol::Ssh, ServerProtocol::Ftp]
274 } else {
275 vec![
276 ServerProtocol::Ssh,
277 // note: list and fetch stop here if ssh was authenticated
278 ServerProtocol::Https,
279 ]
280 };
281 if let Some(protocol) = get_protocol_preference(git_repo, server_url, &Direction::Push) {
282 if let Some(pos) = list.iter().position(|p| *p == protocol) {
283 list.remove(pos);
284 list.insert(0, protocol);
285 }
286 }
287
288 list
266 } 289 }
267} 290}
268 291
292#[derive(Debug, PartialEq)]
293pub enum Direction {
294 Push,
295 Fetch,
296}
297impl fmt::Display for Direction {
298 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
299 match self {
300 Direction::Push => write!(f, "push"),
301 Direction::Fetch => write!(f, "fetch"),
302 }
303 }
304}
305
306pub fn get_protocol_preference(
307 git_repo: &Repo,
308 server_url: &CloneUrl,
309 direction: &Direction,
310) -> Option<ServerProtocol> {
311 let server_short_name = server_url.short_name();
312 if let Ok(Some(list)) =
313 git_repo.get_git_config_item(format!("nostr.protocol-{direction}").as_str(), Some(false))
314 {
315 for item in list.split(';') {
316 let pair = item.split(',').collect::<Vec<&str>>();
317 if let Some(url) = pair.get(1) {
318 if *url == server_short_name {
319 if let Some(protocol) = pair.first() {
320 if let Ok(protocol) = ServerProtocol::from_str(protocol) {
321 return Some(protocol);
322 }
323 }
324 }
325 }
326 }
327 }
328 None
329}
330
331pub fn set_protocol_preference(
332 git_repo: &Repo,
333 protocol: &ServerProtocol,
334 server_url: &CloneUrl,
335 direction: &Direction,
336) -> Result<()> {
337 let server_short_name = server_url.short_name();
338 let mut new = String::new();
339 if let Some(list) =
340 git_repo.get_git_config_item(format!("nostr.protocol-{direction}").as_str(), Some(false))?
341 {
342 for item in list.split(';') {
343 let pair = item.split(',').collect::<Vec<&str>>();
344 if let Some(url) = pair.get(1) {
345 if *url != server_short_name && !item.is_empty() {
346 new.push_str(format!("{item};").as_str());
347 }
348 }
349 }
350 }
351 new.push_str(format!("{protocol},{server_short_name};").as_str());
352
353 git_repo.save_git_config_item(
354 format!("nostr.protocol-{direction}").as_str(),
355 new.as_str(),
356 false,
357 )
358}
359
269/// to understand whether to try over another protocol 360/// to understand whether to try over another protocol
270pub fn fetch_or_list_error_is_not_authentication_failure(error: &anyhow::Error) -> bool { 361pub fn fetch_or_list_error_is_not_authentication_failure(error: &anyhow::Error) -> bool {
271 !error_might_be_authentication_related(error) 362 !error_might_be_authentication_related(error)