use crate::constants::{CONFIG_FILE_NAME, SHELLOCK_HOMES};
use anyhow::Result;
use std::{env, path::PathBuf};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum PathError {
#[error("no matching directory stem, got: {got:?}, valid: {valid:?}")]
NoMatchingStem { got: PathBuf, valid: Vec<PathBuf> },
}
pub fn home_dir() -> PathBuf {
PathBuf::from(env::var("HOME").expect("can not read HOME environment variable"))
}
pub fn data_dir() -> PathBuf {
let xdg_dirs = xdg::BaseDirectories::with_prefix(SHELLOCK_HOMES)
.expect("unable to get XDG base directories");
xdg_dirs.get_data_home()
}
pub fn config_dir() -> PathBuf {
let xdg_dirs = xdg::BaseDirectories::with_prefix(SHELLOCK_HOMES)
.expect("unable to get XDG base directories");
xdg_dirs.get_config_home()
}
pub fn config_file_name() -> PathBuf {
config_dir().join(CONFIG_FILE_NAME)
}
pub fn strip(path: PathBuf) -> PathBuf {
if path.starts_with(data_dir()) {
return path.strip_prefix(data_dir()).unwrap().to_path_buf();
}
if path.starts_with(home_dir()) {
return path.strip_prefix(home_dir()).unwrap().to_path_buf();
}
path
}
pub fn flip_path(path: PathBuf) -> Result<PathBuf> {
let home = home_dir();
let data = data_dir();
if path.starts_with(&data) {
return Ok(home.join(path.strip_prefix(data)?));
}
if path.starts_with(&home) {
return Ok(data.join(path.strip_prefix(home)?));
}
Err(PathError::NoMatchingStem {
got: path,
valid: vec![home, data],
}
.into())
}
#[cfg(test)]
mod tests {
use super::*;
use serial_test::serial;
#[test]
#[serial]
fn test_dirs() {
let temp = tempfile::tempdir().unwrap();
env::set_var("HOME", temp.path().as_os_str().to_str().unwrap());
env::set_var("XDG_DATA_HOME", "");
let home = home_dir();
assert_eq!(home, temp.path());
let cfg = config_dir();
assert_eq!(
cfg,
temp.path()
.join(PathBuf::from(".config"))
.join(PathBuf::from(SHELLOCK_HOMES))
);
let cfg_name = config_file_name();
assert_eq!(
cfg_name,
temp.path()
.join(PathBuf::from(".config"))
.join(PathBuf::from(SHELLOCK_HOMES).join(PathBuf::from(CONFIG_FILE_NAME)))
);
let data = data_dir();
assert_eq!(
data,
temp.path()
.join(PathBuf::from(".local/share"))
.join(PathBuf::from(SHELLOCK_HOMES))
);
}
macro_rules! test_flip_path {
($name:ident, $input:expr) => {
#[test]
#[serial]
fn $name() {
let temp = tempfile::tempdir().unwrap();
env::set_var("HOME", temp.path().as_os_str().to_str().unwrap());
let source = home_dir().join(PathBuf::from($input));
let res = flip_path(source.clone());
assert!(
res.is_ok(),
"result was not ok: {:?}, source: {:?}",
res.err(),
source
);
assert_eq!(res.unwrap(), data_dir().join(PathBuf::from($input)));
let source = data_dir().join(PathBuf::from($input));
let res = flip_path(source.clone());
assert!(
res.is_ok(),
"result was not ok: {:?}, source: {:?}",
res.err(),
source
);
assert_eq!(res.unwrap(), home_dir().join(PathBuf::from($input)));
}
};
}
test_flip_path!(basic, "test/1234");
}