#![allow(unused_variables, dead_code)]
use crate::{Error, Result};
use std::path::PathBuf;
pub(crate) struct Triple {
pub var: Option<&'static str>,
pub rel: Option<&'static str>,
pub abs: Option<&'static str>,
}
impl Triple {
pub(crate) fn resolve(&self) -> Option<PathBuf> {
if let Some(v) = self.var
&& let Some(p) = resolve_env(v)
{
Some(p)
} else if let Some(rel) = self.rel
&& let Ok(home) = home()
{
Some(home.join(rel))
} else {
self.abs.map(PathBuf::from)
}
}
}
pub(crate) fn resolve_env(var: &str) -> Option<PathBuf> {
std::env::var_os(var)
.filter(|v: &std::ffi::OsString| !v.is_empty() && std::path::Path::new(v).is_absolute())
.map(PathBuf::from)
}
pub(crate) fn home() -> Result<PathBuf> {
resolve_env("HOME")
.or_else(|| resolve_env("USERPROFILE"))
.ok_or(Error::NoHome)
}
pub(crate) struct Dir {
pub(crate) xdg: Triple,
pub(crate) mac: Triple,
pub(crate) win: Triple,
}
impl Dir {
pub(crate) fn resolve(&self) -> Option<PathBuf> {
#[cfg(any(feature = "xdg", target_os = "linux"))]
{
self.xdg.resolve()
}
#[cfg(all(not(feature = "xdg"), target_os = "macos"))]
{
self.mac.resolve()
}
#[cfg(all(not(feature = "xdg"), target_os = "windows"))]
{
self.win.resolve()
}
#[cfg(all(
not(feature = "xdg"),
not(target_os = "linux"),
not(target_os = "macos"),
not(target_os = "windows")
))]
{
self.xdg.resolve()
}
}
pub(crate) const fn new() -> Self {
Self {
xdg: Triple {
var: None,
rel: None,
abs: None,
},
mac: Triple {
var: None,
rel: None,
abs: None,
},
win: Triple {
var: None,
rel: None,
abs: None,
},
}
}
pub(crate) const fn xdg_var(mut self, var: &'static str) -> Self {
self.xdg.var = Some(var);
self
}
pub(crate) const fn xdg_rel(mut self, rel: &'static str) -> Self {
self.xdg.rel = Some(rel);
self
}
pub(crate) const fn xdg_abs(mut self, abs: &'static str) -> Self {
self.xdg.abs = Some(abs);
self
}
pub(crate) const fn mac_var(mut self, var: &'static str) -> Self {
self.mac.var = Some(var);
self
}
pub(crate) const fn mac_rel(mut self, rel: &'static str) -> Self {
self.mac.rel = Some(rel);
self
}
pub(crate) const fn mac_abs(mut self, abs: &'static str) -> Self {
self.mac.abs = Some(abs);
self
}
pub(crate) const fn win_var(mut self, var: &'static str) -> Self {
self.win.var = Some(var);
self
}
pub(crate) const fn win_rel(mut self, rel: &'static str) -> Self {
self.win.rel = Some(rel);
self
}
pub(crate) const fn win_abs(mut self, abs: &'static str) -> Self {
self.win.abs = Some(abs);
self
}
}
pub fn app_path(qualifier: &str, org: &str, app: &str) -> PathBuf {
#[cfg(any(feature = "xdg", target_os = "linux"))]
{
PathBuf::from(app)
}
#[cfg(all(not(feature = "xdg"), target_os = "macos"))]
{
PathBuf::from(format!("{qualifier}.{org}.{app}"))
}
#[cfg(all(not(feature = "xdg"), target_os = "windows"))]
{
PathBuf::from(org).join(app)
}
#[cfg(all(
not(feature = "xdg"),
not(target_os = "linux"),
not(target_os = "macos"),
not(target_os = "windows"),
))]
{
PathBuf::from(app)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn env_resolution() {
let prev_home = std::env::var_os("HOME");
let prev_userprofile = std::env::var_os("USERPROFILE");
let prev_test_var = std::env::var_os("FOLD_TEST_VAR");
unsafe { std::env::remove_var("FOLD_TEST_VAR") };
assert_eq!(resolve_env("FOLD_TEST_VAR"), None);
unsafe { std::env::set_var("FOLD_TEST_VAR", "") };
assert_eq!(resolve_env("FOLD_TEST_VAR"), None);
unsafe { std::env::set_var("FOLD_TEST_VAR", "relative/x") };
assert_eq!(resolve_env("FOLD_TEST_VAR"), None);
unsafe { std::env::set_var("FOLD_TEST_VAR", "/abs/x") };
assert_eq!(resolve_env("FOLD_TEST_VAR"), Some(PathBuf::from("/abs/x")));
unsafe { std::env::set_var("FOLD_TEST_VAR", "/x") };
let t = Triple {
var: Some("FOLD_TEST_VAR"),
rel: Some(".cfg"),
abs: None,
};
assert_eq!(t.resolve(), Some(PathBuf::from("/x")));
unsafe { std::env::remove_var("FOLD_TEST_VAR") };
unsafe { std::env::set_var("HOME", "/home/u") };
let t = Triple {
var: Some("FOLD_TEST_VAR"),
rel: Some(".cfg"),
abs: None,
};
assert_eq!(t.resolve(), Some(PathBuf::from("/home/u/.cfg")));
unsafe { std::env::remove_var("HOME") };
unsafe { std::env::remove_var("USERPROFILE") };
let t = Triple {
var: None,
rel: Some(".cfg"),
abs: Some("/etc/x"),
};
assert_eq!(t.resolve(), Some(PathBuf::from("/etc/x")));
let t = Triple {
var: None,
rel: None,
abs: None,
};
assert_eq!(t.resolve(), None);
match prev_home {
Some(v) => unsafe { std::env::set_var("HOME", v) },
None => unsafe { std::env::remove_var("HOME") },
}
match prev_userprofile {
Some(v) => unsafe { std::env::set_var("USERPROFILE", v) },
None => unsafe { std::env::remove_var("USERPROFILE") },
}
match prev_test_var {
Some(v) => unsafe { std::env::set_var("FOLD_TEST_VAR", v) },
None => unsafe { std::env::remove_var("FOLD_TEST_VAR") },
}
}
}