diff --git a/crates/nu-test-support/src/commands.rs b/crates/nu-test-support/src/commands.rs index 61930da1b6..ae26b970a0 100644 --- a/crates/nu-test-support/src/commands.rs +++ b/crates/nu-test-support/src/commands.rs @@ -1,11 +1,27 @@ use std::{ io::Read, process::{Command, Stdio}, + sync::{ + atomic::{AtomicBool, Ordering::Relaxed}, + Mutex, + }, }; -pub fn ensure_binary_present(package: &str) { +static CARGO_BUILD_LOCK: Mutex<()> = Mutex::new(()); +static PLUGINS_BUILT: AtomicBool = AtomicBool::new(false); + +// This runs `cargo build --package nu_plugin_*` to ensure that all plugins +// have been built before plugin tests run. We use a lock to avoid multiple +// simultaneous `cargo build` invocations clobbering each other. +pub fn ensure_plugins_built() { + let _guard = CARGO_BUILD_LOCK.lock().expect("could not get mutex lock"); + + if PLUGINS_BUILT.load(Relaxed) { + return; + } + let cargo_path = env!("CARGO"); - let mut arguments = vec!["build", "--package", package, "--quiet"]; + let mut arguments = vec!["build", "--package", "nu_plugin_*", "--quiet"]; let profile = std::env::var("NUSHELL_CARGO_TARGET"); if let Ok(profile) = &profile { @@ -40,4 +56,6 @@ pub fn ensure_binary_present(package: &str) { if !success { panic!("cargo build failed"); } + + PLUGINS_BUILT.store(true, Relaxed); } diff --git a/crates/nu-test-support/src/macros.rs b/crates/nu-test-support/src/macros.rs index e3643ee2a3..7262194046 100644 --- a/crates/nu-test-support/src/macros.rs +++ b/crates/nu-test-support/src/macros.rs @@ -252,7 +252,7 @@ macro_rules! nu_with_plugins { let temp_plugin_file = temp.path().join("plugin.nu"); std::fs::File::create(&temp_plugin_file).expect("couldn't create temporary plugin file"); - $($crate::commands::ensure_binary_present($plugin_name);)+ + $crate::commands::ensure_plugins_built(); // TODO: the `$format` is a dummy empty string, but `plugin_name` is repeatable // just keep it here for now. Need to find a way to remove it.