diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/bin/git_remote_nostr/fetch.rs | 84 | ||||
| -rw-r--r-- | src/bin/git_remote_nostr/push.rs | 23 | ||||
| -rw-r--r-- | src/bin/git_remote_nostr/utils.rs | 82 |
3 files changed, 121 insertions, 68 deletions
diff --git a/src/bin/git_remote_nostr/fetch.rs b/src/bin/git_remote_nostr/fetch.rs index 1b19347..1e38e0e 100644 --- a/src/bin/git_remote_nostr/fetch.rs +++ b/src/bin/git_remote_nostr/fetch.rs | |||
| @@ -18,6 +18,7 @@ use ngit::{ | |||
| 18 | use crate::utils::{ | 18 | use crate::utils::{ |
| 19 | fetch_or_list_error_is_not_authentication_failure, find_proposal_and_patches_by_branch_name, | 19 | fetch_or_list_error_is_not_authentication_failure, find_proposal_and_patches_by_branch_name, |
| 20 | get_oids_from_fetch_batch, get_open_proposals, get_read_protocols_to_try, join_with_and, | 20 | get_oids_from_fetch_batch, get_open_proposals, get_read_protocols_to_try, join_with_and, |
| 21 | report_on_sideband_progress, report_on_transfer_progress, ProgressStatus, TransferDirection, | ||
| 21 | }; | 22 | }; |
| 22 | 23 | ||
| 23 | pub async fn run_fetch( | 24 | pub async fn run_fetch( |
| @@ -187,31 +188,19 @@ fn fetch_from_git_server_url( | |||
| 187 | let mut fetch_options = git2::FetchOptions::new(); | 188 | let mut fetch_options = git2::FetchOptions::new(); |
| 188 | let mut remote_callbacks = git2::RemoteCallbacks::new(); | 189 | let mut remote_callbacks = git2::RemoteCallbacks::new(); |
| 189 | remote_callbacks.sideband_progress(|data| { | 190 | remote_callbacks.sideband_progress(|data| { |
| 190 | if let Ok(data) = str::from_utf8(data) { | 191 | report_on_sideband_progress(data, term); |
| 191 | let data = data | 192 | true |
| 192 | .split(['\n', '\r']) | 193 | }); |
| 193 | .find(|line| !line.is_empty()) | 194 | remote_callbacks.transfer_progress(|stats| { |
| 194 | .unwrap_or(""); | 195 | let _ = term.clear_last_lines(1); |
| 195 | if !data.is_empty() { | 196 | report_on_transfer_progress( |
| 196 | let s = format!("remote: {data}"); | 197 | &stats, |
| 197 | let _ = term.clear_last_lines(1); | 198 | term, |
| 198 | let _ = term.write_line(s.as_str()); | 199 | TransferDirection::Fetch, |
| 199 | if !s.contains('%') || s.contains("100%") { | 200 | ProgressStatus::InProgress, |
| 200 | // print it twice so the next sideband_progress doesn't delete it | 201 | ); |
| 201 | let _ = term.write_line(s.as_str()); | ||
| 202 | } | ||
| 203 | } | ||
| 204 | } | ||
| 205 | true | 202 | true |
| 206 | }); | 203 | }); |
| 207 | remote_callbacks.transfer_progress( | ||
| 208 | #[allow(clippy::cast_precision_loss)] | ||
| 209 | |stats| { | ||
| 210 | let _ = term.clear_last_lines(1); | ||
| 211 | report_on_transfer_progress(&stats, term, false); | ||
| 212 | true | ||
| 213 | }, | ||
| 214 | ); | ||
| 215 | 204 | ||
| 216 | if !dont_authenticate { | 205 | if !dont_authenticate { |
| 217 | remote_callbacks.credentials(auth.credentials(&git_config)); | 206 | remote_callbacks.credentials(auth.credentials(&git_config)); |
| @@ -220,50 +209,13 @@ fn fetch_from_git_server_url( | |||
| 220 | term.write_line("")?; | 209 | term.write_line("")?; |
| 221 | git_server_remote.download(oids, Some(&mut fetch_options))?; | 210 | git_server_remote.download(oids, Some(&mut fetch_options))?; |
| 222 | 211 | ||
| 223 | report_on_transfer_progress(&git_server_remote.stats(), term, true); | 212 | report_on_transfer_progress( |
| 213 | &git_server_remote.stats(), | ||
| 214 | term, | ||
| 215 | TransferDirection::Fetch, | ||
| 216 | ProgressStatus::Complete, | ||
| 217 | ); | ||
| 224 | 218 | ||
| 225 | git_server_remote.disconnect()?; | 219 | git_server_remote.disconnect()?; |
| 226 | Ok(()) | 220 | Ok(()) |
| 227 | } | 221 | } |
| 228 | |||
| 229 | #[allow(clippy::cast_precision_loss)] | ||
| 230 | #[allow(clippy::float_cmp)] | ||
| 231 | fn report_on_transfer_progress(stats: &git2::Progress<'_>, term: &console::Term, complete: bool) { | ||
| 232 | let total = stats.total_objects() as f64; | ||
| 233 | if total == 0.0 { | ||
| 234 | return; | ||
| 235 | } | ||
| 236 | let received = stats.received_objects() as f64; | ||
| 237 | let percentage = (received / total) * 100.0; | ||
| 238 | |||
| 239 | // Get the total received bytes | ||
| 240 | let received_bytes = stats.received_bytes() as f64; | ||
| 241 | |||
| 242 | // Determine whether to use KiB or MiB | ||
| 243 | let (size, unit) = if received_bytes >= (1024.0 * 1024.0) { | ||
| 244 | // Convert to MiB | ||
| 245 | (received_bytes / (1024.0 * 1024.0), "MiB") | ||
| 246 | } else { | ||
| 247 | // Convert to KiB | ||
| 248 | (received_bytes / 1024.0, "KiB") | ||
| 249 | }; | ||
| 250 | |||
| 251 | // Format the output for receiving objects | ||
| 252 | if received < total || complete { | ||
| 253 | let _ = term.write_line( | ||
| 254 | format!( | ||
| 255 | "Receiving objects: {percentage:.0}% ({received}/{total}) {size:.2} {unit}, done.\r" | ||
| 256 | ) | ||
| 257 | .as_str(), | ||
| 258 | ); | ||
| 259 | } | ||
| 260 | if received == total || complete { | ||
| 261 | let indexed_deltas = stats.indexed_deltas() as f64; | ||
| 262 | let total_deltas = stats.total_deltas() as f64; | ||
| 263 | let percentage = (indexed_deltas / total_deltas) * 100.0; | ||
| 264 | let _ = term.write_line( | ||
| 265 | format!("Resolving deltas: {percentage:.0}% ({indexed_deltas}/{total_deltas}) done.\r") | ||
| 266 | .as_str(), | ||
| 267 | ); | ||
| 268 | } | ||
| 269 | } | ||
diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs index 7f63eb0..5a19bb0 100644 --- a/src/bin/git_remote_nostr/push.rs +++ b/src/bin/git_remote_nostr/push.rs | |||
| @@ -38,7 +38,8 @@ use crate::{ | |||
| 38 | utils::{ | 38 | utils::{ |
| 39 | find_proposal_and_patches_by_branch_name, get_all_proposals, get_remote_name_by_url, | 39 | find_proposal_and_patches_by_branch_name, get_all_proposals, get_remote_name_by_url, |
| 40 | get_short_git_server_name, get_write_protocols_to_try, join_with_and, | 40 | get_short_git_server_name, get_write_protocols_to_try, join_with_and, |
| 41 | push_error_is_not_authentication_failure, read_line, | 41 | push_error_is_not_authentication_failure, read_line, report_on_sideband_progress, |
| 42 | report_on_transfer_progress, ProgressStatus, TransferDirection, | ||
| 42 | }, | 43 | }, |
| 43 | }; | 44 | }; |
| 44 | 45 | ||
| @@ -355,7 +356,11 @@ fn push_to_remote( | |||
| 355 | 356 | ||
| 356 | for protocol in &protocols_to_attempt { | 357 | for protocol in &protocols_to_attempt { |
| 357 | term.write_line( | 358 | term.write_line( |
| 358 | format!("fetching {} ref list over {protocol}...", server_url.short_name(),).as_str(), | 359 | format!( |
| 360 | "fetching {} ref list over {protocol}...", | ||
| 361 | server_url.short_name(), | ||
| 362 | ) | ||
| 363 | .as_str(), | ||
| 359 | )?; | 364 | )?; |
| 360 | 365 | ||
| 361 | let formatted_url = server_url.format_as(protocol, &decoded_nostr_url.user)?; | 366 | let formatted_url = server_url.format_as(protocol, &decoded_nostr_url.user)?; |
| @@ -419,6 +424,20 @@ fn push_to_remote_url( | |||
| 419 | } | 424 | } |
| 420 | Ok(()) | 425 | Ok(()) |
| 421 | }); | 426 | }); |
| 427 | remote_callbacks.transfer_progress(|stats| { | ||
| 428 | let _ = term.clear_last_lines(1); | ||
| 429 | report_on_transfer_progress( | ||
| 430 | &stats, | ||
| 431 | term, | ||
| 432 | TransferDirection::Push, | ||
| 433 | ProgressStatus::InProgress, | ||
| 434 | ); | ||
| 435 | true | ||
| 436 | }); | ||
| 437 | remote_callbacks.sideband_progress(|data| { | ||
| 438 | report_on_sideband_progress(data, term); | ||
| 439 | true | ||
| 440 | }); | ||
| 422 | push_options.remote_callbacks(remote_callbacks); | 441 | push_options.remote_callbacks(remote_callbacks); |
| 423 | git_server_remote.push(remote_refspecs, Some(&mut push_options))?; | 442 | git_server_remote.push(remote_refspecs, Some(&mut push_options))?; |
| 424 | let _ = git_server_remote.disconnect(); | 443 | let _ = git_server_remote.disconnect(); |
diff --git a/src/bin/git_remote_nostr/utils.rs b/src/bin/git_remote_nostr/utils.rs index 9be2580..1d65e3c 100644 --- a/src/bin/git_remote_nostr/utils.rs +++ b/src/bin/git_remote_nostr/utils.rs | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | use core::str; | ||
| 1 | use std::{ | 2 | use std::{ |
| 2 | collections::HashMap, | 3 | collections::HashMap, |
| 3 | io::{self, Stdin}, | 4 | io::{self, Stdin}, |
| @@ -307,6 +308,87 @@ pub fn error_might_be_authentication_related(error: &anyhow::Error) -> bool { | |||
| 307 | false | 308 | false |
| 308 | } | 309 | } |
| 309 | 310 | ||
| 311 | pub enum TransferDirection { | ||
| 312 | Fetch, | ||
| 313 | Push, | ||
| 314 | } | ||
| 315 | |||
| 316 | pub enum ProgressStatus { | ||
| 317 | InProgress, | ||
| 318 | Complete, | ||
| 319 | } | ||
| 320 | |||
| 321 | #[allow(clippy::cast_precision_loss)] | ||
| 322 | #[allow(clippy::float_cmp)] | ||
| 323 | #[allow(clippy::needless_pass_by_value)] | ||
| 324 | pub fn report_on_transfer_progress( | ||
| 325 | progress_stats: &git2::Progress<'_>, | ||
| 326 | term: &console::Term, | ||
| 327 | direction: TransferDirection, | ||
| 328 | status: ProgressStatus, | ||
| 329 | ) { | ||
| 330 | let total = progress_stats.total_objects() as f64; | ||
| 331 | if total == 0.0 { | ||
| 332 | return; | ||
| 333 | } | ||
| 334 | let received = progress_stats.received_objects() as f64; | ||
| 335 | let percentage = (received / total) * 100.0; | ||
| 336 | |||
| 337 | // Get the total received bytes | ||
| 338 | let received_bytes = progress_stats.received_bytes() as f64; | ||
| 339 | |||
| 340 | // Determine whether to use KiB or MiB | ||
| 341 | let (size, unit) = if received_bytes >= (1024.0 * 1024.0) { | ||
| 342 | // Convert to MiB | ||
| 343 | (received_bytes / (1024.0 * 1024.0), "MiB") | ||
| 344 | } else { | ||
| 345 | // Convert to KiB | ||
| 346 | (received_bytes / 1024.0, "KiB") | ||
| 347 | }; | ||
| 348 | |||
| 349 | // Format the output for receiving objects | ||
| 350 | if received < total || matches!(status, ProgressStatus::Complete) { | ||
| 351 | let _ = term.write_line( | ||
| 352 | format!( | ||
| 353 | "{} objects: {percentage:.0}% ({received}/{total}) {size:.2} {unit}, done.\r", | ||
| 354 | if matches!(direction, TransferDirection::Fetch) { | ||
| 355 | "Receiving" | ||
| 356 | } else { | ||
| 357 | "Writing" | ||
| 358 | }, | ||
| 359 | ) | ||
| 360 | .as_str(), | ||
| 361 | ); | ||
| 362 | } | ||
| 363 | if received == total || matches!(status, ProgressStatus::Complete) { | ||
| 364 | let indexed_deltas = progress_stats.indexed_deltas() as f64; | ||
| 365 | let total_deltas = progress_stats.total_deltas() as f64; | ||
| 366 | let percentage = (indexed_deltas / total_deltas) * 100.0; | ||
| 367 | let _ = term.write_line( | ||
| 368 | format!("Resolving deltas: {percentage:.0}% ({indexed_deltas}/{total_deltas}) done.\r") | ||
| 369 | .as_str(), | ||
| 370 | ); | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 374 | pub fn report_on_sideband_progress(data: &[u8], term: &console::Term) { | ||
| 375 | if let Ok(data) = str::from_utf8(data) { | ||
| 376 | let data = data | ||
| 377 | .split(['\n', '\r']) | ||
| 378 | .find(|line| !line.is_empty()) | ||
| 379 | .unwrap_or(""); | ||
| 380 | if !data.is_empty() { | ||
| 381 | let s = format!("remote: {data}"); | ||
| 382 | let _ = term.clear_last_lines(1); | ||
| 383 | let _ = term.write_line(s.as_str()); | ||
| 384 | if !s.contains('%') || s.contains("100%") { | ||
| 385 | // print it twice so the next sideband_progress doesn't delete it | ||
| 386 | let _ = term.write_line(s.as_str()); | ||
| 387 | } | ||
| 388 | } | ||
| 389 | } | ||
| 390 | } | ||
| 391 | |||
| 310 | #[cfg(test)] | 392 | #[cfg(test)] |
| 311 | mod tests { | 393 | mod tests { |
| 312 | use super::*; | 394 | use super::*; |