use crate::run::path_consts::{
CUSTOM_AGENT_DIR, CUSTOM_LUA_DIR, DEFAULT_AGENT_DIR, DEVAI_BASE, DEVAI_CONFIG_FILE_PATH, DEVAI_DIR_NAME,
DEVAI_DIR_PATH, DEVAI_NEW_COMMAND_DIRS, DEVAI_NEW_CUSTOM_COMMAND_DIR, DEVAI_NEW_DEFAULT_COMMAND_DIR,
};
use crate::Result;
use home::home_dir;
use simple_fs::SPath;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone)]
pub struct DevaiDir {
devai_dir: SPath,
devai_dir_full_path: SPath,
workspace_dir: SPath,
}
impl DevaiDir {
pub fn from_parent_dir(parent_dir: impl AsRef<Path>) -> Result<Self> {
let workspace_dir = SPath::from_path(parent_dir)?;
let devai_dir = SPath::from(DEVAI_DIR_PATH);
let devai_dir_full_path = workspace_dir.join(DEVAI_DIR_NAME)?;
Ok(Self {
devai_dir,
workspace_dir,
devai_dir_full_path,
})
}
}
impl DevaiDir {
pub fn exists(&self) -> bool {
self.devai_dir_full_path().exists()
}
pub fn devai_dir(&self) -> &SPath {
&self.devai_dir
}
pub fn devai_dir_full_path(&self) -> &SPath {
&self.devai_dir_full_path
}
pub fn workspace_dir(&self) -> &SPath {
&self.workspace_dir
}
}
impl DevaiDir {
pub fn get_config_toml_path(&self) -> Result<SPath> {
let path = self.devai_dir_full_path.join(DEVAI_CONFIG_FILE_PATH)?;
Ok(path)
}
pub fn get_agent_dirs(&self) -> Result<Vec<SPath>> {
let mut dirs: Vec<SPath> = Vec::new();
dirs.push(self.get_custom_agent_dir()?);
if let Some(devai_base_custom_agent_dir) =
get_devai_base_dir().and_then(|base_dir| base_dir.join(CUSTOM_AGENT_DIR).ok())
{
if devai_base_custom_agent_dir.exists() {
dirs.push(devai_base_custom_agent_dir);
}
}
dirs.push(self.get_default_agent_dir()?);
Ok(dirs)
}
pub fn get_default_agent_dir(&self) -> Result<SPath> {
let dir = self.devai_dir_full_path.join(DEFAULT_AGENT_DIR)?;
Ok(dir)
}
pub fn get_custom_agent_dir(&self) -> Result<SPath> {
let dir = self.devai_dir_full_path.join(CUSTOM_AGENT_DIR)?;
Ok(dir)
}
pub fn get_lua_custom_dir(&self) -> Result<SPath> {
let dir = self.devai_dir_full_path.join(CUSTOM_LUA_DIR)?;
Ok(dir)
}
pub fn get_custom_new_template_dir(&self) -> Result<SPath> {
let dir = self.devai_dir_full_path.join(DEVAI_NEW_CUSTOM_COMMAND_DIR)?;
Ok(dir)
}
pub fn get_default_new_template_dir(&self) -> Result<SPath> {
let dir = self.devai_dir_full_path.join(DEVAI_NEW_DEFAULT_COMMAND_DIR)?;
Ok(dir)
}
pub fn get_new_template_command_dirs(&self) -> Result<Vec<SPath>> {
let dirs = DEVAI_NEW_COMMAND_DIRS
.iter()
.map(|&suffix_dir| self.devai_dir_full_path.join(suffix_dir).map_err(|err| err.into()))
.collect::<Result<_>>()?;
Ok(dirs)
}
}
impl AsRef<Path> for DevaiDir {
fn as_ref(&self) -> &Path {
self.devai_dir_full_path.as_ref()
}
}
pub fn find_workspace_dir(from_dir: impl AsRef<Path>) -> Result<Option<SPath>> {
let mut tmp_dir: Option<PathBuf> = Some(from_dir.as_ref().to_path_buf());
while let Some(parent_dir) = tmp_dir {
let devai_dir = DevaiDir::from_parent_dir(&parent_dir)?;
if devai_dir.exists() {
return Ok(Some(SPath::new(parent_dir)?));
}
tmp_dir = parent_dir.parent().map(|p| p.into());
}
Ok(None)
}
pub fn get_devai_base_dir() -> Option<SPath> {
let home_dir = home_dir()?;
if !home_dir.exists() {
return None;
}
let base_dir = home_dir.join(DEVAI_BASE);
if !base_dir.exists() {
return None;
}
SPath::from_path_buf_ok(base_dir)
}
#[cfg(test)]
mod tests {
type Result<T> = core::result::Result<T, Box<dyn std::error::Error>>;
use super::*;
use crate::_test_support::SANDBOX_01_DIR;
#[test]
fn test_devai_dir_simple() -> Result<()> {
let devai_dir = DevaiDir::from_parent_dir(SANDBOX_01_DIR)?;
assert_eq!(
devai_dir.get_config_toml_path()?.to_str(),
"./tests-data/sandbox-01/.devai/config.toml"
);
assert_eq!(
devai_dir.get_custom_agent_dir()?.to_str(),
"./tests-data/sandbox-01/.devai/custom/agent"
);
Ok(())
}
}