use std::path::PathBuf;
pub struct PathResolver;
impl PathResolver {
pub fn system_config_dir() -> PathBuf {
dirs::home_dir()
.map(|h| h.join(".swarm-engine"))
.expect("Could not determine home directory")
}
pub fn global_config_file() -> PathBuf {
Self::system_config_dir().join("config.toml")
}
pub fn cache_dir() -> PathBuf {
Self::system_config_dir().join("cache")
}
pub fn logs_dir() -> PathBuf {
Self::system_config_dir().join("logs")
}
pub fn state_dir() -> PathBuf {
Self::system_config_dir().join("state")
}
pub fn user_data_dir() -> PathBuf {
if let Ok(dir) = std::env::var("SWARM_ENGINE_USER_DATA_DIR") {
return PathBuf::from(dir);
}
dirs::home_dir()
.map(|h| h.join("swarm-engine"))
.expect("Could not determine home directory")
}
pub fn user_scenarios_dir() -> PathBuf {
Self::user_data_dir().join("scenarios")
}
pub fn user_eval_scenarios_dir() -> PathBuf {
Self::user_scenarios_dir().join("eval")
}
pub fn user_gym_scenarios_dir() -> PathBuf {
Self::user_scenarios_dir().join("gym")
}
pub fn reports_dir() -> PathBuf {
Self::user_data_dir().join("reports")
}
pub fn exports_dir() -> PathBuf {
Self::user_data_dir().join("exports")
}
pub fn templates_dir() -> PathBuf {
Self::user_data_dir().join("templates")
}
pub fn project_dir() -> Option<PathBuf> {
std::env::current_dir()
.ok()
.map(|d| d.join("swarm-engine"))
.filter(|p| p.exists())
}
pub fn project_config_file() -> Option<PathBuf> {
Self::project_dir().map(|d| d.join("config.toml"))
}
pub fn project_scenarios_dir() -> Option<PathBuf> {
Self::project_dir().map(|d| d.join("scenarios"))
}
pub fn project_eval_scenarios_dir() -> Option<PathBuf> {
Self::project_dir().map(|d| d.join("scenarios").join("eval"))
}
pub fn project_gym_scenarios_dir() -> Option<PathBuf> {
Self::project_dir().map(|d| d.join("scenarios").join("gym"))
}
pub fn project_reports_dir() -> Option<PathBuf> {
Self::project_dir().map(|d| d.join("reports"))
}
pub fn ensure_dirs() -> std::io::Result<()> {
let dirs = [
Self::system_config_dir(),
Self::cache_dir(),
Self::logs_dir(),
Self::state_dir(),
Self::user_data_dir(),
Self::user_eval_scenarios_dir(),
Self::user_gym_scenarios_dir(),
Self::reports_dir(),
];
for dir in dirs {
if !dir.exists() {
std::fs::create_dir_all(&dir)?;
tracing::info!("Created directory: {}", dir.display());
}
}
Ok(())
}
pub fn eval_scenario_search_paths() -> Vec<PathBuf> {
let mut paths = vec![Self::user_eval_scenarios_dir()];
if let Some(project_dir) = Self::project_eval_scenarios_dir() {
if project_dir.exists() {
paths.push(project_dir);
}
}
paths
}
pub fn gym_scenario_search_paths() -> Vec<PathBuf> {
let mut paths = vec![Self::user_gym_scenarios_dir()];
if let Some(project_dir) = Self::project_gym_scenarios_dir() {
if project_dir.exists() {
paths.push(project_dir);
}
}
paths
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_system_config_dir() {
let dir = PathResolver::system_config_dir();
assert!(dir.ends_with(".swarm-engine"));
}
#[test]
fn test_user_data_dir() {
std::env::remove_var("SWARM_ENGINE_USER_DATA_DIR");
let dir = PathResolver::user_data_dir();
assert!(dir.ends_with("swarm-engine"));
assert!(!dir.to_string_lossy().contains("/.swarm-engine"));
let test_dir = "/tmp/test-swarm-engine";
std::env::set_var("SWARM_ENGINE_USER_DATA_DIR", test_dir);
let dir = PathResolver::user_data_dir();
assert_eq!(dir, PathBuf::from(test_dir));
std::env::remove_var("SWARM_ENGINE_USER_DATA_DIR");
}
#[test]
fn test_eval_scenario_search_paths() {
let paths = PathResolver::eval_scenario_search_paths();
assert!(!paths.is_empty());
assert!(paths[0].ends_with("scenarios/eval"));
}
}