From a3282aa9ed749f2e80618c6e2f25047d9a2bb2d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Fri, 11 Sep 2020 18:19:49 +0200 Subject: feat(unstable): deno run --watch (#7382) Co-authored-by: Sebastian Seedorf --- cli/file_watcher.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 cli/file_watcher.rs (limited to 'cli/file_watcher.rs') diff --git a/cli/file_watcher.rs b/cli/file_watcher.rs new file mode 100644 index 000000000..892d0d4a1 --- /dev/null +++ b/cli/file_watcher.rs @@ -0,0 +1,92 @@ +use crate::colors; +use deno_core::ErrBox; +use futures::stream::StreamExt; +use futures::Future; +use notify::event::Event as NotifyEvent; +use notify::event::EventKind; +use notify::Config; +use notify::Error as NotifyError; +use notify::RecommendedWatcher; +use notify::RecursiveMode; +use notify::Watcher; +use std::path::PathBuf; +use std::pin::Pin; +use tokio::select; +use tokio::sync::mpsc; + +// TODO(bartlomieju): rename +type WatchFuture = + Pin>>>; + +async fn error_handler(watch_future: WatchFuture) { + let result = watch_future.await; + if let Err(err) = result { + let msg = format!("{}: {}", colors::red_bold("error"), err.to_string(),); + eprintln!("{}", msg); + } +} + +pub async fn watch_func( + watch_paths: &[PathBuf], + closure: F, +) -> Result<(), ErrBox> +where + F: Fn() -> WatchFuture, +{ + loop { + let func = error_handler(closure()); + let mut is_file_changed = false; + select! { + _ = file_watcher(watch_paths) => { + is_file_changed = true; + info!( + "{} File change detected! Restarting!", + colors::intense_blue("Watcher") + ); + }, + _ = func => { }, + }; + if !is_file_changed { + info!( + "{} Process terminated! Restarting on file change...", + colors::intense_blue("Watcher") + ); + file_watcher(watch_paths).await?; + info!( + "{} File change detected! Restarting!", + colors::intense_blue("Watcher") + ); + } + } +} + +pub async fn file_watcher(paths: &[PathBuf]) -> Result<(), deno_core::ErrBox> { + let (sender, mut receiver) = mpsc::channel::>(16); + let sender = std::sync::Mutex::new(sender); + + let mut watcher: RecommendedWatcher = + Watcher::new_immediate(move |res: Result| { + let res2 = res.map_err(ErrBox::from); + let mut sender = sender.lock().unwrap(); + // Ignore result, if send failed it means that watcher was already closed, + // but not all messages have been flushed. + let _ = sender.try_send(res2); + })?; + + watcher.configure(Config::PreciseEvents(true)).unwrap(); + + for path in paths { + watcher.watch(path, RecursiveMode::NonRecursive)?; + } + + while let Some(result) = receiver.next().await { + let event = result?; + match event.kind { + EventKind::Create(_) => break, + EventKind::Modify(_) => break, + EventKind::Remove(_) => break, + _ => continue, + } + } + Ok(()) +} -- cgit v1.2.3