Skip to content

Commit 0fb4407

Browse files
committed
dist: move Notifier and DownloadTracker into dist::download
1 parent 24d48bc commit 0fb4407

File tree

4 files changed

+161
-168
lines changed

4 files changed

+161
-168
lines changed

src/cli.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#[macro_use]
33
pub mod log;
44
pub mod common;
5-
mod download_tracker;
65
pub mod errors;
76
mod help;
87
mod job;

src/cli/common.rs

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::fmt::Display;
44
use std::fs;
55
use std::io::{BufRead, Write};
66
use std::path::{Path, PathBuf};
7-
use std::sync::{Arc, LazyLock, Mutex};
7+
use std::sync::{Arc, LazyLock};
88
use std::{cmp, env};
99

1010
use anyhow::{Context, Result, anyhow};
@@ -13,13 +13,12 @@ use termcolor::Color;
1313
use tracing::{error, info, warn};
1414
use tracing_subscriber::{EnvFilter, Registry, reload::Handle};
1515

16+
use crate::dist::download::Notifier;
1617
use crate::{
17-
cli::download_tracker::DownloadTracker,
1818
config::Cfg,
1919
dist::{TargetTriple, ToolchainDesc},
2020
errors::RustupError,
2121
install::UpdateStatus,
22-
notifications::Notification,
2322
process::{Attr, Process},
2423
toolchain::{LocalToolchainName, Toolchain, ToolchainName},
2524
utils,
@@ -121,22 +120,6 @@ pub(crate) fn read_line(process: &Process) -> Result<String> {
121120
.context("unable to read from stdin for confirmation")
122121
}
123122

124-
pub(super) struct Notifier {
125-
tracker: Mutex<DownloadTracker>,
126-
}
127-
128-
impl Notifier {
129-
pub(super) fn new(quiet: bool, process: &Process) -> Self {
130-
Self {
131-
tracker: Mutex::new(DownloadTracker::new(!quiet, process)),
132-
}
133-
}
134-
135-
pub(super) fn handle(&self, n: Notification<'_>) {
136-
self.tracker.lock().unwrap().handle_notification(&n);
137-
}
138-
}
139-
140123
#[tracing::instrument(level = "trace", skip(process))]
141124
pub(crate) fn set_globals(current_dir: PathBuf, quiet: bool, process: &Process) -> Result<Cfg<'_>> {
142125
let notifier = Notifier::new(quiet, process);

src/cli/download_tracker.rs

Lines changed: 0 additions & 144 deletions
This file was deleted.

src/dist/download.rs

Lines changed: 159 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1+
use std::collections::HashMap;
12
use std::fs;
23
use std::ops;
34
use std::path::{Path, PathBuf};
5+
use std::sync::Mutex;
6+
use std::time::{Duration, Instant};
47

58
use anyhow::{Context, Result, anyhow};
9+
use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget, ProgressStyle};
610
use sha2::{Digest, Sha256};
7-
use tracing::debug;
8-
use tracing::warn;
11+
use tracing::{debug, warn};
912
use url::Url;
1013

1114
use crate::config::Cfg;
1215
use crate::dist::temp;
13-
use crate::download::download_file;
14-
use crate::download::download_file_with_resume;
16+
use crate::download::{download_file, download_file_with_resume};
1517
use crate::errors::*;
1618
use crate::notifications::Notification;
1719
use crate::process::Process;
@@ -201,6 +203,159 @@ impl<'a> DownloadCfg<'a> {
201203
}
202204
}
203205

206+
pub(crate) struct Notifier {
207+
tracker: Mutex<DownloadTracker>,
208+
}
209+
210+
impl Notifier {
211+
pub(crate) fn new(quiet: bool, process: &Process) -> Self {
212+
Self {
213+
tracker: Mutex::new(DownloadTracker::new(!quiet, process)),
214+
}
215+
}
216+
217+
pub(crate) fn handle(&self, n: Notification<'_>) {
218+
self.tracker.lock().unwrap().handle_notification(&n);
219+
}
220+
}
221+
222+
/// Tracks download progress and displays information about it to a terminal.
223+
///
224+
/// *not* safe for tracking concurrent downloads yet - it is basically undefined
225+
/// what will happen.
226+
pub(crate) struct DownloadTracker {
227+
/// MultiProgress bar for the downloads.
228+
multi_progress_bars: MultiProgress,
229+
/// Mapping of URLs being downloaded to their corresponding progress bars.
230+
/// The `Option<Instant>` represents the instant where the download is being retried,
231+
/// allowing us delay the reappearance of the progress bar so that the user can see
232+
/// the message "retrying download" for at least a second.
233+
/// Without it, the progress bar would reappear immediately, not allowing the user to
234+
/// correctly see the message, before the progress bar starts again.
235+
file_progress_bars: HashMap<String, (ProgressBar, Option<Instant>)>,
236+
}
237+
238+
impl DownloadTracker {
239+
/// Creates a new DownloadTracker.
240+
pub(crate) fn new(display_progress: bool, process: &Process) -> Self {
241+
let multi_progress_bars = MultiProgress::with_draw_target(if display_progress {
242+
process.progress_draw_target()
243+
} else {
244+
ProgressDrawTarget::hidden()
245+
});
246+
247+
Self {
248+
multi_progress_bars,
249+
file_progress_bars: HashMap::new(),
250+
}
251+
}
252+
253+
pub(crate) fn handle_notification(&mut self, n: &Notification<'_>) {
254+
match *n {
255+
Notification::DownloadContentLengthReceived(content_len, url) => {
256+
if let Some(url) = url {
257+
self.content_length_received(content_len, url);
258+
}
259+
}
260+
Notification::DownloadDataReceived(data, url) => {
261+
if let Some(url) = url {
262+
self.data_received(data.len(), url);
263+
}
264+
}
265+
Notification::DownloadFinished(url) => {
266+
if let Some(url) = url {
267+
self.download_finished(url);
268+
}
269+
}
270+
Notification::DownloadFailed(url) => {
271+
self.download_failed(url);
272+
debug!("download failed");
273+
}
274+
Notification::DownloadingComponent(component, _, _, url) => {
275+
self.create_progress_bar(component.to_owned(), url.to_owned());
276+
}
277+
Notification::RetryingDownload(url) => {
278+
self.retrying_download(url);
279+
}
280+
}
281+
}
282+
283+
/// Creates a new ProgressBar for the given component.
284+
pub(crate) fn create_progress_bar(&mut self, component: String, url: String) {
285+
let pb = ProgressBar::hidden();
286+
pb.set_style(
287+
ProgressStyle::with_template(
288+
"{msg:>12.bold} [{bar:40}] {bytes}/{total_bytes} ({bytes_per_sec}, ETA: {eta})",
289+
)
290+
.unwrap()
291+
.progress_chars("## "),
292+
);
293+
pb.set_message(component);
294+
self.multi_progress_bars.add(pb.clone());
295+
self.file_progress_bars.insert(url, (pb, None));
296+
}
297+
298+
/// Sets the length for a new ProgressBar and gives it a style.
299+
pub(crate) fn content_length_received(&mut self, content_len: u64, url: &str) {
300+
if let Some((pb, _)) = self.file_progress_bars.get(url) {
301+
pb.reset();
302+
pb.set_length(content_len);
303+
}
304+
}
305+
306+
/// Notifies self that data of size `len` has been received.
307+
pub(crate) fn data_received(&mut self, len: usize, url: &str) {
308+
let Some((pb, retry_time)) = self.file_progress_bars.get_mut(url) else {
309+
return;
310+
};
311+
pb.inc(len as u64);
312+
if !retry_time.is_some_and(|instant| instant.elapsed() > Duration::from_secs(1)) {
313+
return;
314+
}
315+
*retry_time = None;
316+
pb.set_style(
317+
ProgressStyle::with_template(
318+
"{msg:>12.bold} [{bar:40}] {bytes}/{total_bytes} ({bytes_per_sec}, ETA: {eta})",
319+
)
320+
.unwrap()
321+
.progress_chars("## "),
322+
);
323+
}
324+
325+
/// Notifies self that the download has finished.
326+
pub(crate) fn download_finished(&mut self, url: &str) {
327+
let Some((pb, _)) = self.file_progress_bars.get(url) else {
328+
return;
329+
};
330+
pb.set_style(
331+
ProgressStyle::with_template("{msg:>12.bold} downloaded {total_bytes} in {elapsed}")
332+
.unwrap(),
333+
);
334+
pb.finish();
335+
}
336+
337+
/// Notifies self that the download has failed.
338+
pub(crate) fn download_failed(&mut self, url: &str) {
339+
let Some((pb, _)) = self.file_progress_bars.get(url) else {
340+
return;
341+
};
342+
pb.set_style(
343+
ProgressStyle::with_template("{msg:>12.bold} download failed after {elapsed}")
344+
.unwrap(),
345+
);
346+
pb.finish();
347+
}
348+
349+
/// Notifies self that the download is being retried.
350+
pub(crate) fn retrying_download(&mut self, url: &str) {
351+
let Some((pb, retry_time)) = self.file_progress_bars.get_mut(url) else {
352+
return;
353+
};
354+
*retry_time = Some(Instant::now());
355+
pb.set_style(ProgressStyle::with_template("{msg:>12.bold} retrying download").unwrap());
356+
}
357+
}
358+
204359
fn file_hash(path: &Path, notify_handler: &dyn Fn(Notification<'_>)) -> Result<String> {
205360
let mut hasher = Sha256::new();
206361
let mut downloaded = utils::FileReaderWithProgress::new_file(path, notify_handler)?;

0 commit comments

Comments
 (0)