use std::{
env,
path::{
Path,
PathBuf,
},
};
use directories_next::ProjectDirs;
use crate::data::cache::{
BUNSEN_CACHE_DIR,
BUNSEN_DATA_DIR,
};
pub const BUNSEN_CACHE_CONFIG: PathResolver = PathResolver {
qualifier: "io.crates.bunsen",
organization: "",
application: "bunsen",
cache_env_vars: &[BUNSEN_CACHE_DIR],
data_env_vars: &[BUNSEN_DATA_DIR],
};
pub struct PathResolver {
pub qualifier: &'static str,
pub organization: &'static str,
pub application: &'static str,
pub cache_env_vars: &'static [&'static str],
pub data_env_vars: &'static [&'static str],
}
impl PathResolver {
pub fn project_dirs(&self) -> Option<ProjectDirs> {
ProjectDirs::from(self.organization, self.application, self.qualifier)
}
pub fn resolve_cache_dir<P: AsRef<Path>>(
&self,
path: Option<P>,
) -> Option<PathBuf> {
if let Some(path) = path.as_ref() {
return Some(path.as_ref().to_path_buf());
}
for env_var in self.cache_env_vars {
if let Ok(path) = env::var(env_var) {
return Some(PathBuf::from(path));
}
}
if let Some(pds) = self.project_dirs() {
return Some(pds.cache_dir().to_path_buf());
}
None
}
pub fn resolve_data_dir<P: AsRef<Path>>(
&self,
path: Option<P>,
) -> Option<PathBuf> {
if let Some(path) = path.as_ref() {
return Some(path.as_ref().to_path_buf());
}
for env_var in self.data_env_vars {
if let Ok(path) = env::var(env_var) {
return Some(PathBuf::from(path));
}
}
if let Some(pds) = self.project_dirs() {
return Some(pds.data_dir().to_path_buf());
}
None
}
}
#[cfg(test)]
mod tests {
use serial_test::serial;
use super::*;
const CACHE_ENV1: &str = "_APP_PATH_CACHE_ENV1";
const CACHE_ENV2: &str = "_APP_PATH_CACHE_ENV2";
const DATA_ENV1: &str = "_APP_PATH_DATA_ENV1";
const DATA_ENV2: &str = "_APP_PATH_DATA_ENV2";
const TEST_CONFIG: PathResolver = PathResolver {
qualifier: "io",
organization: "crates",
application: "example",
cache_env_vars: &[CACHE_ENV1, CACHE_ENV2],
data_env_vars: &[DATA_ENV1, DATA_ENV2],
};
#[test]
#[serial]
fn test_resolve_dirs() {
let pds = TEST_CONFIG
.project_dirs()
.expect("failed to get project dirs");
let no_path: Option<PathBuf> = None;
let user_cache_dir = PathBuf::from("/tmp/app_cache/cache");
let user_data_dir = PathBuf::from("/tmp/app_cache/data");
let env_cache_dir1 = PathBuf::from("/tmp/app_cache/env_cache.1");
let env_cache_dir2 = PathBuf::from("/tmp/app_cache/env_cache.2");
let env_data_dir1 = PathBuf::from("/tmp/app_cache/env_data.1");
let env_data_dir2 = PathBuf::from("/tmp/app_cache/env_data.2");
unsafe {
for v in TEST_CONFIG.cache_env_vars {
env::remove_var(v);
}
for v in TEST_CONFIG.data_env_vars {
env::remove_var(v);
}
}
assert_eq!(
TEST_CONFIG.resolve_cache_dir(Some(user_cache_dir.clone())),
Some(user_cache_dir.clone()),
);
assert_eq!(
TEST_CONFIG.resolve_data_dir(Some(user_data_dir.clone())),
Some(user_data_dir.clone()),
);
assert_eq!(
TEST_CONFIG.resolve_cache_dir(no_path.clone()),
Some(pds.cache_dir().to_path_buf())
);
assert_eq!(
TEST_CONFIG.resolve_data_dir(no_path.clone()),
Some(pds.data_dir().to_path_buf())
);
unsafe {
env::set_var(CACHE_ENV2, env_cache_dir2.to_str().unwrap());
env::set_var(DATA_ENV2, env_data_dir2.to_str().unwrap());
}
assert_eq!(
TEST_CONFIG.resolve_cache_dir(Some(user_cache_dir.clone())),
Some(user_cache_dir.clone()),
);
assert_eq!(
TEST_CONFIG.resolve_data_dir(Some(user_data_dir.clone())),
Some(user_data_dir.clone()),
);
assert_eq!(
TEST_CONFIG.resolve_cache_dir(no_path.clone()),
Some(env_cache_dir2.clone())
);
assert_eq!(
TEST_CONFIG.resolve_data_dir(no_path.clone()),
Some(env_data_dir2.clone())
);
unsafe {
env::set_var(CACHE_ENV1, env_cache_dir1.to_str().unwrap());
env::set_var(DATA_ENV1, env_data_dir1.to_str().unwrap());
}
assert_eq!(
TEST_CONFIG.resolve_cache_dir(Some(user_cache_dir.clone())),
Some(user_cache_dir.clone()),
);
assert_eq!(
TEST_CONFIG.resolve_data_dir(Some(user_data_dir.clone())),
Some(user_data_dir.clone()),
);
assert_eq!(
TEST_CONFIG.resolve_cache_dir(no_path.clone()),
Some(env_cache_dir1.clone())
);
assert_eq!(
TEST_CONFIG.resolve_data_dir(no_path.clone()),
Some(env_data_dir1.clone())
);
}
}