upleb.uk

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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-11-13 17:18:35 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-11-13 22:08:56 +0000
commit82c7a95f6e9aa266d2f0d2035a0ce4f1715b62ad (patch)
tree9de47f91a6157f9361b2bf28618d89873a55227a
parentebab8d2aa487d1814e802c5a51b19d4bb1592e01 (diff)
feat(list): make list async and include sync report inline
copy relay fetching approach to async and reporting
-rw-r--r--src/bin/git_remote_nostr/list.rs16
-rw-r--r--src/bin/git_remote_nostr/push.rs8
-rw-r--r--src/bin/ngit/sub_commands/sync.rs10
-rw-r--r--src/lib/list.rs378
-rw-r--r--tests/git_remote_nostr/list.rs29
-rw-r--r--tests/git_remote_nostr/push.rs30
6 files changed, 367 insertions, 104 deletions
diff --git a/src/bin/git_remote_nostr/list.rs b/src/bin/git_remote_nostr/list.rs
index d06d202..7753ba1 100644
--- a/src/bin/git_remote_nostr/list.rs
+++ b/src/bin/git_remote_nostr/list.rs
@@ -8,7 +8,7 @@ use ngit::{
8 fetch::fetch_from_git_server, 8 fetch::fetch_from_git_server,
9 git::{self}, 9 git::{self},
10 git_events::{KIND_PULL_REQUEST, KIND_PULL_REQUEST_UPDATE, event_to_cover_letter, tag_value}, 10 git_events::{KIND_PULL_REQUEST, KIND_PULL_REQUEST_UPDATE, event_to_cover_letter, tag_value},
11 list::{generate_remote_sync_warnings, identify_remote_sync_issues, list_from_remotes}, 11 list::list_from_remotes,
12 login::get_curent_user, 12 login::get_curent_user,
13 repo_ref::{self}, 13 repo_ref::{self},
14 utils::{get_all_proposals, get_open_or_draft_proposals}, 14 utils::{get_all_proposals, get_open_or_draft_proposals},
@@ -27,23 +27,17 @@ pub async fn run_list(
27 27
28 let term = console::Term::stderr(); 28 let term = console::Term::stderr();
29 29
30 term.write_line("git servers: listing refs...")?;
30 let remote_states = list_from_remotes( 31 let remote_states = list_from_remotes(
31 &term, 32 &term,
32 git_repo, 33 git_repo,
33 &repo_ref.git_server, 34 &repo_ref.git_server,
34 &repo_ref.to_nostr_git_url(&None), 35 &repo_ref.to_nostr_git_url(&None),
35 ); 36 nostr_state.as_ref(),
37 )
38 .await;
36 39
37 let mut state = if let Some(nostr_state) = nostr_state { 40 let mut state = if let Some(nostr_state) = nostr_state {
38 // Identify sync issues using shared abstraction
39 let remote_issues = identify_remote_sync_issues(git_repo, &nostr_state, &remote_states);
40
41 // Generate and print warnings
42 let warnings = generate_remote_sync_warnings(&remote_issues, &remote_states);
43 for warning in warnings {
44 term.write_line(&warning)?;
45 }
46
47 nostr_state.state 41 nostr_state.state
48 } else { 42 } else {
49 let (state, _is_grasp_server) = repo_ref 43 let (state, _is_grasp_server) = repo_ref
diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs
index 12350e7..9cf2c52 100644
--- a/src/bin/git_remote_nostr/push.rs
+++ b/src/bin/git_remote_nostr/push.rs
@@ -69,14 +69,18 @@ pub async fn run_push(
69 69
70 let term = console::Term::stderr(); 70 let term = console::Term::stderr();
71 71
72 let list_outputs = list_outputs.unwrap_or_else(|| { 72 let list_outputs = if let Some(outputs) = list_outputs {
73 outputs
74 } else {
73 list_from_remotes( 75 list_from_remotes(
74 &term, 76 &term,
75 git_repo, 77 git_repo,
76 &repo_ref.git_server, 78 &repo_ref.git_server,
77 &repo_ref.to_nostr_git_url(&None), 79 &repo_ref.to_nostr_git_url(&None),
80 None,
78 ) 81 )
79 }); 82 .await
83 };
80 84
81 let existing_state = { 85 let existing_state = {
82 // if no state events - create from first git server listed 86 // if no state events - create from first git server listed
diff --git a/src/bin/ngit/sub_commands/sync.rs b/src/bin/ngit/sub_commands/sync.rs
index d84feb6..daebb1b 100644
--- a/src/bin/ngit/sub_commands/sync.rs
+++ b/src/bin/ngit/sub_commands/sync.rs
@@ -77,8 +77,14 @@ pub async fn launch(args: &SubCommandArgs) -> Result<()> {
77 77
78 let term = console::Term::stderr(); 78 let term = console::Term::stderr();
79 79
80 let remote_states = 80 let remote_states = list_from_remotes(
81 list_from_remotes(&term, &git_repo, &repo_ref.git_server, &decoded_nostr_url); 81 &term,
82 &git_repo,
83 &repo_ref.git_server,
84 &decoded_nostr_url,
85 Some(&nostr_state),
86 )
87 .await;
82 88
83 let missing_refs = 89 let missing_refs =
84 fetch_missing_refs(&git_repo, &nostr_state, &remote_states, &decoded_nostr_url); 90 fetch_missing_refs(&git_repo, &nostr_state, &remote_states, &decoded_nostr_url);
diff --git a/src/lib/list.rs b/src/lib/list.rs
index 08b197c..69da792 100644
--- a/src/lib/list.rs
+++ b/src/lib/list.rs
@@ -1,7 +1,19 @@
1use std::{collections::HashMap, path::PathBuf, str::FromStr}; 1use std::{
2 collections::HashMap,
3 path::PathBuf,
4 str::FromStr,
5 sync::{
6 Arc,
7 atomic::{AtomicU64, Ordering},
8 },
9 time::Duration,
10};
2 11
3use anyhow::{Result, anyhow}; 12use anyhow::{Result, anyhow};
4use auth_git2::GitAuthenticator; 13use auth_git2::GitAuthenticator;
14use console::Style;
15use futures::stream::{self, StreamExt};
16use indicatif::{MultiProgress, ProgressBar, ProgressState, ProgressStyle};
5use nostr::hashes::sha1::Hash as Sha1Hash; 17use nostr::hashes::sha1::Hash as Sha1Hash;
6 18
7use crate::{ 19use crate::{
@@ -44,34 +56,321 @@ impl RemoteIssues {
44 } 56 }
45} 57}
46 58
47pub fn list_from_remotes( 59static GIT_SERVER_SUCCESS_THRESHOLD: f64 = 0.5; // 50% of servers must succeed to switch to short timeout
60
61fn git_server_long_timeout() -> u64 {
62 if std::env::var("NGITTEST").is_ok() {
63 1
64 } else {
65 60
66 }
67}
68
69fn git_server_short_timeout() -> u64 {
70 if std::env::var("NGITTEST").is_ok() {
71 1
72 } else {
73 5
74 }
75}
76
77fn git_server_pb_style(current_timeout: Arc<AtomicU64>) -> Result<ProgressStyle> {
78 Ok(ProgressStyle::with_template(" {spinner} {prefix} {msg}")?
79 .with_key(
80 "timeout_display",
81 move |_state: &ProgressState, w: &mut dyn std::fmt::Write| {
82 write!(w, "{}s", current_timeout.load(Ordering::Relaxed)).unwrap();
83 },
84 )
85 .tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ "))
86}
87
88fn git_server_pb_after_style(succeed: bool) -> ProgressStyle {
89 let symbol = if succeed {
90 console::style("✔".to_string())
91 .for_stderr()
92 .green()
93 .to_string()
94 } else {
95 console::style("✘".to_string())
96 .for_stderr()
97 .red()
98 .to_string()
99 };
100 ProgressStyle::with_template(&format!(" {symbol} {{prefix}} {{msg}}"))
101 .unwrap_or_else(|_| ProgressStyle::default_bar())
102}
103
104pub async fn list_from_remotes(
48 term: &console::Term, 105 term: &console::Term,
49 git_repo: &Repo, 106 git_repo: &Repo,
50 git_servers: &Vec<String>, 107 git_servers: &[String],
51 decoded_nostr_url: &NostrUrlDecoded, 108 decoded_nostr_url: &NostrUrlDecoded,
109 nostr_state: Option<&RepoState>,
52) -> HashMap<String, (HashMap<String, String>, bool)> { 110) -> HashMap<String, (HashMap<String, String>, bool)> {
111 if git_servers.is_empty() {
112 return HashMap::new();
113 }
114
115 let progress_reporter = if std::env::var("NGITTEST").is_err() {
116 MultiProgress::new()
117 } else {
118 MultiProgress::with_draw_target(indicatif::ProgressDrawTarget::hidden())
119 };
120
121 // Track successful servers for adaptive timeout
122 let success_count = Arc::new(AtomicU64::new(0));
123 let current_timeout = Arc::new(AtomicU64::new(git_server_long_timeout()));
124 let total_servers = git_servers.len() as u64;
125
126 // Calculate column width for alignment
127 let server_column_width = git_servers
128 .iter()
129 .map(|s| get_short_git_server_name(s).chars().count())
130 .max()
131 .unwrap_or(20)
132 + 2;
133
134 let futures: Vec<_> = git_servers
135 .iter()
136 .map(|url| {
137 let url = url.clone();
138 let is_grasp_server = is_grasp_server_clone_url(&url);
139 let success_count_clone = success_count.clone();
140 let current_timeout_clone = current_timeout.clone();
141 let progress_reporter_clone = progress_reporter.clone();
142 let decoded_nostr_url = decoded_nostr_url.clone();
143
144 async move {
145 let dim = Style::new().color256(247);
146 let server_name = get_short_git_server_name(&url);
147
148 let pb = if std::env::var("NGITTEST").is_err() {
149 match git_server_pb_style(current_timeout_clone.clone()) {
150 Ok(style) => {
151 let pb = progress_reporter_clone.add(
152 ProgressBar::new(1)
153 .with_prefix(
154 dim.apply_to(format!(
155 "{: <server_column_width$} connecting",
156 &server_name
157 ))
158 .to_string(),
159 )
160 .with_style(style),
161 );
162 pb.enable_steady_tick(Duration::from_millis(300));
163 Some(pb)
164 }
165 Err(_) => None,
166 }
167 } else {
168 None
169 };
170
171 fn update_progress_bar_with_error(
172 server_column_width: usize,
173 server_name: &str,
174 pb: Option<ProgressBar>,
175 error: &anyhow::Error,
176 ) {
177 if let Some(pb) = pb {
178 pb.set_style(git_server_pb_after_style(false));
179 pb.set_prefix(
180 Style::new()
181 .color256(247)
182 .apply_to(format!("{: <server_column_width$}", server_name))
183 .to_string(),
184 );
185 pb.finish_with_message(
186 console::style(error.to_string())
187 .for_stderr()
188 .red()
189 .to_string(),
190 );
191 }
192 }
193
194 // Create the list operation future - spawn_blocking to avoid blocking async runtime
195 let git_repo_path = git_repo.get_path().ok().map(|p| p.to_path_buf());
196 let url_clone = url.clone();
197 let decoded_nostr_url_clone = decoded_nostr_url.clone();
198 let pb_clone = pb.clone();
199
200 let list_future = async move {
201 match tokio::task::spawn_blocking(move || {
202 // Re-open repo in blocking thread (git2::Repository is not Send)
203 let git_repo = match git_repo_path {
204 Some(path) => Repo::from_path(&path).ok(),
205 None => None,
206 };
207
208 match git_repo {
209 Some(ref repo) => list_from_remote_sync(
210 repo,
211 &url_clone,
212 &decoded_nostr_url_clone,
213 is_grasp_server,
214 pb_clone.as_ref(),
215 ),
216 None => Err(anyhow!("failed to open git repository")),
217 }
218 })
219 .await
220 {
221 Ok(result) => result,
222 Err(e) => Err(anyhow!("task join error: {}", e)),
223 }
224 };
225
226 let timeout_future = async {
227 let check_interval = Duration::from_millis(100);
228 let long_timeout_end = tokio::time::Instant::now()
229 + Duration::from_secs(git_server_long_timeout());
230
231 loop {
232 let current_success_count = success_count_clone.load(Ordering::Relaxed);
233 let threshold = (total_servers as f64 * GIT_SERVER_SUCCESS_THRESHOLD).ceil() as u64;
234
235 if current_success_count >= threshold {
236 tokio::time::sleep(Duration::from_secs(git_server_short_timeout())).await;
237 return "short";
238 }
239
240 if tokio::time::Instant::now() >= long_timeout_end {
241 return "long";
242 }
243
244 tokio::time::sleep(check_interval).await;
245 }
246 };
247
248 let result = tokio::select! {
249 result = list_future => {
250 if result.is_ok() {
251 let new_count = success_count_clone.fetch_add(1, Ordering::Relaxed) + 1;
252 let threshold = (total_servers as f64 * GIT_SERVER_SUCCESS_THRESHOLD).ceil() as u64;
253
254 if new_count >= threshold {
255 current_timeout_clone.store(git_server_short_timeout(), Ordering::Relaxed);
256 }
257 }
258 result
259 }
260 timeout_type = timeout_future => {
261 Err(anyhow!("timeout after {}s",
262 if timeout_type == "long" { git_server_long_timeout() } else { git_server_short_timeout() }))
263 }
264 };
265
266 match result {
267 Err(error) => {
268 update_progress_bar_with_error(
269 server_column_width,
270 &server_name,
271 pb,
272 &error,
273 );
274 Err((url, error))
275 }
276 Ok(state) => {
277 // Determine sync status message and styling using existing functions
278 let status_msg = if state.is_empty() {
279 "empty repository".to_string()
280 } else if let Some(nostr_state) = nostr_state {
281 // Use existing generate_remote_sync_warnings to get detailed status
282 let mut temp_states = HashMap::new();
283 temp_states.insert(url.clone(), (state.clone(), is_grasp_server));
284 let remote_issues = identify_remote_sync_issues(git_repo, nostr_state, &temp_states);
285 let warnings = generate_remote_sync_warnings(&remote_issues, &temp_states);
286
287 if warnings.is_empty() {
288 "in sync".to_string()
289 } else {
290 // Extract the message after "WARNING: <server> "
291 let warning = &warnings[0];
292 let server_name = get_short_git_server_name(&url);
293 let prefix = format!("WARNING: {} ", server_name);
294 warning.strip_prefix(&prefix)
295 .unwrap_or(warning)
296 .to_string()
297 }
298 } else {
299 // No nostr state to compare against
300 "success".to_string()
301 };
302
303 let message_style = if status_msg == "empty repository" {
304 console::style(&status_msg).for_stderr().red()
305 } else if status_msg == "in sync" || status_msg == "success" {
306 console::style(&status_msg).for_stderr().green()
307 } else {
308 console::style(&status_msg).for_stderr().yellow()
309 };
310
311 let is_success = status_msg != "empty repository";
312
313 if let Some(pb) = pb {
314 pb.set_style(git_server_pb_after_style(is_success));
315 pb.set_prefix(
316 Style::new()
317 .color256(247)
318 .apply_to(format!("{: <server_column_width$}", &server_name))
319 .to_string(),
320 );
321 pb.finish_with_message(message_style.to_string());
322 }
323 Ok((url, state, is_grasp_server))
324 }
325 }
326 }
327 })
328 .collect();
329
330 let results = stream::iter(futures)
331 .buffer_unordered(15)
332 .collect::<Vec<Result<(String, HashMap<String, String>, bool), (String, anyhow::Error)>>>()
333 .await;
334
53 let mut remote_states = HashMap::new(); 335 let mut remote_states = HashMap::new();
54 let mut errors = HashMap::new(); 336 for result in results {
55 for url in git_servers { 337 match result {
56 let is_grasp_server = is_grasp_server_clone_url(url); 338 Ok((url, state, is_grasp_server)) => {
57 match list_from_remote(term, git_repo, url, decoded_nostr_url, is_grasp_server) { 339 remote_states.insert(url, (state, is_grasp_server));
58 Err(error) => {
59 errors.insert(url, error);
60 } 340 }
61 Ok(state) => { 341 Err((url, error)) => {
62 remote_states.insert(url.to_string(), (state, is_grasp_server)); 342 // Errors are already displayed in progress bars
343 let _ = term.write_line(&format!("failed to list from {}: {}", url, error));
63 } 344 }
64 } 345 }
65 } 346 }
347
66 remote_states 348 remote_states
67} 349}
68 350
351// Backward-compatible synchronous wrapper for use in non-async contexts
69pub fn list_from_remote( 352pub fn list_from_remote(
70 term: &console::Term, 353 _term: &console::Term,
354 git_repo: &Repo,
355 git_server_url: &str,
356 decoded_nostr_url: &NostrUrlDecoded,
357 is_grasp_server: bool,
358) -> Result<HashMap<String, String>> {
359 list_from_remote_sync(
360 git_repo,
361 git_server_url,
362 decoded_nostr_url,
363 is_grasp_server,
364 None,
365 )
366}
367
368fn list_from_remote_sync(
71 git_repo: &Repo, 369 git_repo: &Repo,
72 git_server_url: &str, 370 git_server_url: &str,
73 decoded_nostr_url: &NostrUrlDecoded, 371 decoded_nostr_url: &NostrUrlDecoded,
74 is_grasp_server: bool, 372 is_grasp_server: bool,
373 pb: Option<&ProgressBar>,
75) -> Result<HashMap<String, String>> { 374) -> Result<HashMap<String, String>> {
76 let server_url = git_server_url.parse::<CloneUrl>()?; 375 let server_url = git_server_url.parse::<CloneUrl>()?;
77 let protocols_to_attempt = 376 let protocols_to_attempt =
@@ -81,13 +380,15 @@ pub fn list_from_remote(
81 let mut remote_state: Option<HashMap<String, String>> = None; 380 let mut remote_state: Option<HashMap<String, String>> = None;
82 381
83 for protocol in &protocols_to_attempt { 382 for protocol in &protocols_to_attempt {
84 term.write_line( 383 if let Some(pb) = pb {
85 format!( 384 // Only show protocol for non-grasp servers as they can failover to other
86 "fetching {} ref list over {protocol}...", 385 // protocols
87 server_url.short_name(), 386 if is_grasp_server {
88 ) 387 pb.set_message("".to_string());
89 .as_str(), 388 } else {
90 )?; 389 pb.set_message(format!("via {protocol}"));
390 }
391 }
91 392
92 let formatted_url = server_url.format_as(protocol)?; 393 let formatted_url = server_url.format_as(protocol)?;
93 394
@@ -96,46 +397,29 @@ pub fn list_from_remote(
96 &formatted_url, 397 &formatted_url,
97 decoded_nostr_url.ssh_key_file_path().as_ref(), 398 decoded_nostr_url.ssh_key_file_path().as_ref(),
98 [ServerProtocol::UnauthHttps, ServerProtocol::UnauthHttp].contains(protocol), 399 [ServerProtocol::UnauthHttps, ServerProtocol::UnauthHttp].contains(protocol),
99 term,
100 ); 400 );
101 401
102 match res { 402 match res {
103 Ok(state) => { 403 Ok(state) => {
104 remote_state = Some(state); 404 remote_state = Some(state);
105 if !is_grasp_server && !failed_protocols.is_empty() { 405 if !is_grasp_server && !failed_protocols.is_empty() {
106 term.write_line(
107 format!(
108 "list: succeeded over {protocol} from {}",
109 server_url.short_name(),
110 )
111 .as_str(),
112 )?;
113 let _ = 406 let _ =
114 set_protocol_preference(git_repo, protocol, &server_url, &Direction::Fetch); 407 set_protocol_preference(git_repo, protocol, &server_url, &Direction::Fetch);
115 } 408 }
116 break; 409 break;
117 } 410 }
118 Err(error) => { 411 Err(error) => {
119 if is_grasp_server {
120 term.write_line(&format!("list: failed: {error}"))?;
121 } else {
122 term.write_line(&format!(
123 "list: {formatted_url} failed over {protocol}{}: {error}",
124 if protocol == &ServerProtocol::Ssh {
125 if let Some(ssh_key_file) = &decoded_nostr_url.ssh_key_file_path() {
126 format!(" with ssh key from {ssh_key_file}")
127 } else {
128 String::new()
129 }
130 } else {
131 String::new()
132 }
133 ))?;
134 }
135 failed_protocols.push(protocol); 412 failed_protocols.push(protocol);
413 if failed_protocols.len() == protocols_to_attempt.len() {
414 // All protocols failed
415 if let Some(pb) = pb {
416 pb.set_message(format!("all protocols failed: {}", error));
417 }
418 }
136 } 419 }
137 } 420 }
138 } 421 }
422
139 if let Some(remote_state) = remote_state { 423 if let Some(remote_state) = remote_state {
140 Ok(remote_state) 424 Ok(remote_state)
141 } else { 425 } else {
@@ -149,9 +433,6 @@ pub fn list_from_remote(
149 "" 433 ""
150 }, 434 },
151 ); 435 );
152 if !is_grasp_server {
153 term.write_line(format!("list: {error}").as_str())?;
154 }
155 Err(error) 436 Err(error)
156 } 437 }
157} 438}
@@ -161,7 +442,6 @@ fn list_from_remote_url(
161 git_server_remote_url: &str, 442 git_server_remote_url: &str,
162 ssh_key_file: Option<&String>, 443 ssh_key_file: Option<&String>,
163 dont_authenticate: bool, 444 dont_authenticate: bool,
164 term: &console::Term,
165) -> Result<HashMap<String, String>> { 445) -> Result<HashMap<String, String>> {
166 let git_config = git_repo.git_repo.config()?; 446 let git_config = git_repo.git_repo.config()?;
167 447
@@ -185,9 +465,7 @@ fn list_from_remote_url(
185 if !dont_authenticate { 465 if !dont_authenticate {
186 remote_callbacks.credentials(auth.credentials(&git_config)); 466 remote_callbacks.credentials(auth.credentials(&git_config));
187 } 467 }
188 term.write_line("list: connecting...")?;
189 git_server_remote.connect_auth(git2::Direction::Fetch, Some(remote_callbacks), None)?; 468 git_server_remote.connect_auth(git2::Direction::Fetch, Some(remote_callbacks), None)?;
190 term.clear_last_lines(1)?;
191 let mut state = HashMap::new(); 469 let mut state = HashMap::new();
192 for head in git_server_remote.list()? { 470 for head in git_server_remote.list()? {
193 if let Some(symbolic_reference) = head.symref_target() { 471 if let Some(symbolic_reference) = head.symref_target() {
@@ -435,7 +713,7 @@ pub fn generate_remote_sync_warnings(
435 if let Some(state) = remote_state { 713 if let Some(state) = remote_state {
436 // Check if remote is completely empty 714 // Check if remote is completely empty
437 if state.is_empty() { 715 if state.is_empty() {
438 warnings.push(format!("WARNING: {remote_name} has no data.")); 716 warnings.push(format!("WARNING: {remote_name} has empty repository."));
439 continue; 717 continue;
440 } 718 }
441 719
diff --git a/tests/git_remote_nostr/list.rs b/tests/git_remote_nostr/list.rs
index 8723b54..88bd3f7 100644
--- a/tests/git_remote_nostr/list.rs
+++ b/tests/git_remote_nostr/list.rs
@@ -8,7 +8,7 @@ mod without_state_announcement {
8 #[serial] 8 #[serial]
9 async fn lists_head_and_2_branches_and_commit_ids_from_git_server() -> Result<()> { 9 async fn lists_head_and_2_branches_and_commit_ids_from_git_server() -> Result<()> {
10 let source_git_repo = prep_git_repo()?; 10 let source_git_repo = prep_git_repo()?;
11 let source_path = source_git_repo.dir.to_str().unwrap().to_string(); 11 let _source_path = source_git_repo.dir.to_str().unwrap().to_string();
12 std::fs::write(source_git_repo.dir.join("commit.md"), "some content")?; 12 std::fs::write(source_git_repo.dir.join("commit.md"), "some content")?;
13 let main_commit_id = source_git_repo.stage_and_commit("commit.md")?; 13 let main_commit_id = source_git_repo.stage_and_commit("commit.md")?;
14 14
@@ -41,8 +41,7 @@ mod without_state_announcement {
41 let cli_tester_handle = std::thread::spawn(move || -> Result<()> { 41 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
42 let mut p = cli_tester_after_fetch(&git_repo)?; 42 let mut p = cli_tester_after_fetch(&git_repo)?;
43 p.send_line("list")?; 43 p.send_line("list")?;
44 p.expect(format!("fetching {source_path} ref list over filesystem...\r\n").as_str())?; 44 p.expect("git servers: listing refs...\r\n")?;
45 p.expect("list: connecting...\r\n\r")?;
46 // println!("{}", p.expect_eventually("\r\n\r\n")?); 45 // println!("{}", p.expect_eventually("\r\n\r\n")?);
47 let res = p.expect_eventually("\r\n\r\n")?; 46 let res = p.expect_eventually("\r\n\r\n")?;
48 p.exit()?; 47 p.exit()?;
@@ -90,7 +89,7 @@ mod with_state_announcement {
90 #[serial] 89 #[serial]
91 async fn lists_head_and_2_branches_and_commit_ids_announcement() -> Result<()> { 90 async fn lists_head_and_2_branches_and_commit_ids_announcement() -> Result<()> {
92 let (state_event, source_git_repo) = generate_repo_with_state_event().await?; 91 let (state_event, source_git_repo) = generate_repo_with_state_event().await?;
93 let source_path = source_git_repo.dir.to_str().unwrap().to_string(); 92 let _source_path = source_git_repo.dir.to_str().unwrap().to_string();
94 93
95 let main_commit_id = source_git_repo.get_tip_of_local_branch("main")?; 94 let main_commit_id = source_git_repo.get_tip_of_local_branch("main")?;
96 let example_commit_id = source_git_repo.get_tip_of_local_branch("example-branch")?; 95 let example_commit_id = source_git_repo.get_tip_of_local_branch("example-branch")?;
@@ -119,10 +118,7 @@ mod with_state_announcement {
119 let cli_tester_handle = std::thread::spawn(move || -> Result<()> { 118 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
120 let mut p = cli_tester_after_fetch(&git_repo)?; 119 let mut p = cli_tester_after_fetch(&git_repo)?;
121 p.send_line("list")?; 120 p.send_line("list")?;
122 p.expect( 121 p.expect("git servers: listing refs...\r\n")?;
123 format!("fetching {source_path} ref list over filesystem...\r\n").as_str(),
124 )?;
125 p.expect("list: connecting...\r\n\r")?;
126 // println!("{}", p.expect_eventually("\r\n\r\n")?); 122 // println!("{}", p.expect_eventually("\r\n\r\n")?);
127 let res = p.expect_eventually("\r\n\r\n")?; 123 let res = p.expect_eventually("\r\n\r\n")?;
128 p.exit()?; 124 p.exit()?;
@@ -163,7 +159,7 @@ mod with_state_announcement {
163 #[serial] 159 #[serial]
164 async fn anouncement_state_is_used() -> Result<()> { 160 async fn anouncement_state_is_used() -> Result<()> {
165 let (state_event, source_git_repo) = generate_repo_with_state_event().await?; 161 let (state_event, source_git_repo) = generate_repo_with_state_event().await?;
166 let source_path = source_git_repo.dir.to_str().unwrap().to_string(); 162 let _source_path = source_git_repo.dir.to_str().unwrap().to_string();
167 let main_original_commit_id = source_git_repo.get_tip_of_local_branch("main")?; 163 let main_original_commit_id = source_git_repo.get_tip_of_local_branch("main")?;
168 164
169 { 165 {
@@ -203,13 +199,7 @@ mod with_state_announcement {
203 let cli_tester_handle = std::thread::spawn(move || -> Result<()> { 199 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
204 let mut p = cli_tester_after_fetch(&git_repo)?; 200 let mut p = cli_tester_after_fetch(&git_repo)?;
205 p.send_line("list")?; 201 p.send_line("list")?;
206 p.expect( 202 p.expect("git servers: listing refs...\r\n")?;
207 format!("fetching {source_path} ref list over filesystem...\r\n").as_str(),
208 )?;
209 p.expect("list: connecting...\r\n\r")?;
210 p.expect(
211 format!("WARNING: {source_path} is out of sync. main out of sync\r\n").as_str(),
212 )?;
213 203
214 // println!("{}", p.expect_eventually("\r\n\r\n")?); 204 // println!("{}", p.expect_eventually("\r\n\r\n")?);
215 let res = p.expect_eventually("\r\n\r\n")?; 205 let res = p.expect_eventually("\r\n\r\n")?;
@@ -255,7 +245,7 @@ mod with_state_announcement {
255 #[serial] 245 #[serial]
256 async fn open_proposal_listed_in_prs_namespace() -> Result<()> { 246 async fn open_proposal_listed_in_prs_namespace() -> Result<()> {
257 let (state_event, source_git_repo) = generate_repo_with_state_event().await?; 247 let (state_event, source_git_repo) = generate_repo_with_state_event().await?;
258 let source_path = source_git_repo.dir.to_str().unwrap().to_string(); 248 let _source_path = source_git_repo.dir.to_str().unwrap().to_string();
259 249
260 let main_commit_id = source_git_repo.get_tip_of_local_branch("main")?; 250 let main_commit_id = source_git_repo.get_tip_of_local_branch("main")?;
261 let example_commit_id = source_git_repo.get_tip_of_local_branch("example-branch")?; 251 let example_commit_id = source_git_repo.get_tip_of_local_branch("example-branch")?;
@@ -287,10 +277,7 @@ mod with_state_announcement {
287 277
288 let mut p = cli_tester_after_fetch(&git_repo)?; 278 let mut p = cli_tester_after_fetch(&git_repo)?;
289 p.send_line("list")?; 279 p.send_line("list")?;
290 p.expect( 280 p.expect("git servers: listing refs...\r\n")?;
291 format!("fetching {source_path} ref list over filesystem...\r\n").as_str(),
292 )?;
293 p.expect("list: connecting...\r\n\r")?;
294 // println!("{}", p.expect_eventually("\r\n\r\n")?); 281 // println!("{}", p.expect_eventually("\r\n\r\n")?);
295 let res = p.expect_eventually("\r\n\r\n")?; 282 let res = p.expect_eventually("\r\n\r\n")?;
296 283
diff --git a/tests/git_remote_nostr/push.rs b/tests/git_remote_nostr/push.rs
index 647a2f3..404d07f 100644
--- a/tests/git_remote_nostr/push.rs
+++ b/tests/git_remote_nostr/push.rs
@@ -845,7 +845,7 @@ async fn pushes_to_all_git_servers_listed_and_ok_printed() -> Result<()> {
845async fn proposal_three_way_merge_commit_pushed_to_main_leads_to_status_event_issued() -> Result<()> 845async fn proposal_three_way_merge_commit_pushed_to_main_leads_to_status_event_issued() -> Result<()>
846{ 846{
847 let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?; 847 let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?;
848 let source_path = source_git_repo.dir.to_str().unwrap().to_string(); 848 let _source_path = source_git_repo.dir.to_str().unwrap().to_string();
849 849
850 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( 850 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
851 Relay::new(8051, None, None), 851 Relay::new(8051, None, None),
@@ -881,8 +881,7 @@ async fn proposal_three_way_merge_commit_pushed_to_main_leads_to_status_event_is
881 881
882 let mut p = CliTester::new_git_with_remote_helper_from_dir(&git_repo.dir, ["push"]); 882 let mut p = CliTester::new_git_with_remote_helper_from_dir(&git_repo.dir, ["push"]);
883 cli_expect_nostr_fetch(&mut p)?; 883 cli_expect_nostr_fetch(&mut p)?;
884 p.expect(format!("fetching {source_path} ref list over filesystem...\r\n").as_str())?; 884 p.expect("git servers: listing refs...\r\n")?;
885 p.expect("list: connecting...\r\n")?;
886 p.expect_eventually("merge commit ")?; 885 p.expect_eventually("merge commit ")?;
887 // shorthand merge commit id appears in this gap 886 // shorthand merge commit id appears in this gap
888 p.expect_eventually(": create nostr proposal status event\r\n")?; 887 p.expect_eventually(": create nostr proposal status event\r\n")?;
@@ -1002,7 +1001,7 @@ async fn proposal_fast_forward_merge_commits_pushed_to_main_leads_to_status_even
1002-> Result<()> { 1001-> Result<()> {
1003 // 1002 //
1004 let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?; 1003 let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?;
1005 let source_path = source_git_repo.dir.to_str().unwrap().to_string(); 1004 let _source_path = source_git_repo.dir.to_str().unwrap().to_string();
1006 1005
1007 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( 1006 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
1008 Relay::new(8051, None, None), 1007 Relay::new(8051, None, None),
@@ -1035,8 +1034,7 @@ async fn proposal_fast_forward_merge_commits_pushed_to_main_leads_to_status_even
1035 1034
1036 let mut p = CliTester::new_git_with_remote_helper_from_dir(&git_repo.dir, ["push"]); 1035 let mut p = CliTester::new_git_with_remote_helper_from_dir(&git_repo.dir, ["push"]);
1037 cli_expect_nostr_fetch(&mut p)?; 1036 cli_expect_nostr_fetch(&mut p)?;
1038 p.expect(format!("fetching {source_path} ref list over filesystem...\r\n").as_str())?; 1037 p.expect("git servers: listing refs...\r\n")?;
1039 p.expect("list: connecting...\r\n")?;
1040 p.expect_eventually(format!( 1038 p.expect_eventually(format!(
1041 "fast-forward merge: create nostr proposal status event for {branch_name}\r\n" 1039 "fast-forward merge: create nostr proposal status event for {branch_name}\r\n"
1042 ))?; 1040 ))?;
@@ -1184,7 +1182,7 @@ async fn proposal_fast_forward_merge_commits_pushed_to_main_leads_to_status_even
1184async fn proposal_commits_applied_and_pushed_to_main_leads_to_status_event_issued() -> Result<()> { 1182async fn proposal_commits_applied_and_pushed_to_main_leads_to_status_event_issued() -> Result<()> {
1185 // 1183 //
1186 let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?; 1184 let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?;
1187 let source_path = source_git_repo.dir.to_str().unwrap().to_string(); 1185 let _source_path = source_git_repo.dir.to_str().unwrap().to_string();
1188 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( 1186 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
1189 Relay::new(8051, None, None), 1187 Relay::new(8051, None, None),
1190 Relay::new(8052, None, None), 1188 Relay::new(8052, None, None),
@@ -1222,8 +1220,7 @@ async fn proposal_commits_applied_and_pushed_to_main_leads_to_status_event_issue
1222 1220
1223 let mut p = CliTester::new_git_with_remote_helper_from_dir(&git_repo.dir, ["push"]); 1221 let mut p = CliTester::new_git_with_remote_helper_from_dir(&git_repo.dir, ["push"]);
1224 cli_expect_nostr_fetch(&mut p)?; 1222 cli_expect_nostr_fetch(&mut p)?;
1225 p.expect(format!("fetching {source_path} ref list over filesystem...\r\n").as_str())?; 1223 p.expect("git servers: listing refs...\r\n")?;
1226 p.expect("list: connecting...\r\n")?;
1227 p.expect_eventually(format!( 1224 p.expect_eventually(format!(
1228 "applied commits from proposal: create nostr proposal status event for {branch_name}\r\n" ))?; 1225 "applied commits from proposal: create nostr proposal status event for {branch_name}\r\n" ))?;
1229 // status updates printed here 1226 // status updates printed here
@@ -1354,7 +1351,7 @@ async fn proposal_commits_applied_and_pushed_to_main_leads_to_status_event_issue
1354#[serial] 1351#[serial]
1355async fn push_2_commits_to_existing_proposal() -> Result<()> { 1352async fn push_2_commits_to_existing_proposal() -> Result<()> {
1356 let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?; 1353 let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?;
1357 let source_path = source_git_repo.dir.to_str().unwrap().to_string(); 1354 let _source_path = source_git_repo.dir.to_str().unwrap().to_string();
1358 1355
1359 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( 1356 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
1360 Relay::new(8051, None, None), 1357 Relay::new(8051, None, None),
@@ -1384,8 +1381,7 @@ async fn push_2_commits_to_existing_proposal() -> Result<()> {
1384 1381
1385 let mut p = CliTester::new_git_with_remote_helper_from_dir(&git_repo.dir, ["push"]); 1382 let mut p = CliTester::new_git_with_remote_helper_from_dir(&git_repo.dir, ["push"]);
1386 cli_expect_nostr_fetch(&mut p)?; 1383 cli_expect_nostr_fetch(&mut p)?;
1387 p.expect(format!("fetching {source_path} ref list over filesystem...\r\n").as_str())?; 1384 p.expect("git servers: listing refs...\r\n")?;
1388 p.expect("list: connecting...\r\n\r")?;
1389 p.expect_eventually_and_print(format!("To {}\r\n", get_nostr_remote_url()?).as_str())?; 1385 p.expect_eventually_and_print(format!("To {}\r\n", get_nostr_remote_url()?).as_str())?;
1390 let output = p.expect_end_eventually()?; 1386 let output = p.expect_end_eventually()?;
1391 1387
@@ -1500,7 +1496,7 @@ async fn push_2_commits_to_existing_proposal() -> Result<()> {
1500#[serial] 1496#[serial]
1501async fn force_push_creates_proposal_revision() -> Result<()> { 1497async fn force_push_creates_proposal_revision() -> Result<()> {
1502 let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?; 1498 let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?;
1503 let source_path = source_git_repo.dir.to_str().unwrap().to_string(); 1499 let _source_path = source_git_repo.dir.to_str().unwrap().to_string();
1504 1500
1505 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( 1501 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
1506 Relay::new(8051, None, None), 1502 Relay::new(8051, None, None),
@@ -1539,8 +1535,7 @@ async fn force_push_creates_proposal_revision() -> Result<()> {
1539 let mut p = 1535 let mut p =
1540 CliTester::new_git_with_remote_helper_from_dir(&git_repo.dir, ["push", "--force"]); 1536 CliTester::new_git_with_remote_helper_from_dir(&git_repo.dir, ["push", "--force"]);
1541 cli_expect_nostr_fetch(&mut p)?; 1537 cli_expect_nostr_fetch(&mut p)?;
1542 p.expect(format!("fetching {source_path} ref list over filesystem...\r\n").as_str())?; 1538 p.expect("git servers: listing refs...\r\n")?;
1543 p.expect("list: connecting...\r\n")?;
1544 p.expect_eventually_and_print(format!("To {}\r\n", get_nostr_remote_url()?).as_str())?; 1539 p.expect_eventually_and_print(format!("To {}\r\n", get_nostr_remote_url()?).as_str())?;
1545 let output = p.expect_end_eventually()?; 1540 let output = p.expect_end_eventually()?;
1546 1541
@@ -1659,7 +1654,7 @@ async fn force_push_creates_proposal_revision() -> Result<()> {
1659#[serial] 1654#[serial]
1660async fn push_new_pr_branch_creates_proposal() -> Result<()> { 1655async fn push_new_pr_branch_creates_proposal() -> Result<()> {
1661 let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?; 1656 let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?;
1662 let source_path = source_git_repo.dir.to_str().unwrap().to_string(); 1657 let _source_path = source_git_repo.dir.to_str().unwrap().to_string();
1663 1658
1664 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( 1659 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
1665 Relay::new(8051, None, None), 1660 Relay::new(8051, None, None),
@@ -1693,8 +1688,7 @@ async fn push_new_pr_branch_creates_proposal() -> Result<()> {
1693 ["push", "-u", "origin", branch_name], 1688 ["push", "-u", "origin", branch_name],
1694 ); 1689 );
1695 cli_expect_nostr_fetch(&mut p)?; 1690 cli_expect_nostr_fetch(&mut p)?;
1696 p.expect(format!("fetching {source_path} ref list over filesystem...\r\n").as_str())?; 1691 p.expect("git servers: listing refs...\r\n")?;
1697 p.expect("list: connecting...\r\n\r")?;
1698 p.expect_eventually_and_print(format!("To {}\r\n", get_nostr_remote_url()?).as_str())?; 1692 p.expect_eventually_and_print(format!("To {}\r\n", get_nostr_remote_url()?).as_str())?;
1699 let output = p.expect_end_eventually()?; 1693 let output = p.expect_end_eventually()?;
1700 1694