use crate::tree::config::ProjectConfig;
use crate::tree::node::TreeNode;
use crate::utils::{check_path, generate_id};
use std::fs;
use std::io::Result;
use std::path::{Path, PathBuf};
pub struct ProjectTree {
pub id: String,
pub name: String,
pub path: String,
pub root: Option<TreeNode>,
pub config: Option<ProjectConfig>,
}
impl ProjectTree {
pub fn new<S, I>(name: S, path: I, config: Option<ProjectConfig>) -> Self
where
S: Into<String>,
I: Into<String>,
{
ProjectTree {
id: generate_id(),
name: name.into(),
path: path.into(),
root: None,
config,
}
}
pub fn is_valid(&self) -> bool {
check_path(&self.path).is_ok()
}
pub fn plant<S, I>(name: S, path: I, config: Option<ProjectConfig>) -> Self
where
S: Into<String>,
I: Into<String>,
{
let mut tree = ProjectTree::new(name, path, config);
tree.build().expect("project build panic");
tree.summarize().expect("project summarize panic");
tree
}
pub fn build(&mut self) -> Result<()> {
if !self.is_valid() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"invalid path",
));
}
let root_path = PathBuf::from(&self.path);
self.root = Some(Self::build_tree_node(&root_path)?);
Ok(())
}
fn build_tree_node(path: &Path) -> Result<TreeNode> {
let metadata = fs::metadata(path)?;
let is_dir = metadata.is_dir();
let mut node = TreeNode::new(path.to_string_lossy().into_owned(), is_dir);
if is_dir {
let mut children = Vec::new();
for entry in fs::read_dir(path)? {
let entry = entry?;
children.push(Self::build_tree_node(&entry.path())?);
}
node.children = Some(children);
}
Ok(node)
}
pub fn summarize(&mut self) -> Result<()> {
if self.root.is_none() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"root is none, please build by `build()` first",
));
}
if !self.is_valid() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"invalid root path, please check it",
));
}
self.root.as_mut().unwrap().upsert_summary();
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tree::visible::ProjectTreeVisible;
#[test]
fn test_new() {
let name = "test";
let path = ".".to_string();
let tree = ProjectTree::new(name, path, None);
assert_eq!(tree.id.len(), 36);
assert_eq!(tree.name, name.to_string());
assert_eq!(tree.path, ".".to_string());
}
#[test]
fn test_get_valid() {
let valid_tree = ProjectTree::new("test".to_string(), "./src".to_string(), None);
assert_eq!(valid_tree.is_valid(), true);
let invalid_tree = ProjectTree::new("test".to_string(), "/not_exist".to_string(), None);
assert_eq!(invalid_tree.is_valid(), false);
}
#[test]
fn test_build_project_tree() {
let name = "test";
let path = "./src";
let mut tree = ProjectTree::new(name, path, None);
tree.build().expect("panic");
assert_eq!(tree.root.is_some(), true);
assert_eq!(tree.name, "test".to_string());
assert_eq!(tree.path, "./src".to_string());
tree.print_tree();
}
#[test]
fn test_plant() {
let name = "test";
let path = "./src";
let tree = ProjectTree::plant(name, path, None);
assert_eq!(tree.root.is_some(), true);
assert_eq!(tree.name, "test".to_string());
assert_eq!(tree.path, "./src".to_string());
tree.print_tree();
println!("{}", tree.root.unwrap());
}
}