diff options
Diffstat (limited to 'src/bin/git_remote_nostr')
| -rw-r--r-- | src/bin/git_remote_nostr/list.rs | 138 | ||||
| -rw-r--r-- | src/bin/git_remote_nostr/main.rs | 18 | ||||
| -rw-r--r-- | src/bin/git_remote_nostr/push.rs | 16 |
3 files changed, 135 insertions, 37 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>> { |
diff --git a/src/bin/git_remote_nostr/main.rs b/src/bin/git_remote_nostr/main.rs index a3fc5f8..e2738d2 100644 --- a/src/bin/git_remote_nostr/main.rs +++ b/src/bin/git_remote_nostr/main.rs | |||
| @@ -75,13 +75,21 @@ async fn main() -> Result<()> { | |||
| 75 | println!("unsupported"); | 75 | println!("unsupported"); |
| 76 | } | 76 | } |
| 77 | ["fetch", oid, refstr] => { | 77 | ["fetch", oid, refstr] => { |
| 78 | fetch::run_fetch(&git_repo, &repo_ref, &decoded_nostr_url, &stdin, oid, refstr).await?; | 78 | fetch::run_fetch( |
| 79 | &git_repo, | ||
| 80 | &repo_ref, | ||
| 81 | &decoded_nostr_url, | ||
| 82 | &stdin, | ||
| 83 | oid, | ||
| 84 | refstr, | ||
| 85 | ) | ||
| 86 | .await?; | ||
| 79 | } | 87 | } |
| 80 | ["push", refspec] => { | 88 | ["push", refspec] => { |
| 81 | push::run_push( | 89 | push::run_push( |
| 82 | &git_repo, | 90 | &git_repo, |
| 83 | &repo_ref, | 91 | &repo_ref, |
| 84 | nostr_remote_url, | 92 | &decoded_nostr_url, |
| 85 | &stdin, | 93 | &stdin, |
| 86 | refspec, | 94 | refspec, |
| 87 | &client, | 95 | &client, |
| @@ -90,10 +98,12 @@ async fn main() -> Result<()> { | |||
| 90 | .await?; | 98 | .await?; |
| 91 | } | 99 | } |
| 92 | ["list"] => { | 100 | ["list"] => { |
| 93 | list_outputs = Some(list::run_list(&git_repo, &repo_ref, false).await?); | 101 | list_outputs = |
| 102 | Some(list::run_list(&git_repo, &repo_ref, &decoded_nostr_url, false).await?); | ||
| 94 | } | 103 | } |
| 95 | ["list", "for-push"] => { | 104 | ["list", "for-push"] => { |
| 96 | list_outputs = Some(list::run_list(&git_repo, &repo_ref, true).await?); | 105 | list_outputs = |
| 106 | Some(list::run_list(&git_repo, &repo_ref, &decoded_nostr_url, true).await?); | ||
| 97 | } | 107 | } |
| 98 | [] => { | 108 | [] => { |
| 99 | return Ok(()); | 109 | return Ok(()); |
diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs index 441c341..2c9c7e1 100644 --- a/src/bin/git_remote_nostr/push.rs +++ b/src/bin/git_remote_nostr/push.rs | |||
| @@ -15,7 +15,7 @@ use git_events::{ | |||
| 15 | }; | 15 | }; |
| 16 | use ngit::{ | 16 | use ngit::{ |
| 17 | client::{self, get_event_from_cache_by_id}, | 17 | client::{self, get_event_from_cache_by_id}, |
| 18 | git, | 18 | git::{self, nostr_url::NostrUrlDecoded}, |
| 19 | git_events::{self, get_event_root}, | 19 | git_events::{self, get_event_root}, |
| 20 | login::{self, get_curent_user}, | 20 | login::{self, get_curent_user}, |
| 21 | repo_ref, repo_state, | 21 | repo_ref, repo_state, |
| @@ -42,7 +42,7 @@ use crate::{ | |||
| 42 | pub async fn run_push( | 42 | pub async fn run_push( |
| 43 | git_repo: &Repo, | 43 | git_repo: &Repo, |
| 44 | repo_ref: &RepoRef, | 44 | repo_ref: &RepoRef, |
| 45 | nostr_remote_url: &str, | 45 | decoded_nostr_url: &NostrUrlDecoded, |
| 46 | stdin: &Stdin, | 46 | stdin: &Stdin, |
| 47 | initial_refspec: &str, | 47 | initial_refspec: &str, |
| 48 | client: &Client, | 48 | client: &Client, |
| @@ -66,7 +66,7 @@ pub async fn run_push( | |||
| 66 | 66 | ||
| 67 | let list_outputs = match list_outputs { | 67 | let list_outputs = match list_outputs { |
| 68 | Some(outputs) => outputs, | 68 | Some(outputs) => outputs, |
| 69 | _ => list_from_remotes(&term, git_repo, &repo_ref.git_server)?, | 69 | _ => list_from_remotes(&term, git_repo, &repo_ref.git_server, decoded_nostr_url), |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | let nostr_state = get_state_from_cache(git_repo.get_path()?, repo_ref).await; | 72 | let nostr_state = get_state_from_cache(git_repo.get_path()?, repo_ref).await; |
| @@ -154,7 +154,7 @@ pub async fn run_push( | |||
| 154 | &term, | 154 | &term, |
| 155 | repo_ref, | 155 | repo_ref, |
| 156 | git_repo, | 156 | git_repo, |
| 157 | nostr_remote_url, | 157 | &decoded_nostr_url.original_string, |
| 158 | &signer, | 158 | &signer, |
| 159 | &git_server_refspecs, | 159 | &git_server_refspecs, |
| 160 | ) | 160 | ) |
| @@ -306,8 +306,12 @@ pub async fn run_push( | |||
| 306 | } | 306 | } |
| 307 | let (_, to) = refspec_to_from_to(refspec)?; | 307 | let (_, to) = refspec_to_from_to(refspec)?; |
| 308 | println!("ok {to}"); | 308 | println!("ok {to}"); |
| 309 | update_remote_refs_pushed(&git_repo.git_repo, refspec, nostr_remote_url) | 309 | update_remote_refs_pushed( |
| 310 | .context("could not update remote_ref locally")?; | 310 | &git_repo.git_repo, |
| 311 | refspec, | ||
| 312 | &decoded_nostr_url.original_string, | ||
| 313 | ) | ||
| 314 | .context("could not update remote_ref locally")?; | ||
| 311 | } | 315 | } |
| 312 | 316 | ||
| 313 | // TODO make async - check gitlib2 callbacks work async | 317 | // TODO make async - check gitlib2 callbacks work async |