#![feature(let_chains)] mod generator; use clap::{Command, arg, command}; use debounced::debounced; use futures::FutureExt; use generator::{FileWatcher, content_base_path}; use log::info; use std::cell::RefCell; use std::rc::Rc; use std::time::Duration; use tokio::pin; use tokio_stream::StreamExt; use tokio_stream::wrappers::UnboundedReceiverStream; #[tokio::main] async fn main() { env_logger::init(); let matches = command!() .subcommand_required(true) .arg_required_else_help(true) .subcommand( Command::new("gen") .arg(arg!(--watch "Watch the site directory and regenerate on changes")), ) .subcommand( Command::new("serve") .arg(arg!(--watch "Watch the site directory and regenerate on changes")), ) .get_matches(); if cfg!(debug_assertions) { info!("Running in dev mode"); } else { info!("Running in release mode"); } match matches.subcommand() { Some(("gen", matches)) => { let watcher = Rc::new(RefCell::new(FileWatcher::new())); let mut graph = generator::generate(Rc::clone(&watcher)) .await .expect("generating"); if matches.contains_id("watch") { let (tx, rx) = tokio::sync::mpsc::unbounded_channel::<()>(); watcher.borrow_mut().watch(content_base_path(), move || { tx.send(()).expect("sending regenerate signal"); }); let mut debounced = debounced(UnboundedReceiverStream::new(rx), Duration::from_millis(100)); let watch = FileWatcher::start(watcher).fuse(); let regenerate = async move { while let Some(_) = debounced.next().await { info!("Regenerating"); graph.evaluate_async().await; } } .fuse(); pin!(regenerate, watch); loop { futures::select! { watcher_res = watch => { watcher_res.expect("watching files"); } _ = regenerate => { info!("regenerate channel closed"); } } } } } Some(("serve", _matches)) => { todo!() } _ => unreachable!(), } }