use std::ffi::OsString;
use std::path::{Path, PathBuf};
fn env_home() -> PathBuf {
let variable = if cfg!(windows) { "USERPROFILE" } else { "HOME" };
std::env::var_os(variable)
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from("/"))
}
pub fn profiles_owner(path: &Path, profiles_dir: &str) -> Option<PathBuf> {
let mut owner = PathBuf::new();
for part in path.components() {
if part.as_os_str().eq_ignore_ascii_case(profiles_dir) {
return (owner.components().count() > 1).then_some(owner);
}
owner.push(part);
}
None
}
pub fn profile_aware_home(profiles_dir: &str) -> PathBuf {
let env = env_home();
#[cfg(windows)]
if let Some(dir) = profiles_owner(&env, profiles_dir) {
return dir;
}
#[cfg(unix)]
if let Some(dir) = crate::app_dirs::account_home()
.ok()
.filter(|dir| env == Path::new("/") || env.starts_with(dir.join(profiles_dir)))
{
return dir;
}
let _ = profiles_dir;
env
}
pub fn profile_aware_env_var(key: &str, profiles_dir: &str) -> Option<OsString> {
#[cfg(unix)]
if key == "HOME" {
return Some(profile_aware_home(profiles_dir).into_os_string());
}
let value = std::env::var_os(key);
#[cfg(windows)]
if let Some(account) = value
.as_ref()
.and_then(|v| profiles_owner(Path::new(v), profiles_dir))
{
match key.to_ascii_uppercase().as_str() {
"USERPROFILE" | "HOME" => return Some(account.into_os_string()),
"APPDATA" => return Some(account.join("AppData").join("Roaming").into_os_string()),
"LOCALAPPDATA" => return Some(account.join("AppData").join("Local").into_os_string()),
_ => {}
}
}
let _ = profiles_dir;
value
}