vake 1.0.2

Custom build tool for the In Silico project
Documentation
pub mod config;
pub mod serialize;

use log::{ debug, error };

use std::{collections::HashMap, sync::Arc};
use std::path::{Path, PathBuf};
use std::sync::{mpsc, Mutex};
use std::fs::{self, metadata};

use notify::{Event, RecursiveMode, Watcher};

use crate::parser::parse::Recipe;

#[derive(Clone)]
pub enum ActionType {
    Remove,
    Create,
    Path
}

#[derive(Clone)]
pub struct ProjectQueue {
    pub queue: HashMap<PathBuf, ActionType>
}

impl ProjectQueue {
    pub fn new() -> ProjectQueue {
        return Self { queue: HashMap::new() }
    }

    pub fn push(&mut self, path: PathBuf, action: ActionType) {
        self.queue.insert(path, action);
    }

    pub fn serialize(&mut self, recipe: Recipe) -> String {
        serialize::build(self, recipe)
    }

    pub fn all(&mut self, recipe: &Recipe) {
        let dir = &recipe.options.active_directory;
        Self::visit_files(dir, &mut |path| {
            debug!("Sending file {:?}", path);
            self.push(path, ActionType::Create);
        });
    }

    fn visit_files(path: &Path, f: &mut impl FnMut(PathBuf)) {
        if let Ok(entries) = fs::read_dir(path) {
            for entry in entries.flatten() {
                let path = entry.path();
                if path.is_file() {
                    f(path);
                } else if path.is_dir() {
                    Self::visit_files(&path, f);
                }
            }
        }
    }

    pub fn clear(&mut self) {
        self.queue.clear();
    }
}

pub fn daemon(directory: &PathBuf, queue: &Arc<Mutex<ProjectQueue>>) -> Result<(), notify::Error> {
    debug!("Starting daemon on directory '{}'", directory.as_os_str().to_str().expect("Expected a specified directory"));
    let (sender, reciever) = mpsc::channel::<Result<Event, notify::Error>>();
    let mut watcher = notify::recommended_watcher(sender)?;

    let daemon = watcher.watch(&directory, RecursiveMode::Recursive);

    for res in reciever {
        match res {
            Ok(event) => process_event(event, queue),
            Err(e) => error!("watch error: {:?}", e),
        }
    }

    return daemon;
}

fn process_event(event: Event, queue: &Arc<Mutex<ProjectQueue>>) {
    let mut queue = queue.lock().unwrap();
    for path in event.paths {
        let metadata = metadata(path.clone());
        if metadata.is_err() {
            debug!("Removed {}", path.as_os_str().to_str().expect("Expected a file name"));
            queue.push(path, ActionType::Remove);
            continue;
        }

        let handle = metadata.unwrap();
        if handle.is_dir() {
            debug!("Recieved directory event on directory {}", path.as_os_str().to_str().expect("Expected a file name"));
            queue.push(path, ActionType::Path);
        } else if handle.is_file() {
            debug!("Recieved file event on file {}", path.as_os_str().to_str().expect("Expected a file name"));
            queue.push(path, ActionType::Create);
        }
    }
}