mirror of
https://github.com/cargo-bins/cargo-binstall.git
synced 2025-04-24 22:30:03 +00:00
Perform startup/init code eagerly in entry::install_crates
(#880)
The startup/init code in `entry::install_crates` performs a lot of blocking operations, from testing if dir exists to reading from files and there is no `.await` in there until after the startup. There are also a few cases where `block_in_place` should be called (e.g. loading manifests, loading TLS certificates) but is missing. Most of the `Args` passed to `entry::install_crates` are actually consumed before the first `.await` point, so performing startup/init code eagerly would make the generated future much smaller, reduce codegen and also makes it easier to optimize. Signed-off-by: Jiahao XU <Jiahao_XU@outlook.com>
This commit is contained in:
parent
18bc81f46f
commit
c5d0b84aa6
3 changed files with 98 additions and 90 deletions
|
@ -35,29 +35,33 @@ impl Termination for MainExit {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MainExit {
|
impl MainExit {
|
||||||
pub fn new(result: Result<Result<()>, BinstallError>, done: Duration) -> Self {
|
pub fn new(res: Result<()>, done: Duration) -> Self {
|
||||||
result.map_or_else(MainExit::Error, |res| {
|
res.map(|()| MainExit::Success(Some(done)))
|
||||||
res.map(|()| MainExit::Success(Some(done)))
|
.unwrap_or_else(|err| {
|
||||||
.unwrap_or_else(|err| {
|
err.downcast::<BinstallError>()
|
||||||
err.downcast::<BinstallError>()
|
.map(MainExit::Error)
|
||||||
.map(MainExit::Error)
|
.unwrap_or_else(MainExit::Report)
|
||||||
.unwrap_or_else(MainExit::Report)
|
})
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function would start a tokio multithreading runtime,
|
/// This function would start a tokio multithreading runtime,
|
||||||
/// spawn a new task on it that runs `f`, then `block_on` it.
|
/// spawn a new task on it that runs `f()`, then `block_on` it.
|
||||||
///
|
///
|
||||||
/// It will cancel the future if user requested cancellation
|
/// It will cancel the future if user requested cancellation
|
||||||
/// via signal.
|
/// via signal.
|
||||||
pub fn run_tokio_main<F, T>(f: F) -> Result<T, BinstallError>
|
pub fn run_tokio_main<Func, Fut>(f: Func) -> Result<()>
|
||||||
where
|
where
|
||||||
F: Future<Output = T> + Send + 'static,
|
Func: FnOnce() -> Result<Option<Fut>>,
|
||||||
T: Send + 'static,
|
Fut: Future<Output = Result<()>> + Send + 'static,
|
||||||
{
|
{
|
||||||
let rt = Runtime::new()?;
|
let rt = Runtime::new().map_err(BinstallError::from)?;
|
||||||
let handle = AutoAbortJoinHandle::new(rt.spawn(f));
|
let _guard = rt.enter();
|
||||||
rt.block_on(cancel_on_user_sig_term(handle))
|
|
||||||
|
if let Some(fut) = f()? {
|
||||||
|
let handle = AutoAbortJoinHandle::new(rt.spawn(fut));
|
||||||
|
rt.block_on(cancel_on_user_sig_term(handle))?
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
env, fs,
|
env, fs,
|
||||||
|
future::Future,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
|
@ -35,7 +36,10 @@ use crate::{
|
||||||
ui::confirm,
|
ui::confirm,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub async fn install_crates(args: Args, jobserver_client: LazyJobserverClient) -> Result<()> {
|
pub fn install_crates(
|
||||||
|
args: Args,
|
||||||
|
jobserver_client: LazyJobserverClient,
|
||||||
|
) -> Result<Option<impl Future<Output = Result<()>>>> {
|
||||||
// Compute Resolvers
|
// Compute Resolvers
|
||||||
let mut cargo_install_fallback = false;
|
let mut cargo_install_fallback = false;
|
||||||
|
|
||||||
|
@ -63,7 +67,7 @@ pub async fn install_crates(args: Args, jobserver_client: LazyJobserverClient) -
|
||||||
|
|
||||||
if crate_names.peek().is_none() {
|
if crate_names.peek().is_none() {
|
||||||
debug!("Nothing to do");
|
debug!("Nothing to do");
|
||||||
return Ok(());
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Launch target detection
|
// Launch target detection
|
||||||
|
@ -131,53 +135,55 @@ pub async fn install_crates(args: Args, jobserver_client: LazyJobserverClient) -
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Collect results
|
Ok(Some(async move {
|
||||||
let mut resolution_fetchs = Vec::new();
|
// Collect results
|
||||||
let mut resolution_sources = Vec::new();
|
let mut resolution_fetchs = Vec::new();
|
||||||
|
let mut resolution_sources = Vec::new();
|
||||||
|
|
||||||
for task in tasks {
|
for task in tasks {
|
||||||
match task.await?? {
|
match task.await?? {
|
||||||
Resolution::AlreadyUpToDate => {}
|
Resolution::AlreadyUpToDate => {}
|
||||||
Resolution::Fetch(fetch) => {
|
Resolution::Fetch(fetch) => {
|
||||||
fetch.print(&binstall_opts);
|
fetch.print(&binstall_opts);
|
||||||
resolution_fetchs.push(fetch)
|
resolution_fetchs.push(fetch)
|
||||||
}
|
}
|
||||||
Resolution::InstallFromSource(source) => {
|
Resolution::InstallFromSource(source) => {
|
||||||
source.print();
|
source.print();
|
||||||
resolution_sources.push(source)
|
resolution_sources.push(source)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if resolution_fetchs.is_empty() && resolution_sources.is_empty() {
|
if resolution_fetchs.is_empty() && resolution_sources.is_empty() {
|
||||||
debug!("Nothing to do");
|
debug!("Nothing to do");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Confirm
|
// Confirm
|
||||||
if !dry_run && !no_confirm {
|
if !dry_run && !no_confirm {
|
||||||
confirm().await?;
|
confirm().await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
do_install_fetches(
|
do_install_fetches(
|
||||||
resolution_fetchs,
|
resolution_fetchs,
|
||||||
manifests,
|
manifests,
|
||||||
&binstall_opts,
|
&binstall_opts,
|
||||||
dry_run,
|
dry_run,
|
||||||
temp_dir,
|
temp_dir,
|
||||||
no_cleanup,
|
no_cleanup,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let tasks: Vec<_> = resolution_sources
|
let tasks: Vec<_> = resolution_sources
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|source| AutoAbortJoinHandle::spawn(source.install(binstall_opts.clone())))
|
.map(|source| AutoAbortJoinHandle::spawn(source.install(binstall_opts.clone())))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
for task in tasks {
|
for task in tasks {
|
||||||
task.await??;
|
task.await??;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_read_root_cert(path: &Path) -> Result<Option<Certificate>, BinstallError> {
|
fn do_read_root_cert(path: &Path) -> Result<Option<Certificate>, BinstallError> {
|
||||||
|
@ -228,43 +234,41 @@ fn compute_paths_and_load_manifests(
|
||||||
roots: Option<PathBuf>,
|
roots: Option<PathBuf>,
|
||||||
install_path: Option<PathBuf>,
|
install_path: Option<PathBuf>,
|
||||||
) -> Result<(PathBuf, Option<Manifests>, tempfile::TempDir)> {
|
) -> Result<(PathBuf, Option<Manifests>, tempfile::TempDir)> {
|
||||||
block_in_place(|| {
|
// Compute cargo_roots
|
||||||
// Compute cargo_roots
|
let cargo_roots = install_path::get_cargo_roots_path(roots).ok_or_else(|| {
|
||||||
let cargo_roots = install_path::get_cargo_roots_path(roots).ok_or_else(|| {
|
error!("No viable cargo roots path found of specified, try `--roots`");
|
||||||
error!("No viable cargo roots path found of specified, try `--roots`");
|
miette!("No cargo roots path found or specified")
|
||||||
miette!("No cargo roots path found or specified")
|
})?;
|
||||||
})?;
|
|
||||||
|
|
||||||
// Compute install directory
|
// Compute install directory
|
||||||
let (install_path, custom_install_path) =
|
let (install_path, custom_install_path) =
|
||||||
install_path::get_install_path(install_path, Some(&cargo_roots));
|
install_path::get_install_path(install_path, Some(&cargo_roots));
|
||||||
let install_path = install_path.ok_or_else(|| {
|
let install_path = install_path.ok_or_else(|| {
|
||||||
error!("No viable install path found of specified, try `--install-path`");
|
error!("No viable install path found of specified, try `--install-path`");
|
||||||
miette!("No install path found or specified")
|
miette!("No install path found or specified")
|
||||||
})?;
|
})?;
|
||||||
fs::create_dir_all(&install_path).map_err(BinstallError::Io)?;
|
fs::create_dir_all(&install_path).map_err(BinstallError::Io)?;
|
||||||
debug!("Using install path: {}", install_path.display());
|
debug!("Using install path: {}", install_path.display());
|
||||||
|
|
||||||
// Load manifests
|
// Load manifests
|
||||||
let manifests = if !custom_install_path {
|
let manifests = if !custom_install_path {
|
||||||
Some(Manifests::open_exclusive(&cargo_roots)?)
|
Some(Manifests::open_exclusive(&cargo_roots)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a temporary directory for downloads etc.
|
// Create a temporary directory for downloads etc.
|
||||||
//
|
//
|
||||||
// Put all binaries to a temporary directory under `dst` first, catching
|
// Put all binaries to a temporary directory under `dst` first, catching
|
||||||
// some failure modes (e.g., out of space) before touching the existing
|
// some failure modes (e.g., out of space) before touching the existing
|
||||||
// binaries. This directory will get cleaned up via RAII.
|
// binaries. This directory will get cleaned up via RAII.
|
||||||
let temp_dir = tempfile::Builder::new()
|
let temp_dir = tempfile::Builder::new()
|
||||||
.prefix("cargo-binstall")
|
.prefix("cargo-binstall")
|
||||||
.tempdir_in(&install_path)
|
.tempdir_in(&install_path)
|
||||||
.map_err(BinstallError::from)
|
.map_err(BinstallError::from)
|
||||||
.wrap_err("Creating a temporary directory failed.")?;
|
.wrap_err("Creating a temporary directory failed.")?;
|
||||||
|
|
||||||
Ok((install_path, manifests, temp_dir))
|
Ok((install_path, manifests, temp_dir))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return vec of (crate_name, current_version)
|
/// Return vec of (crate_name, current_version)
|
||||||
|
|
|
@ -32,7 +32,7 @@ fn main() -> MainExit {
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
|
||||||
let result = run_tokio_main(entry::install_crates(args, jobserver_client));
|
let result = run_tokio_main(|| entry::install_crates(args, jobserver_client));
|
||||||
|
|
||||||
let done = start.elapsed();
|
let done = start.elapsed();
|
||||||
debug!("run time: {done:?}");
|
debug!("run time: {done:?}");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue