use crate::error::{StorageError, StorageResult};
use crate::types::{ResourceType, StorageMode};
use std::path::{Path, PathBuf};
pub trait StorageManager: Send + Sync {
fn global_path(&self) -> &PathBuf;
fn project_path(&self) -> Option<&PathBuf>;
fn mode(&self) -> StorageMode;
fn global_resource_path(&self, resource_type: ResourceType) -> PathBuf;
fn project_resource_path(&self, resource_type: ResourceType) -> Option<PathBuf>;
fn is_first_run(&self) -> bool;
}
pub struct PathResolver;
impl PathResolver {
pub fn resolve_global_path() -> StorageResult<PathBuf> {
if let Ok(home_override) = std::env::var("RICECODER_HOME") {
let path = PathBuf::from(home_override);
return Ok(path);
}
if let Some(docs_dir) = dirs::document_dir() {
let ricecoder_path = docs_dir.join(".ricecoder");
return Ok(ricecoder_path);
}
if let Some(home_dir) = dirs::home_dir() {
let ricecoder_path = home_dir.join(".ricecoder");
return Ok(ricecoder_path);
}
Err(StorageError::path_resolution_error(
"Could not determine home directory",
))
}
pub fn resolve_project_path() -> PathBuf {
PathBuf::from(".agent")
}
pub fn expand_home(path: &Path) -> StorageResult<PathBuf> {
let path_str = path
.to_str()
.ok_or_else(|| StorageError::path_resolution_error("Invalid path encoding"))?;
if path_str.starts_with("~") {
if let Some(home_dir) = dirs::home_dir() {
let expanded = if path_str == "~" {
home_dir
} else {
home_dir.join(&path_str[2..])
};
return Ok(expanded);
}
}
Ok(path.to_path_buf())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_resolve_global_path_with_env_override() {
std::env::set_var("RICECODER_HOME", "/tmp/ricecoder-test");
let path = PathResolver::resolve_global_path().expect("Should resolve path");
assert_eq!(path, PathBuf::from("/tmp/ricecoder-test"));
std::env::remove_var("RICECODER_HOME");
}
#[test]
fn test_resolve_global_path_without_env() {
std::env::remove_var("RICECODER_HOME");
let path = PathResolver::resolve_global_path().expect("Should resolve path");
assert!(path.to_string_lossy().contains(".ricecoder"));
}
#[test]
fn test_resolve_project_path() {
let path = PathResolver::resolve_project_path();
assert_eq!(path, PathBuf::from(".agent"));
}
#[test]
fn test_expand_home_with_tilde() {
let path = PathBuf::from("~/.ricecoder");
let expanded = PathResolver::expand_home(&path).expect("Should expand");
assert!(!expanded.to_string_lossy().contains("~"));
}
#[test]
fn test_expand_home_without_tilde() {
let path = PathBuf::from("/tmp/ricecoder");
let expanded = PathResolver::expand_home(&path).expect("Should expand");
assert_eq!(expanded, path);
}
}