diff --git a/src/rustup-dist/src/manifestation.rs b/src/rustup-dist/src/manifestation.rs index 30ee8d42c46..affd80c5f0a 100644 --- a/src/rustup-dist/src/manifestation.rs +++ b/src/rustup-dist/src/manifestation.rs @@ -74,6 +74,55 @@ pub enum UpdateStatus { Unchanged, } +struct FileReaderWithProgress<'a> { + fh: std::fs::File, + notify_handler: &'a Fn(Notification), + sent_start: bool, + nbytes: u64, + flen: u64, +} + +impl<'a> FileReaderWithProgress<'a> { + fn new_file(path: &Path, notify_handler: &'a Fn(Notification)) -> Result { + Ok(FileReaderWithProgress { + fh: std::fs::File::open(path)?, + notify_handler, + sent_start: false, + nbytes: 0, + flen: 0, + }) + } +} + +impl<'a> std::io::Read for FileReaderWithProgress<'a> { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + if !self.sent_start { + // Send the start notifications + let flen = self.fh.metadata()?.len(); + self.flen = flen; + (self.notify_handler)(Notification::Utils( + rustup_utils::Notification::DownloadContentLengthReceived(flen), + )); + } + match self.fh.read(buf) { + Ok(nbytes) => { + self.nbytes += nbytes as u64; + if (nbytes == 0) || (self.flen == self.nbytes) { + (self.notify_handler)(Notification::Utils( + rustup_utils::Notification::DownloadFinished, + )); + } else { + (self.notify_handler)(Notification::Utils( + rustup_utils::Notification::DownloadDataReceived(&buf[0..nbytes]), + )); + } + Ok(nbytes) + } + Err(e) => Err(e), + } + } +} + impl Manifestation { /// Open the install prefix for updates from a distribution /// channel. The install prefix directory does not need to exist; @@ -200,13 +249,14 @@ impl Manifestation { let gz; let xz; + let reader = FileReaderWithProgress::new_file(&installer_file, notify_handler)?; let package: &Package = match format { Format::Gz => { - gz = TarGzPackage::new_file(&installer_file, temp_cfg)?; + gz = TarGzPackage::new(reader, temp_cfg)?; &gz } Format::Xz => { - xz = TarXzPackage::new_file(&installer_file, temp_cfg)?; + xz = TarXzPackage::new(reader, temp_cfg)?; &xz } };