diff --git a/src/dist/component/package.rs b/src/dist/component/package.rs index 9ca699fb8a..b6a551c36b 100644 --- a/src/dist/component/package.rs +++ b/src/dist/component/package.rs @@ -8,6 +8,7 @@ use std::mem; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::sync::OnceLock; +use std::time::{Duration, Instant}; use anyhow::{Context, Result, anyhow, bail}; use tar::EntryType; @@ -88,7 +89,7 @@ impl> DirectoryPackage

{ } } - pub fn install<'a>( + pub async fn install<'a>( &self, target: &Components, name: &str, @@ -108,7 +109,15 @@ impl> DirectoryPackage

{ let manifest = utils::read_file("package manifest", &root.join("manifest.in"))?; let mut builder = target.add(name, tx); + let yield_timeout = Duration::from_millis(50); + let mut last_yield = Instant::now(); for l in manifest.lines() { + if Instant::now().duration_since(last_yield) > yield_timeout { + // Yield to the async runtime to keep things moving + tokio::task::yield_now().await; + last_yield = Instant::now(); + } + let part = ComponentPart::decode(l) .ok_or_else(|| RustupError::CorruptComponent(name.to_owned()))?; diff --git a/src/dist/manifestation.rs b/src/dist/manifestation.rs index b99775fe8b..5cbcf692da 100644 --- a/src/dist/manifestation.rs +++ b/src/dist/manifestation.rs @@ -232,7 +232,7 @@ impl Manifestation { if let Some((bin, downloaded)) = installable { cleanup_downloads.push(&bin.binary.hash); - tx = bin.install(downloaded, tx, self)?; + tx = bin.install(downloaded, tx, self).await?; } } @@ -410,7 +410,9 @@ impl Manifestation { let reader = utils::FileReaderWithProgress::new_file(&installer_file)?; let package = DirectoryPackage::compressed(reader, CompressionKind::GZip, dl_cfg)?; for component in package.components() { - tx = package.install(&self.installation, &component, None, tx)?; + tx = package + .install(&self.installation, &component, None, tx) + .await?; } // End transaction @@ -705,7 +707,7 @@ impl<'a> ComponentBinary<'a> { Ok((self, downloaded_file)) } - fn install<'t>( + async fn install<'t>( &self, installer_file: File, tx: Transaction<'t>, @@ -732,12 +734,14 @@ impl<'a> ComponentBinary<'a> { return Err(RustupError::CorruptComponent(short_name).into()); } - let tx = package.install( - &manifestation.installation, - &pkg_name, - Some(short_pkg_name), - tx, - ); + let tx = package + .install( + &manifestation.installation, + &pkg_name, + Some(short_pkg_name), + tx, + ) + .await; self.status.installed(); tx } diff --git a/tests/suite/dist_install.rs b/tests/suite/dist_install.rs index 2908815c97..53db264d1f 100644 --- a/tests/suite/dist_install.rs +++ b/tests/suite/dist_install.rs @@ -83,8 +83,8 @@ fn package_bad_version() { assert!(DirectoryPackage::new(tempdir.path().to_owned(), true).is_err()); } -#[test] -fn basic_install() { +#[tokio::test] +async fn basic_install() { let mock = MockInstallerBuilder { components: vec![MockComponentBuilder { name: "mycomponent".to_string(), @@ -98,7 +98,10 @@ fn basic_install() { let cx = DistContext::new(Some(mock)).unwrap(); let (tx, components, pkg) = cx.start().unwrap(); - let tx = pkg.install(&components, "mycomponent", None, tx).unwrap(); + let tx = pkg + .install(&components, "mycomponent", None, tx) + .await + .unwrap(); tx.commit(); assert!(utils::path_exists(cx.inst_dir.path().join("bin/foo"))); @@ -113,8 +116,8 @@ fn basic_install() { assert!(components.find("mycomponent").unwrap().is_some()); } -#[test] -fn multiple_component_install() { +#[tokio::test] +async fn multiple_component_install() { let mock = MockInstallerBuilder { components: vec![ MockComponentBuilder { @@ -130,8 +133,14 @@ fn multiple_component_install() { let cx = DistContext::new(Some(mock)).unwrap(); let (tx, components, pkg) = cx.start().unwrap(); - let tx = pkg.install(&components, "mycomponent", None, tx).unwrap(); - let tx = pkg.install(&components, "mycomponent2", None, tx).unwrap(); + let tx = pkg + .install(&components, "mycomponent", None, tx) + .await + .unwrap(); + let tx = pkg + .install(&components, "mycomponent2", None, tx) + .await + .unwrap(); tx.commit(); assert!(utils::path_exists(cx.inst_dir.path().join("bin/foo"))); @@ -141,8 +150,8 @@ fn multiple_component_install() { assert!(components.find("mycomponent2").unwrap().is_some()); } -#[test] -fn uninstall() { +#[tokio::test] +async fn uninstall() { let mock = MockInstallerBuilder { components: vec![ MockComponentBuilder { @@ -162,8 +171,14 @@ fn uninstall() { let cx = DistContext::new(Some(mock)).unwrap(); let (tx, components, pkg) = cx.start().unwrap(); - let tx = pkg.install(&components, "mycomponent", None, tx).unwrap(); - let tx = pkg.install(&components, "mycomponent2", None, tx).unwrap(); + let tx = pkg + .install(&components, "mycomponent", None, tx) + .await + .unwrap(); + let tx = pkg + .install(&components, "mycomponent2", None, tx) + .await + .unwrap(); tx.commit(); // Now uninstall @@ -193,8 +208,8 @@ fn uninstall_best_effort() { //unimplemented!() } -#[test] -fn component_bad_version() { +#[tokio::test] +async fn component_bad_version() { let mock = MockInstallerBuilder { components: vec![MockComponentBuilder { name: "mycomponent".to_string(), @@ -204,7 +219,10 @@ fn component_bad_version() { let cx = DistContext::new(Some(mock)).unwrap(); let (tx, components, pkg) = cx.start().unwrap(); - let tx = pkg.install(&components, "mycomponent", None, tx).unwrap(); + let tx = pkg + .install(&components, "mycomponent", None, tx) + .await + .unwrap(); tx.commit(); // Write a bogus version to the component manifest directory @@ -224,8 +242,8 @@ fn component_bad_version() { } // Installing to a prefix that doesn't exist creates it automatically -#[test] -fn install_to_prefix_that_does_not_exist() { +#[tokio::test] +async fn install_to_prefix_that_does_not_exist() { let mock = MockInstallerBuilder { components: vec![MockComponentBuilder { name: "mycomponent".to_string(), @@ -237,7 +255,10 @@ fn install_to_prefix_that_does_not_exist() { let does_not_exist = cx.inst_dir.path().join("does_not_exist"); cx.prefix = InstallPrefix::from(does_not_exist.clone()); let (tx, components, pkg) = cx.start().unwrap(); - let tx = pkg.install(&components, "mycomponent", None, tx).unwrap(); + let tx = pkg + .install(&components, "mycomponent", None, tx) + .await + .unwrap(); tx.commit(); // The directory that does not exist