use std::ffi::OsString;
use std::path::{Path, PathBuf};
use anyhow::{bail, Context, Result};
pub const DEFAULT_LOCAL_ID: &str = "default";
pub fn of(local_id: &str) -> Result<PathBuf> {
if local_id.is_empty() || local_id == "." || local_id == ".." || local_id.contains(['/', '\\'])
{
bail!("a device's local id is one path component, not {local_id:?}");
}
Ok(dirs::data_local_dir()
.context(
"this platform has no per-user data directory: set DEVICE_DIR, or name the \
device directory explicitly",
)?
.join("semio")
.join("arora")
.join("devices")
.join(local_id))
}
pub fn from_env() -> Result<PathBuf> {
if let Some(dir) = override_from_env() {
return Ok(dir);
}
if let Some(file) = env_nonempty("IDENTITY_FILE") {
let dir = of_identity_file(Path::new(&file));
log::warn!(
"IDENTITY_FILE is deprecated: DEVICE_DIR names the device directory. This run's \
is {}, the directory the identity {} migrates to",
dir.display(),
file
);
return Ok(dir);
}
of(&local_id_from_env())
}
pub(crate) fn override_from_env() -> Option<PathBuf> {
env_nonempty("DEVICE_DIR").map(PathBuf::from)
}
pub(crate) fn of_identity_file(file: &Path) -> PathBuf {
with_suffix(file, "_dir")
}
pub(crate) fn with_suffix(path: &Path, suffix: &str) -> PathBuf {
let mut name = OsString::from(path.as_os_str());
name.push(suffix);
PathBuf::from(name)
}
pub(crate) fn local_id_from_env() -> String {
env_nonempty("DEVICE_LOCAL_ID").unwrap_or_else(|| DEFAULT_LOCAL_ID.to_string())
}
fn env_nonempty(key: &str) -> Option<String> {
std::env::var(key)
.ok()
.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_local_id_names_one_directory_under_devices() {
let dir = of("bench-2").unwrap();
assert!(
dir.ends_with("semio/arora/devices/bench-2"),
"{}",
dir.display()
);
}
#[test]
fn a_local_id_is_one_path_component() {
for bad in ["", ".", "..", "a/b", "a\\b"] {
assert!(of(bad).is_err(), "{bad:?} is refused");
}
}
#[test]
fn an_identity_file_s_device_directory_is_beside_it() {
assert_eq!(
of_identity_file(Path::new("/etc/arora/identity")),
PathBuf::from("/etc/arora/identity_dir")
);
}
}