use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Mutex, MutexGuard};
static NEXT_TEMP_ID: AtomicUsize = AtomicUsize::new(0);
static ENV_LOCK: Mutex<()> = Mutex::new(());
pub(crate) struct TempDir {
path: PathBuf,
}
impl TempDir {
pub(crate) fn new(label: &str) -> Self {
let id = NEXT_TEMP_ID.fetch_add(1, Ordering::Relaxed);
let path = env::temp_dir().join(format!("sipp-sys-{label}-{}-{id}", std::process::id()));
if path.exists() {
fs::remove_dir_all(&path).expect("remove stale temp dir");
}
fs::create_dir_all(&path).expect("create temp dir");
Self { path }
}
pub(crate) fn path(&self) -> &Path {
&self.path
}
pub(crate) fn join(&self, path: impl AsRef<Path>) -> PathBuf {
self.path.join(path)
}
}
impl Drop for TempDir {
fn drop(&mut self) {
let _ = fs::remove_dir_all(&self.path);
}
}
pub(crate) struct EnvGuard {
saved: Vec<(String, Option<OsString>)>,
_lock: MutexGuard<'static, ()>,
}
impl EnvGuard {
pub(crate) fn new(vars: &[(&str, Option<&str>)]) -> Self {
let lock = ENV_LOCK
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner());
let saved = vars
.iter()
.map(|(name, _)| ((*name).to_owned(), env::var_os(name)))
.collect();
for (name, value) in vars {
if let Some(value) = value {
env::set_var(name, value);
} else {
env::remove_var(name);
}
}
Self { saved, _lock: lock }
}
}
impl Drop for EnvGuard {
fn drop(&mut self) {
for (name, value) in &self.saved {
if let Some(value) = value {
env::set_var(name, value);
} else {
env::remove_var(name);
}
}
}
}