use std::path::{Path, PathBuf};
pub fn home_override() -> Option<PathBuf> {
read_storage_home_from_xdg()
}
fn read_storage_home_from_xdg() -> Option<PathBuf> {
let config_toml = directories::ProjectDirs::from("", "", "atomwrite")
.map(|p| p.config_dir().join("config.toml"))?;
let text = std::fs::read_to_string(config_toml).ok()?;
let value: toml::Value = text.parse().ok()?;
let home = value
.get("storage")
.and_then(|s| s.get("home"))
.and_then(|h| h.as_str())
.filter(|s| !s.is_empty())?;
Some(PathBuf::from(home))
}
pub fn home_override_from(raw: Option<std::ffi::OsString>) -> Option<PathBuf> {
raw.filter(|v| !v.is_empty()).map(PathBuf::from)
}
pub fn config_dir() -> Option<PathBuf> {
config_dir_from(home_override())
}
pub fn config_dir_from(home: Option<PathBuf>) -> Option<PathBuf> {
if let Some(home) = home {
return Some(home.join("config"));
}
directories::ProjectDirs::from("", "", "atomwrite").map(|p| p.config_dir().to_path_buf())
}
pub fn data_dir() -> Option<PathBuf> {
data_dir_from(home_override())
}
pub fn data_dir_from(home: Option<PathBuf>) -> Option<PathBuf> {
if let Some(home) = home {
return Some(home.join("data"));
}
directories::ProjectDirs::from("", "", "atomwrite").map(|p| p.data_dir().to_path_buf())
}
pub fn cache_dir() -> Option<PathBuf> {
cache_dir_from(home_override())
}
pub fn cache_dir_from(home: Option<PathBuf>) -> Option<PathBuf> {
if let Some(home) = home {
return Some(home.join("cache"));
}
directories::ProjectDirs::from("", "", "atomwrite").map(|p| p.cache_dir().to_path_buf())
}
pub fn state_dir() -> Option<PathBuf> {
state_dir_from(home_override())
}
pub fn state_dir_from(home: Option<PathBuf>) -> Option<PathBuf> {
if let Some(home) = home {
return Some(home.join("state"));
}
directories::ProjectDirs::from("", "", "atomwrite").map(|p| {
p.state_dir()
.map(|s| s.to_path_buf())
.unwrap_or_else(|| p.data_dir().to_path_buf())
})
}
pub fn global_config_path() -> Option<PathBuf> {
config_dir().map(|d| d.join("config.toml"))
}
pub fn ensure_dir(path: &Path) -> std::io::Result<()> {
std::fs::create_dir_all(path)?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let _ = std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o700));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::ffi::OsString;
#[test]
fn empty_home_override_ignored() {
assert!(home_override_from(None).is_none());
assert!(home_override_from(Some(OsString::from(""))).is_none());
}
#[test]
fn home_override_redirects_all_dirs() {
let base = PathBuf::from("/tmp/aw-home-test");
let home = Some(base.clone());
assert_eq!(
config_dir_from(home.clone()).as_deref(),
Some(base.join("config").as_path())
);
assert_eq!(
data_dir_from(home.clone()).as_deref(),
Some(base.join("data").as_path())
);
assert_eq!(
cache_dir_from(home.clone()).as_deref(),
Some(base.join("cache").as_path())
);
assert_eq!(
state_dir_from(home).as_deref(),
Some(base.join("state").as_path())
);
}
#[test]
fn project_dirs_fallback_does_not_panic() {
let _ = config_dir_from(None);
let _ = data_dir_from(None);
let _ = cache_dir_from(None);
let _ = state_dir_from(None);
}
}