use anyhow::Result;
use directories::UserDirs;
use std::path::PathBuf;
#[cfg(unix)]
fn sudo_user_home() -> Option<PathBuf> {
let sudo_user = std::env::var("SUDO_USER").ok()?;
let sudo_user = sudo_user.trim();
if sudo_user.is_empty() || sudo_user == "root" {
return None;
}
let passwd = std::fs::read_to_string("/etc/passwd").ok()?;
for line in passwd.lines() {
let mut fields = line.splitn(7, ':');
let username = fields.next()?;
if username != sudo_user {
continue;
}
let home = fields.nth(4)?; if !home.is_empty() {
return Some(PathBuf::from(home));
}
}
None
}
#[cfg(not(unix))]
fn sudo_user_home() -> Option<PathBuf> {
None
}
pub(crate) fn effective_home_dir() -> PathBuf {
if let Some(home) = sudo_user_home() {
return home;
}
if let Ok(home) = std::env::var("HOME") {
let home = home.trim().to_string();
if !home.is_empty() {
return PathBuf::from(home);
}
}
UserDirs::new().map_or_else(|| PathBuf::from("."), |u| u.home_dir().to_path_buf())
}
pub fn tilde_expand(s: &str) -> String {
let home = effective_home_dir().to_string_lossy().into_owned();
shellexpand::tilde_with_context(s, || Some(home)).into_owned()
}
pub fn full_expand(s: &str) -> Result<String, shellexpand::LookupError<std::env::VarError>> {
full_expand_with_home(s, &effective_home_dir())
}
pub fn full_expand_with_home(
s: &str,
home: &std::path::Path,
) -> Result<String, shellexpand::LookupError<std::env::VarError>> {
let home = home.to_string_lossy().into_owned();
let home2 = home.clone();
shellexpand::full_with_context(
s,
move || Some(home),
move |var| {
if var == "HOME" {
return Ok(Some(home2.clone()));
}
match std::env::var(var) {
Ok(v) => Ok(Some(v)),
Err(std::env::VarError::NotPresent) => Ok(None),
Err(e) => Err(e),
}
},
)
.map(|c| c.into_owned())
}
fn default_config_dir() -> Result<PathBuf> {
Ok(effective_home_dir().join(".shine"))
}
pub(crate) fn default_config_and_presets_dir() -> Result<(PathBuf, PathBuf)> {
let config_dir = default_config_dir()?;
Ok((config_dir.clone(), config_dir.join("presets")))
}