#![allow(dead_code)]
use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::{Mutex, MutexGuard, OnceLock};
use tempfile::TempDir;
pub fn env_lock() -> &'static Mutex<()> {
static LOCK: OnceLock<Mutex<()>> = OnceLock::new();
LOCK.get_or_init(|| Mutex::new(()))
}
pub struct IsolatedGlobalEnv {
_lock: MutexGuard<'static, ()>,
saved: Vec<(&'static str, Option<OsString>)>,
_home: TempDir,
home_canon: PathBuf,
}
impl IsolatedGlobalEnv {
pub fn new() -> Self {
let lock = env_lock().lock().unwrap();
let home = tempfile::tempdir().unwrap();
let home_canon = fs::canonicalize(home.path()).unwrap();
let appdata = home_canon.join("AppData").join("Roaming");
let localappdata = home_canon.join("AppData").join("Local");
let xdg_config = home_canon.join(".config");
fs::create_dir_all(&appdata).unwrap();
fs::create_dir_all(&localappdata).unwrap();
fs::create_dir_all(&xdg_config).unwrap();
let vars = [
"HOME",
"USERPROFILE",
"APPDATA",
"LOCALAPPDATA",
"XDG_CONFIG_HOME",
"CODEX_HOME",
];
let saved = vars
.into_iter()
.map(|key| (key, env::var_os(key)))
.collect();
env::set_var("HOME", &home_canon);
env::set_var("USERPROFILE", &home_canon);
env::set_var("APPDATA", &appdata);
env::set_var("LOCALAPPDATA", &localappdata);
env::set_var("XDG_CONFIG_HOME", &xdg_config);
env::set_var("CODEX_HOME", home_canon.join(".codex"));
Self {
_lock: lock,
saved,
_home: home,
home_canon,
}
}
pub fn home_path(&self) -> &Path {
&self.home_canon
}
pub fn appdata_path(&self) -> PathBuf {
self.home_canon.join("AppData").join("Roaming")
}
pub fn xdg_config_path(&self) -> PathBuf {
self.home_canon.join(".config")
}
}
impl Drop for IsolatedGlobalEnv {
fn drop(&mut self) {
for (key, value) in &self.saved {
match value {
Some(value) => env::set_var(key, value),
None => env::remove_var(key),
}
}
}
}