quake 0.5.0

Simple knowledge management tool for geek.
use std::error::Error;
use std::fs;
use std::path::{Path, PathBuf};

use tracing::info;
use walkdir::WalkDir;

use quake_core::entry::entry_file::EntryFile;
use quake_core::entry::EntryDefine;
use quake_core::errors::QuakeError;
use quake_core::meta::MetaProperty;
use quake_processor::process_engine::ProcessEngine;

pub fn process_by_path(
    define: &EntryDefine,
    is_force: bool,
    entry_path: &Path,
) -> Result<(), Box<dyn Error>> {
    let file_prop = lookup_file_prop_from_define(define);
    if file_prop.is_empty() {
        return Err(Box::new(QuakeError("cannot find entry".to_string())));
    }

    let walk_paths = WalkDir::new(&entry_path)
        .max_depth(1)
        .min_depth(1)
        .into_iter()
        .filter_map(|e| e.ok());

    let one_kb = 1024;

    for path in walk_paths {
        let name = path.file_name().to_str().unwrap();
        if !EntryFile::is_match(name) {
            continue;
        }

        if is_force && path.metadata().unwrap().len() > one_kb {
            continue;
        }

        let content = fs::read_to_string(path.path())?;
        let mut entry_file = EntryFile::from(&*content, 1)?;

        if let Some(value) = entry_file.property(&file_prop) {
            let file_path = get_file_property_path(&value, entry_path);
            if file_path.exists() {
                let ext = file_path.extension().unwrap().to_str().unwrap();
                let engine = ProcessEngine::engine(ext);
                let content = engine.content(&file_path)?;
                info!("call {:?} engine from {:?}", ext, file_path);

                entry_file.content = content;
                fs::write(&path.path(), entry_file.to_string()).unwrap();
            } else {
                return Err(Box::new(QuakeError("cannot entry file".to_string())));
            }
        }
    }

    Ok(())
}

pub fn lookup_file_prop_from_define(define: &EntryDefine) -> String {
    let mut field = "".to_string();
    for (typ, property) in define.to_field_type() {
        if let MetaProperty::File(_file) = property {
            field = typ
        }
    }

    field
}

pub fn get_file_property_path(file_property: &str, entry_path: &Path) -> PathBuf {
    let absolute = PathBuf::from(file_property);
    if absolute.exists() {
        return absolute;
    }

    entry_path.join(file_property)
}

#[cfg(test)]
mod tests {
    use std::path::PathBuf;

    use crate::usecases::processor_usecases::get_file_property_path;

    #[test]
    fn return_absolute_when_file_exists() {
        let buf = get_file_property_path("README.md", &PathBuf::from("docs"));
        assert_eq!("README.md", buf.display().to_string())
    }
}