use std::ffi::{OsStr, OsString};
use std::path::PathBuf;
use std::sync::{Mutex, MutexGuard};
static CWD_MUTEX: Mutex<()> = Mutex::new(());
static ENV_MUTEX: Mutex<()> = Mutex::new(());
pub fn lock_cwd() -> CwdGuard {
let lock = CWD_MUTEX.lock().unwrap_or_else(|e| e.into_inner());
let original = std::env::current_dir().expect("failed to get current dir");
CwdGuard {
_lock: lock,
original,
}
}
pub struct CwdGuard {
_lock: MutexGuard<'static, ()>,
original: PathBuf,
}
impl Drop for CwdGuard {
fn drop(&mut self) {
if let Err(err) = std::env::set_current_dir(&self.original) {
if std::thread::panicking() {
eprintln!(
"CwdGuard: failed to restore original working directory {:?}: {}",
self.original, err
);
} else {
panic!(
"CwdGuard: failed to restore original working directory {:?}: {}",
self.original, err
);
}
}
}
}
pub fn lock_env_var(name: &'static str, value: impl AsRef<OsStr>) -> EnvVarGuard {
let lock = ENV_MUTEX.lock().unwrap_or_else(|e| e.into_inner());
let original = std::env::var_os(name);
unsafe { std::env::set_var(name, value) };
EnvVarGuard {
_lock: lock,
name,
original,
}
}
pub struct EnvVarGuard {
_lock: MutexGuard<'static, ()>,
name: &'static str,
original: Option<OsString>,
}
impl Drop for EnvVarGuard {
fn drop(&mut self) {
unsafe {
if let Some(value) = &self.original {
std::env::set_var(self.name, value);
} else {
std::env::remove_var(self.name);
}
}
}
}