current_dir

A utility crate that helps using set_current_dir() and current_dir() in a thread safe manner.
This is generally useful for #[test]s that depend on different current working directories each as they are run in multiple threads by default.
The current working directory is global to the whole process, so if you only use a single thread or you never change the current working directory, go ahead!
Otherwise, changing the current working directory without synchronising may lead to unexpected behaviour.
Cwd Example
# use std::error::Error;
# fn main() -> Result<(), Box<dyn Error>> {
use std::env::temp_dir;
use current_dir::*;
let mut locked_cwd = Cwd::mutex().lock()?;
locked_cwd.set(temp_dir())?;
# assert_eq!(locked_cwd.get()?, temp_dir());
# drop(locked_cwd);
#
# Ok(())
# }
or you can just use set_current_dir() and current_dir() with a locked current working directory.
# use std::error::Error;
# fn main() -> Result<(), Box<dyn Error>> {
use std::env::{set_current_dir, temp_dir};
use current_dir::*;
let locked_cwd = Cwd::mutex().lock()?;
set_current_dir(temp_dir())?;
# assert_eq!(locked_cwd.get()?, temp_dir());
# drop(locked_cwd);
#
# Ok(())
# }
# use std::error::Error;
# fn main() -> Result<(), Box<dyn Error>> {
use std::{env::temp_dir, fs::create_dir_all};
use current_dir::*;
#
# let test_dirs = temp_dir().join("sub/sub");
# if !test_dirs.exists() {
# create_dir_all(&test_dirs)?;
# }
let mut locked_cwd = Cwd::mutex().lock()?;
locked_cwd.set(temp_dir())?;
# assert_eq!(locked_cwd.get()?, temp_dir());
{
let mut cwd_guard = CwdGuard::try_from(&mut *locked_cwd)?;
cwd_guard.set("sub")?;
# assert_eq!(cwd_guard.get()?, temp_dir().join("sub"));
{
let mut sub_cwd_guard = CwdGuard::try_from(&mut cwd_guard)?;
sub_cwd_guard.set("sub")?;
# assert_eq!(sub_cwd_guard.get()?, temp_dir().join("sub/sub"));
{
let mut sub_sub_cwd_guard = CwdGuard::try_from(&mut sub_cwd_guard)?;
sub_sub_cwd_guard.set(temp_dir())?;
# assert_eq!(sub_sub_cwd_guard.get()?, temp_dir());
}
# assert_eq!(sub_cwd_guard.get()?, temp_dir().join("sub/sub"));
}
# assert_eq!(cwd_guard.get()?, temp_dir().join("sub"));
}
# assert_eq!(locked_cwd.get()?, temp_dir());
# drop(locked_cwd);
#
# Ok(())
# }
Poison cleanup Example
# use std::error::Error;
# fn main() -> Result<(), Box<dyn Error>> {
use std::{
env::temp_dir,
error::Error,
fs::{create_dir_all, remove_dir},
panic,
};
use current_dir::*;
let test_dir = temp_dir().join("cwd");
# if !test_dir.exists() {
# create_dir_all(&test_dir)?;
# }
panic::catch_unwind(|| {
let mut locked_cwd = Cwd::mutex().lock().unwrap();
locked_cwd.set(&test_dir)?;
let cwd_guard = CwdGuard::try_from(&mut *locked_cwd)?;
remove_dir(&test_dir)?;
drop(cwd_guard);
#
# Ok::<_, Box<dyn Error>>(())
})
.expect_err("panicked");
let mut poisoned_locked_cwd = Cwd::mutex().lock().expect_err("cwd poisoned");
let expected_cwd = poisoned_locked_cwd.get_ref().get_expected().unwrap();
# assert_eq!(expected_cwd, test_dir);
create_dir_all(&expected_cwd)?;
poisoned_locked_cwd.get_mut().set(&expected_cwd)?;
Cwd::mutex().clear_poison();
let locked_cwd = poisoned_locked_cwd.into_inner();
# drop(locked_cwd);
#
# Ok(())
# }