-
Notifications
You must be signed in to change notification settings - Fork 15
feat(progress): show feedback while waiting on the remote #206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -64,6 +64,12 @@ fn spinner_style() -> ProgressStyle { | |||||||||||||
| ProgressStyle::with_template("{spinner:.cyan} {msg}").unwrap() | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /// Spinner that also shows how long the wait has lasted, for stages that block on | ||||||||||||||
| /// a remote and have nothing else to report. | ||||||||||||||
| fn waiting_style() -> ProgressStyle { | ||||||||||||||
| ProgressStyle::with_template("{spinner:.cyan} {msg} {elapsed:.dim}").unwrap() | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /// Create a download progress bar with a progress bar, bytes, and ETA. | ||||||||||||||
| pub fn create_download_job(prefix: &str) -> ProgressBar { | ||||||||||||||
| let pb = if progress_enabled() { | ||||||||||||||
|
|
@@ -77,6 +83,23 @@ pub fn create_download_job(prefix: &str) -> ProgressBar { | |||||||||||||
| pb | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /// Create a spinner job for a stage that blocks on a remote, showing elapsed time. | ||||||||||||||
| /// | ||||||||||||||
| /// Unlike [`create_spinner_job`] this ignores the `spinners` display setting: it is the | ||||||||||||||
| /// only feedback such a stage has, and without it the run looks stuck. | ||||||||||||||
| pub fn create_wait_job(message: &str) -> ProgressBar { | ||||||||||||||
| // Left out of MULTI entirely: adding a bar to it overrides the hidden draw | ||||||||||||||
| // target, so a hidden bar added to it still draws. | ||||||||||||||
| if !progress_enabled() { | ||||||||||||||
| return ProgressBar::hidden(); | ||||||||||||||
| } | ||||||||||||||
| let pb = MULTI.add(ProgressBar::new_spinner()); | ||||||||||||||
| pb.set_style(waiting_style()); | ||||||||||||||
| pb.set_message(message.to_string()); | ||||||||||||||
| pb.enable_steady_tick(Duration::from_millis(100)); | ||||||||||||||
| pb | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /// Create a spinner job. | ||||||||||||||
| pub fn create_spinner_job(message: &str) -> ProgressBar { | ||||||||||||||
| let pb = if progress_enabled() && display_settings().spinners() { | ||||||||||||||
|
|
@@ -93,17 +116,25 @@ pub fn create_spinner_job(message: &str) -> ProgressBar { | |||||||||||||
| /// Handle download progress events and update a progress bar. | ||||||||||||||
| pub fn handle_download_progress(state: Progress, pb: &ProgressBar) { | ||||||||||||||
| match state { | ||||||||||||||
| Progress::Preparing => { | ||||||||||||||
| pb.set_style(waiting_style()); | ||||||||||||||
| pb.set_message("connecting"); | ||||||||||||||
| } | ||||||||||||||
| Progress::Starting { | ||||||||||||||
| total, | ||||||||||||||
| } => { | ||||||||||||||
| pb.reset(); | ||||||||||||||
| pb.set_length(total); | ||||||||||||||
| pb.set_style(download_style()); | ||||||||||||||
| } | ||||||||||||||
| Progress::Resuming { | ||||||||||||||
| current, | ||||||||||||||
| total, | ||||||||||||||
| } => { | ||||||||||||||
| pb.reset(); | ||||||||||||||
| pb.set_length(total); | ||||||||||||||
| pb.set_position(current); | ||||||||||||||
| pb.set_style(download_style()); | ||||||||||||||
| } | ||||||||||||||
| Progress::Chunk { | ||||||||||||||
| current, .. | ||||||||||||||
|
|
@@ -119,6 +150,18 @@ pub fn handle_download_progress(state: Progress, pb: &ProgressBar) { | |||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /// Create the bar an operation's download uses, from the wait for the remote through | ||||||||||||||
| /// the transfer itself. It starts in the waiting state, which is where every | ||||||||||||||
| /// download begins. | ||||||||||||||
| fn create_download_bar(pkg_name: &str) -> ProgressBar { | ||||||||||||||
| let pb = MULTI.add(ProgressBar::new(0)); | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Respect the global progress setting. Line 156 always adds a visible progress bar. Download preparation events use this helper. Therefore, Proposed fix fn create_download_bar(pkg_name: &str) -> ProgressBar {
- let pb = MULTI.add(ProgressBar::new(0));
+ let pb = if progress_enabled() {
+ MULTI.add(ProgressBar::new(0))
+ } else {
+ MULTI.add(ProgressBar::hidden())
+ };
pb.set_style(waiting_style());📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
| pb.set_style(waiting_style()); | ||||||||||||||
| pb.set_prefix(colored_prefix(pkg_name)); | ||||||||||||||
| pb.set_message(format!("{pkg_name}: connecting")); | ||||||||||||||
| pb.enable_steady_tick(Duration::from_millis(100)); | ||||||||||||||
| pb | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /// Create a spinner-style progress bar for an operation. | ||||||||||||||
| fn create_op_spinner(msg: &str) -> ProgressBar { | ||||||||||||||
| let pb = if progress_enabled() && display_settings().spinners() { | ||||||||||||||
|
|
@@ -166,18 +209,40 @@ pub fn spawn_event_handler(receiver: Receiver<SoarEvent>) -> ProgressGuard { | |||||||||||||
| while let Ok(event) = receiver.recv() { | ||||||||||||||
| match event { | ||||||||||||||
| // ── Download lifecycle ────────────────────────────────── | ||||||||||||||
| // The bar is created here so the wait for a slow remote is | ||||||||||||||
| // visible, and reused once the transfer starts. | ||||||||||||||
| SoarEvent::DownloadPreparing { | ||||||||||||||
| op_id, | ||||||||||||||
| pkg_name, | ||||||||||||||
| .. | ||||||||||||||
| } => { | ||||||||||||||
| let is_new = !jobs.contains_key(&op_id); | ||||||||||||||
| let pb = jobs | ||||||||||||||
| .entry(op_id) | ||||||||||||||
| .or_insert_with(|| create_download_bar(&pkg_name)); | ||||||||||||||
| pb.set_style(waiting_style()); | ||||||||||||||
| pb.set_message(format!("{pkg_name}: connecting")); | ||||||||||||||
| if is_new { | ||||||||||||||
| reposition_batch!(batch_job, batch_msg); | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| SoarEvent::DownloadStarting { | ||||||||||||||
| op_id, | ||||||||||||||
| pkg_name, | ||||||||||||||
| total, | ||||||||||||||
| .. | ||||||||||||||
| } => { | ||||||||||||||
| let pb = MULTI.add(ProgressBar::new(total)); | ||||||||||||||
| let is_new = !jobs.contains_key(&op_id); | ||||||||||||||
| let pb = jobs | ||||||||||||||
| .entry(op_id) | ||||||||||||||
| .or_insert_with(|| create_download_bar(&pkg_name)); | ||||||||||||||
| pb.reset(); | ||||||||||||||
| pb.set_length(total); | ||||||||||||||
| // Set last: a draw between the two would paint a full bar at 0/0. | ||||||||||||||
| pb.set_style(download_style()); | ||||||||||||||
| pb.set_prefix(colored_prefix(&pkg_name)); | ||||||||||||||
| pb.enable_steady_tick(Duration::from_millis(100)); | ||||||||||||||
| jobs.insert(op_id, pb); | ||||||||||||||
| reposition_batch!(batch_job, batch_msg); | ||||||||||||||
| if is_new { | ||||||||||||||
| reposition_batch!(batch_job, batch_msg); | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| SoarEvent::DownloadResuming { | ||||||||||||||
| op_id, | ||||||||||||||
|
|
@@ -187,15 +252,13 @@ pub fn spawn_event_handler(receiver: Receiver<SoarEvent>) -> ProgressGuard { | |||||||||||||
| .. | ||||||||||||||
| } => { | ||||||||||||||
| let is_new = !jobs.contains_key(&op_id); | ||||||||||||||
| let pb = jobs.entry(op_id).or_insert_with(|| { | ||||||||||||||
| let pb = MULTI.add(ProgressBar::new(0)); | ||||||||||||||
| pb.set_style(download_style()); | ||||||||||||||
| pb.set_prefix(colored_prefix(&pkg_name)); | ||||||||||||||
| pb.enable_steady_tick(Duration::from_millis(100)); | ||||||||||||||
| pb | ||||||||||||||
| }); | ||||||||||||||
| let pb = jobs | ||||||||||||||
| .entry(op_id) | ||||||||||||||
| .or_insert_with(|| create_download_bar(&pkg_name)); | ||||||||||||||
| pb.reset(); | ||||||||||||||
| pb.set_length(total); | ||||||||||||||
| pb.set_position(current); | ||||||||||||||
| pb.set_style(download_style()); | ||||||||||||||
| if is_new { | ||||||||||||||
| reposition_batch!(batch_job, batch_msg); | ||||||||||||||
| } | ||||||||||||||
|
|
@@ -220,10 +283,14 @@ pub fn spawn_event_handler(receiver: Receiver<SoarEvent>) -> ProgressGuard { | |||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| SoarEvent::DownloadRetry { | ||||||||||||||
| op_id, .. | ||||||||||||||
| op_id, | ||||||||||||||
| pkg_name, | ||||||||||||||
| .. | ||||||||||||||
| } => { | ||||||||||||||
| if let Some(pb) = jobs.get(&op_id) { | ||||||||||||||
| pb.set_style(waiting_style()); | ||||||||||||||
| pb.set_position(0); | ||||||||||||||
| pb.set_message(format!("{pkg_name}: retrying")); | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| SoarEvent::DownloadAborted { | ||||||||||||||
|
|
@@ -239,13 +306,8 @@ pub fn spawn_event_handler(receiver: Receiver<SoarEvent>) -> ProgressGuard { | |||||||||||||
| .. | ||||||||||||||
| } => { | ||||||||||||||
| let is_new = !jobs.contains_key(&op_id); | ||||||||||||||
| jobs.entry(op_id).or_insert_with(|| { | ||||||||||||||
| let pb = MULTI.add(ProgressBar::new(0)); | ||||||||||||||
| pb.set_style(download_style()); | ||||||||||||||
| pb.set_prefix(colored_prefix(&pkg_name)); | ||||||||||||||
| pb.enable_steady_tick(Duration::from_millis(100)); | ||||||||||||||
| pb | ||||||||||||||
| }); | ||||||||||||||
| jobs.entry(op_id) | ||||||||||||||
| .or_insert_with(|| create_download_bar(&pkg_name)); | ||||||||||||||
| if is_new { | ||||||||||||||
| reposition_batch!(batch_job, batch_msg); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.