use crate::error::{Result, SkillcError};
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
pub fn validate_skill_path(path: &Path) -> Result<()> {
if !path.exists() {
return Err(SkillcError::SkillNotFound(
path.to_string_lossy().to_string(),
));
}
if !path.join("SKILL.md").exists() {
return Err(SkillcError::NotAValidSkill(
path.to_string_lossy().to_string(),
));
}
Ok(())
}
pub fn is_valid_skill(path: &Path) -> bool {
path.is_dir() && path.join("SKILL.md").exists()
}
pub fn copy_dir_recursive(src: &Path, dst: &Path) -> io::Result<()> {
fs::create_dir_all(dst)?;
for entry in fs::read_dir(src)? {
let entry = entry?;
let file_type = entry.file_type()?;
let src_path = entry.path();
let dst_path = dst.join(entry.file_name());
if file_type.is_dir() {
copy_dir_recursive(&src_path, &dst_path)?;
} else if file_type.is_file() {
fs::copy(&src_path, &dst_path)?;
}
}
Ok(())
}
pub fn project_logs_dir(root: &Path) -> PathBuf {
root.join(".skillc").join("logs")
}
pub fn project_skill_logs_dir(root: &Path, skill: &str) -> PathBuf {
project_logs_dir(root).join(skill)
}
pub fn project_runtime_dir(root: &Path) -> PathBuf {
root.join(".skillc").join("runtime")
}
pub fn project_skill_runtime_dir(root: &Path, skill: &str) -> PathBuf {
project_runtime_dir(root).join(skill)
}
pub fn project_skills_dir(root: &Path) -> PathBuf {
root.join(".skillc").join("skills")
}
pub fn project_skill_dir(root: &Path, skill: &str) -> PathBuf {
project_skills_dir(root).join(skill)
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::TempDir;
#[test]
fn test_copy_dir_recursive() {
let temp = TempDir::new().expect("create temp dir");
let src = temp.path().join("src");
let dst = temp.path().join("dst");
fs::create_dir_all(src.join("subdir")).expect("test operation");
fs::write(src.join("file.txt"), "content").expect("test operation");
fs::write(src.join("subdir").join("nested.txt"), "nested").expect("test operation");
copy_dir_recursive(&src, &dst).expect("copy dir");
assert!(dst.join("file.txt").exists());
assert!(dst.join("subdir").join("nested.txt").exists());
assert_eq!(
fs::read_to_string(dst.join("file.txt")).expect("read file"),
"content"
);
}
#[test]
fn test_project_path_helpers() {
let root = Path::new("/project");
assert_eq!(
project_logs_dir(root),
PathBuf::from("/project/.skillc/logs")
);
assert_eq!(
project_skill_logs_dir(root, "my-skill"),
PathBuf::from("/project/.skillc/logs/my-skill")
);
assert_eq!(
project_runtime_dir(root),
PathBuf::from("/project/.skillc/runtime")
);
assert_eq!(
project_skill_runtime_dir(root, "my-skill"),
PathBuf::from("/project/.skillc/runtime/my-skill")
);
assert_eq!(
project_skills_dir(root),
PathBuf::from("/project/.skillc/skills")
);
assert_eq!(
project_skill_dir(root, "my-skill"),
PathBuf::from("/project/.skillc/skills/my-skill")
);
}
}