diff --git a/src/binstall/install.rs b/src/binstall/install.rs index 777ebd53..6c1830ea 100644 --- a/src/binstall/install.rs +++ b/src/binstall/install.rs @@ -12,7 +12,7 @@ pub async fn install( resolution: Resolution, opts: Arc, desired_targets: DesiredTargets, - jobserver_client: jobserver::Client, + jobserver_client: LazyJobserverClient, ) -> Result<()> { match resolution { Resolution::Fetch { @@ -140,8 +140,10 @@ async fn install_from_package( async fn install_from_source( package: Package, target: &str, - jobserver_client: jobserver::Client, + lazy_jobserver_client: LazyJobserverClient, ) -> Result<()> { + let jobserver_client = lazy_jobserver_client.get().await?; + debug!( "Running `cargo install {} --version {} --target {target}`", package.name, package.version diff --git a/src/helpers/jobserver_client.rs b/src/helpers/jobserver_client.rs index 740fcc38..14a6c5f2 100644 --- a/src/helpers/jobserver_client.rs +++ b/src/helpers/jobserver_client.rs @@ -1,20 +1,35 @@ use std::num::NonZeroUsize; +use std::sync::Arc; use std::thread::available_parallelism; +use jobserver::Client; +use tokio::sync::OnceCell; + use crate::BinstallError; -pub fn create_jobserver_client() -> Result { - use jobserver::Client; +#[derive(Clone)] +pub struct LazyJobserverClient(Arc>); - // Safety: - // - // Client::from_env is unsafe because from_raw_fd is unsafe. - // It doesn't do anything that is actually unsafe, like - // dereferencing pointer. - if let Some(client) = unsafe { Client::from_env() } { - Ok(client) - } else { - let ncore = available_parallelism().map(NonZeroUsize::get).unwrap_or(1); - Ok(Client::new(ncore)?) +impl LazyJobserverClient { + /// This must be called at the start of the program since + /// `Client::from_env` requires that. + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + // Safety: + // + // Client::from_env is unsafe because from_raw_fd is unsafe. + // It doesn't do anything that is actually unsafe, like + // dereferencing pointer. + let opt = unsafe { Client::from_env() }; + Self(Arc::new(OnceCell::new_with(opt))) + } + + pub async fn get(&self) -> Result<&Client, BinstallError> { + self.0 + .get_or_try_init(|| async { + let ncore = available_parallelism().map(NonZeroUsize::get).unwrap_or(1); + Ok(Client::new(ncore)?) + }) + .await } } diff --git a/src/main.rs b/src/main.rs index fb64bf41..50bd5a48 100644 --- a/src/main.rs +++ b/src/main.rs @@ -160,10 +160,7 @@ impl Termination for MainExit { fn main() -> MainExit { // Create jobserver client - let jobserver_client = match create_jobserver_client() { - Ok(jobserver_client) => jobserver_client, - Err(binstall_err) => return MainExit::Error(binstall_err), - }; + let jobserver_client = LazyJobserverClient::new(); let start = Instant::now(); @@ -184,7 +181,7 @@ fn main() -> MainExit { }) } -async fn entry(jobserver_client: jobserver::Client) -> Result<()> { +async fn entry(jobserver_client: LazyJobserverClient) -> Result<()> { // Filter extraneous arg when invoked by cargo // `cargo run -- --help` gives ["target/debug/cargo-binstall", "--help"] // `cargo binstall --help` gives ["/home/ryan/.cargo/bin/cargo-binstall", "binstall", "--help"]