diff options
Diffstat (limited to 'src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs')
-rw-r--r-- | src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs new file mode 100644 index 000000000..3bec23a91 --- /dev/null +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs @@ -0,0 +1,75 @@ +use std::{ + fs, io, + path::{Path, PathBuf}, + sync::atomic::{AtomicUsize, Ordering}, +}; + +pub(crate) struct TestDir { + path: PathBuf, + keep: bool, +} + +impl TestDir { + pub(crate) fn new() -> TestDir { + let temp_dir = std::env::temp_dir(); + // On MacOS builders on GitHub actions, the temp dir is a symlink, and + // that causes problems down the line. Specifically: + // * Cargo may emit different PackageId depending on the working directory + // * rust-analyzer may fail to map LSP URIs to correct paths. + // + // Work-around this by canonicalizing. Note that we don't want to do this + // on *every* OS, as on windows `canonicalize` itself creates problems. + #[cfg(target_os = "macos")] + let temp_dir = temp_dir.canonicalize().unwrap(); + + let base = temp_dir.join("testdir"); + let pid = std::process::id(); + + static CNT: AtomicUsize = AtomicUsize::new(0); + for _ in 0..100 { + let cnt = CNT.fetch_add(1, Ordering::Relaxed); + let path = base.join(format!("{}_{}", pid, cnt)); + if path.is_dir() { + continue; + } + fs::create_dir_all(&path).unwrap(); + return TestDir { path, keep: false }; + } + panic!("Failed to create a temporary directory") + } + #[allow(unused)] + pub(crate) fn keep(mut self) -> TestDir { + self.keep = true; + self + } + pub(crate) fn path(&self) -> &Path { + &self.path + } +} + +impl Drop for TestDir { + fn drop(&mut self) { + if self.keep { + return; + } + remove_dir_all(&self.path).unwrap_or_else(|err| { + panic!("failed to remove temporary directory {}: {}", self.path.display(), err) + }) + } +} + +#[cfg(not(windows))] +fn remove_dir_all(path: &Path) -> io::Result<()> { + fs::remove_dir_all(path) +} + +#[cfg(windows)] +fn remove_dir_all(path: &Path) -> io::Result<()> { + for _ in 0..99 { + if fs::remove_dir_all(path).is_ok() { + return Ok(()); + } + std::thread::sleep(std::time::Duration::from_millis(10)) + } + fs::remove_dir_all(path) +} |