diff --git a/crates/cargo-test-macro/src/lib.rs b/crates/cargo-test-macro/src/lib.rs index dae129ade66..11d417df8ac 100644 --- a/crates/cargo-test-macro/src/lib.rs +++ b/crates/cargo-test-macro/src/lib.rs @@ -31,8 +31,12 @@ pub fn cargo_test(attr: TokenStream, item: TokenStream) -> TokenStream { } }; - let mut new_body = - to_token_stream("let _test_guard = cargo_test_support::paths::init_root();"); + let mut new_body = to_token_stream( + r#"let _test_guard = { + let tmp_dir = option_env!("CARGO_TARGET_TMPDIR"); + cargo_test_support::paths::init_root(tmp_dir) + };"#, + ); // If this is a `build_std` test (aka `tests/build-std/*.rs`) then they // only run on nightly and they only run when specifically instructed to diff --git a/crates/cargo-test-support/src/git.rs b/crates/cargo-test-support/src/git.rs index cc6b0c7462a..18c4646b37d 100644 --- a/crates/cargo-test-support/src/git.rs +++ b/crates/cargo-test-support/src/git.rs @@ -132,11 +132,12 @@ pub fn init(path: &Path) -> git2::Repository { } fn default_search_path() { - use crate::paths::GLOBAL_ROOT; + use crate::paths::global_root; use git2::{opts::set_search_path, ConfigLevel}; + static INIT: Once = Once::new(); INIT.call_once(|| unsafe { - let path = GLOBAL_ROOT.join("blank_git_search_path"); + let path = global_root().join("blank_git_search_path"); t!(set_search_path(ConfigLevel::System, &path)); t!(set_search_path(ConfigLevel::Global, &path)); t!(set_search_path(ConfigLevel::XDG, &path)); diff --git a/crates/cargo-test-support/src/paths.rs b/crates/cargo-test-support/src/paths.rs index 6e0dbf9d68b..192657dae58 100644 --- a/crates/cargo-test-support/src/paths.rs +++ b/crates/cargo-test-support/src/paths.rs @@ -14,28 +14,44 @@ use std::sync::Mutex; static CARGO_INTEGRATION_TEST_DIR: &str = "cit"; lazy_static! { - pub static ref GLOBAL_ROOT: PathBuf = { - let mut path = t!(env::current_exe()); - path.pop(); // chop off exe name - path.pop(); // chop off 'debug' - - // If `cargo test` is run manually then our path looks like - // `target/debug/foo`, in which case our `path` is already pointing at - // `target`. If, however, `cargo test --target $target` is used then the - // output is `target/$target/debug/foo`, so our path is pointing at - // `target/$target`. Here we conditionally pop the `$target` name. - if path.file_name().and_then(|s| s.to_str()) != Some("target") { - path.pop(); - } - - path.push(CARGO_INTEGRATION_TEST_DIR); - path.mkdir_p(); - path - }; + // TODO: Use `SyncOnceCell` when stable + static ref GLOBAL_ROOT: Mutex> = Mutex::new(None); static ref TEST_ROOTS: Mutex> = Default::default(); } +/// This is used when running cargo is pre-CARGO_TARGET_TMPDIR +/// TODO: Remove when CARGO_TARGET_TMPDIR grows old enough. +fn global_root_legacy() -> PathBuf { + let mut path = t!(env::current_exe()); + path.pop(); // chop off exe name + path.pop(); // chop off "deps" + path.push("tmp"); + path.mkdir_p(); + path +} + +fn set_global_root(tmp_dir: Option<&'static str>) { + let mut lock = GLOBAL_ROOT.lock().unwrap(); + if lock.is_none() { + let mut root = match tmp_dir { + Some(tmp_dir) => PathBuf::from(tmp_dir), + None => global_root_legacy(), + }; + + root.push(CARGO_INTEGRATION_TEST_DIR); + *lock = Some(root); + } +} + +pub fn global_root() -> PathBuf { + let lock = GLOBAL_ROOT.lock().unwrap(); + match lock.as_ref() { + Some(p) => p.clone(), + None => unreachable!("GLOBAL_ROOT not set yet"), + } +} + // We need to give each test a unique id. The test name could serve this // purpose, but the `test` crate doesn't have a way to obtain the current test // name.[*] Instead, we used the `cargo-test-macro` crate to automatically @@ -52,14 +68,15 @@ pub struct TestIdGuard { _private: (), } -pub fn init_root() -> TestIdGuard { +pub fn init_root(tmp_dir: Option<&'static str>) -> TestIdGuard { static NEXT_ID: AtomicUsize = AtomicUsize::new(0); - let id = NEXT_ID.fetch_add(1, Ordering::Relaxed); + let id = NEXT_ID.fetch_add(1, Ordering::SeqCst); TEST_ID.with(|n| *n.borrow_mut() = Some(id)); let guard = TestIdGuard { _private: () }; + set_global_root(tmp_dir); let r = root(); r.rm_rf(); r.mkdir_p(); @@ -80,7 +97,10 @@ pub fn root() -> PathBuf { order to be able to use the crate root.", ) }); - GLOBAL_ROOT.join(&format!("t{}", id)) + + let mut root = global_root(); + root.push(&format!("t{}", id)); + root } pub fn home() -> PathBuf {