use std::ffi::{OsStr, OsString};
use std::path::PathBuf;
use std::sync::{Mutex, MutexGuard, OnceLock};
static ENV_LOCK: OnceLock<Mutex<()>> = OnceLock::new();
pub fn env_lock() -> MutexGuard<'static, ()> {
ENV_LOCK
.get_or_init(|| Mutex::new(()))
.lock()
.expect("env lock poisoned")
}
pub struct EnvVarGuard {
key: &'static str,
previous: Option<OsString>,
}
impl EnvVarGuard {
pub fn set(key: &'static str, value: impl AsRef<OsStr>) -> Self {
let previous = std::env::var_os(key);
std::env::set_var(key, value);
Self { key, previous }
}
pub fn unset(key: &'static str) -> Self {
let previous = std::env::var_os(key);
std::env::remove_var(key);
Self { key, previous }
}
pub fn prepend_path(path: PathBuf) -> Self {
let previous = std::env::var_os("PATH");
let mut paths = vec![path];
if let Some(old_path) = &previous {
paths.extend(std::env::split_paths(old_path));
}
std::env::set_var("PATH", std::env::join_paths(paths).unwrap());
Self {
key: "PATH",
previous,
}
}
}
impl Drop for EnvVarGuard {
fn drop(&mut self) {
match &self.previous {
Some(value) => std::env::set_var(self.key, value),
None => std::env::remove_var(self.key),
}
}
}