use std::ffi::OsString;
use std::path::{Path, PathBuf};
use thiserror::Error;
const APP_DIR: &str = "openlogi";
#[derive(Debug, Error)]
pub enum PathsError {
#[error("could not resolve a home directory for the current user")]
HomeNotFound,
}
fn home() -> Result<PathBuf, PathsError> {
std::env::var_os("HOME")
.or_else(|| std::env::var_os("USERPROFILE"))
.filter(|h| !h.is_empty())
.map(PathBuf::from)
.ok_or(PathsError::HomeNotFound)
}
fn xdg_base(env_value: Option<OsString>, fallback: &[&str]) -> Result<PathBuf, PathsError> {
match env_value {
Some(v) if Path::new(&v).is_absolute() => Ok(PathBuf::from(v).join(APP_DIR)),
_ => {
let mut dir = home()?;
dir.extend(fallback);
dir.push(APP_DIR);
Ok(dir)
}
}
}
pub fn config_dir() -> Result<PathBuf, PathsError> {
xdg_base(std::env::var_os("XDG_CONFIG_HOME"), &[".config"])
}
pub fn config_path() -> Result<PathBuf, PathsError> {
Ok(config_dir()?.join("config.toml"))
}
pub fn data_dir() -> Result<PathBuf, PathsError> {
xdg_base(std::env::var_os("XDG_DATA_HOME"), &[".local", "share"])
}
#[cfg(all(test, unix))]
#[allow(clippy::expect_used, reason = "expect/unwrap are idiomatic in tests")]
mod tests {
use super::*;
#[test]
fn absolute_xdg_override_is_used_verbatim() {
let dir = xdg_base(Some("/tmp/xdg-config".into()), &[".config"])
.expect("absolute override needs no home dir");
assert_eq!(dir, PathBuf::from("/tmp/xdg-config/openlogi"));
}
#[test]
fn relative_xdg_value_is_ignored_per_spec() {
let dir = xdg_base(Some("relative/dir".into()), &[".config"]).expect("home dir resolves");
assert!(dir.ends_with("openlogi"));
assert!(!dir.to_string_lossy().contains("relative"));
}
}