use std::path::PathBuf;
use anyhow::{Context, Result};
pub const DEFAULT_BUILD_DIR: &str = "{cargo-cache-home}/epicenter/build";
pub fn home() -> Result<PathBuf> {
if let Some(home) = std::env::var_os("HOME") {
if !home.is_empty() {
return Ok(PathBuf::from(home));
}
}
std::env::home_dir()
.filter(|p| !p.as_os_str().is_empty())
.with_context(|| "could not determine the user home directory")
}
pub fn cargo_home() -> Result<PathBuf> {
if let Some(dir) = std::env::var_os("CARGO_HOME") {
if !dir.is_empty() {
return Ok(PathBuf::from(dir));
}
}
Ok(home()?.join(".cargo"))
}
pub fn epicenter_dir() -> Result<PathBuf> {
Ok(home()?.join(".epicenter"))
}
pub fn default_cache_root() -> Result<PathBuf> {
Ok(PathBuf::from(DEFAULT_BUILD_DIR))
}
pub fn resolve_template(value: &str) -> Result<PathBuf> {
for token in brace_tokens(value) {
if token != "cargo-cache-home" {
anyhow::bail!(
"unsupported template variable {{{token}}} in {value:?}: \
epicenter can only resolve {{cargo-cache-home}}"
);
}
}
let expanded = value.replace("{cargo-cache-home}", &cargo_home()?.to_string_lossy());
Ok(PathBuf::from(
expanded.replace('\\', &std::path::MAIN_SEPARATOR.to_string()),
))
}
fn brace_tokens(value: &str) -> Vec<String> {
let mut tokens = Vec::new();
let mut rest = value;
while let Some(start) = rest.find('{') {
match rest[start..].find('}') {
Some(end) => {
tokens.push(rest[start + 1..start + end].to_string());
rest = &rest[start + end + 1..];
}
None => break,
}
}
tokens
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn expands_the_default_template() {
assert_eq!(
resolve_template(DEFAULT_BUILD_DIR).unwrap(),
cargo_home().unwrap().join("epicenter").join("build")
);
}
#[test]
fn plain_paths_pass_through_untouched() {
assert_eq!(
resolve_template("/tmp/cache").unwrap(),
PathBuf::from("/tmp/cache")
);
}
#[test]
fn backslash_template_mirrors_cargo_normalization() {
assert_eq!(
resolve_template(r"{cargo-cache-home}\epicenter\build").unwrap(),
cargo_home().unwrap().join("epicenter").join("build")
);
}
#[test]
fn unknown_template_tokens_are_rejected() {
assert!(resolve_template("{workspace-root}/build").is_err());
}
}