wachit 0.2.2

Instant rebuilds for your dev workflow
Documentation
use std::{
    path::Path,
    process::Command,
    sync::{Arc, Mutex, atomic::AtomicBool, mpsc},
    time::{Duration, Instant},
};

use notify::{Event, Result, Watcher};
use wachit::{
    processor::{run_command, should_ignore_path},
    types::Config,
};

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let confg = Config::new(args);

    let (tx, rx) = mpsc::channel::<Result<Event>>();
    let last_event = Arc::new(Mutex::new(Instant::now()));
    let pending_restart = Arc::new(Mutex::new(AtomicBool::new(false)));
    let pending_restart_clone = pending_restart.clone();
    let last_event_watcher = last_event.clone();
    let config_clone = confg.clone();
    let restart_tx = tx.clone();

    let mut watcher = notify::recommended_watcher(move |event: Result<Event>| {
        let event = match event {
            Ok(ev) => ev,
            Err(_) => return,
        };

        let mut ignore_path = false;
        for path in &event.paths {
            let p = path.to_str().unwrap().to_string();
            ignore_path = should_ignore_path(&p, &config_clone);
        }
        if ignore_path {
            return;
        }

        *last_event_watcher.lock().unwrap() = Instant::now();
        pending_restart
            .lock()
            .unwrap()
            .store(true, std::sync::atomic::Ordering::SeqCst);
    })
    .unwrap();

    let _ = watcher.watch(Path::new("."), notify::RecursiveMode::Recursive);

    let mut pid: u32 = 0;
    let child = run_command(&confg);
    pid = child.unwrap().id();

    let confg_clone = confg.clone();
    let last_event_debounce = last_event.clone();

    std::thread::spawn(move || {
        loop {
            let flag = pending_restart_clone
                .lock()
                .unwrap()
                .load(std::sync::atomic::Ordering::SeqCst);

            if !flag {
                continue;
            }

            std::thread::sleep(Duration::from_millis(30));

            let elapsed = last_event_debounce.lock().unwrap().elapsed();
            if elapsed >= Duration::from_millis(confg_clone.delay) {
                println!("Restarting server after delay");
                let _ = restart_tx.send(Ok(Event::new(Default::default())));

                pending_restart_clone
                    .lock()
                    .unwrap()
                    .store(false, std::sync::atomic::Ordering::SeqCst);
            }
        }
    });

    for res in rx {
        match res {
            Ok(event) => {
                if pid != 0 {
                    let output = Command::new("kill")
                        .arg("-9")
                        .arg(pid.to_string())
                        .output()
                        .expect("failed to execute kill command");

                    if output.status.success() {
                        println!("Restarting development server");
                    } else {
                        eprintln!(
                            "Failed to kill process: {}",
                            String::from_utf8_lossy(&output.stderr)
                        );
                    }
                }

                let child = run_command(&confg).unwrap();
                pid = child.id();
            }
            Err(_) => {}
        }
    }
}