use std::path::PathBuf;
use crate::error::{Result, ShoreError};
pub(crate) const SHORE_HOME_ENV: &str = "SHORE_HOME";
pub(crate) fn shore_home_root() -> Result<PathBuf> {
resolve_shore_home_root(
std::env::var_os(SHORE_HOME_ENV).map(PathBuf::from),
std::env::var_os("XDG_DATA_HOME").map(PathBuf::from),
std::env::var_os("HOME").map(PathBuf::from),
std::env::var_os("APPDATA").map(PathBuf::from),
)
}
pub(crate) fn resolve_shore_home_root(
shore_home: Option<PathBuf>,
xdg_data_home: Option<PathBuf>,
home: Option<PathBuf>,
app_data: Option<PathBuf>,
) -> Result<PathBuf> {
if let Some(root) = shore_home {
return Ok(root);
}
if let Some(xdg) = xdg_data_home {
return Ok(xdg.join("shore"));
}
#[cfg(unix)]
if let Some(home) = home {
return Ok(home.join(".shore"));
}
#[cfg(windows)]
if let Some(app_data) = app_data {
return Ok(app_data.join("shore"));
}
let _ = (home, app_data);
Err(ShoreError::Message(
"cannot resolve a user-level shore home: set SHORE_HOME or a platform home directory"
.to_owned(),
))
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use super::*;
#[test]
fn shore_home_override_is_used_verbatim() {
let root = resolve_shore_home_root(
Some(PathBuf::from("/tmp/hermetic-store")),
Some(PathBuf::from("/xdg/data")),
Some(PathBuf::from("/home/dev")),
None,
)
.unwrap();
assert_eq!(root, PathBuf::from("/tmp/hermetic-store"));
}
#[test]
fn xdg_data_home_wins_over_home_when_no_override() {
let root = resolve_shore_home_root(
None,
Some(PathBuf::from("/xdg/data")),
Some(PathBuf::from("/home/dev")),
None,
)
.unwrap();
assert_eq!(root, PathBuf::from("/xdg/data").join("shore"));
}
#[cfg(unix)]
#[test]
fn home_dot_shore_is_the_unix_default() {
let root =
resolve_shore_home_root(None, None, Some(PathBuf::from("/home/dev")), None).unwrap();
assert_eq!(root, PathBuf::from("/home/dev").join(".shore"));
}
#[cfg(windows)]
#[test]
fn app_data_shore_is_the_windows_default() {
let root = resolve_shore_home_root(
None,
None,
None,
Some(PathBuf::from(r"C:\Users\dev\AppData\Roaming")),
)
.unwrap();
assert_eq!(
root,
PathBuf::from(r"C:\Users\dev\AppData\Roaming").join("shore")
);
}
#[test]
fn missing_home_with_no_override_is_a_typed_error() {
let result = resolve_shore_home_root(None, None, None, None);
assert!(result.is_err());
}
#[test]
fn shore_home_root_reads_the_env_override() {
let tmp = tempfile::tempdir().unwrap();
unsafe {
std::env::set_var(SHORE_HOME_ENV, tmp.path());
}
let root = shore_home_root().unwrap();
unsafe {
std::env::remove_var(SHORE_HOME_ENV);
}
assert_eq!(root, tmp.path());
}
}