use cyberbrain_core::{Error, Result};
use std::path::{Path, PathBuf};
pub const ENV: &str = "CYBERBRAIN_IDENTITY";
pub fn path() -> Option<PathBuf> {
let base = if cfg!(windows) {
std::env::var_os("APPDATA").map(PathBuf::from)
} else {
std::env::var_os("XDG_CONFIG_HOME")
.map(PathBuf::from)
.or_else(|| std::env::var_os("HOME").map(|h| PathBuf::from(h).join(".config")))
}?;
Some(base.join("cyberbrain").join("identity"))
}
pub fn who(store: &Path) -> Result<String> {
if let Some(name) = from_env() {
return Ok(name);
}
if let Some(name) = from_file() {
return Ok(name);
}
if let Some(name) = from_git(store) {
return Ok(name);
}
Err(Error::Config(format!(
"this machine has no identity, and a proposal has to say who made it.\n\
Set one of:\n \
{ENV}=<you>\n \
{}\n \
git config user.email",
path()
.map(|p| format!("a line in {}", cyberbrain_core::Slash(&p)))
.unwrap_or_else(|| "a configuration directory this platform did not name".into())
)))
}
fn clean(raw: &str) -> Option<String> {
let name = raw.lines().next().unwrap_or_default().trim();
(!name.is_empty()).then(|| name.to_string())
}
fn from_env() -> Option<String> {
clean(&std::env::var(ENV).ok()?)
}
fn from_file() -> Option<String> {
clean(&std::fs::read_to_string(path()?).ok()?)
}
fn from_git(store: &Path) -> Option<String> {
let dir = store.parent().unwrap_or(store);
let out = std::process::Command::new("git")
.current_dir(dir)
.args(["config", "--get", "user.email"])
.output()
.ok()?;
if !out.status.success() {
return None;
}
clean(&String::from_utf8_lossy(&out.stdout))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_name_is_one_trimmed_line() {
assert_eq!(clean(" someone \n"), Some("someone".to_string()));
assert_eq!(clean("someone\nnote.write x"), Some("someone".to_string()));
assert_eq!(clean(" "), None);
assert_eq!(clean(""), None);
}
#[test]
fn the_environment_wins_over_everything() {
unsafe { std::env::set_var(ENV, "from-env") };
let got = who(Path::new("/nonexistent/.cyberbrain")).unwrap();
unsafe { std::env::remove_var(ENV) };
assert_eq!(got, "from-env");
}
}