diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2020-09-11 18:19:49 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-11 18:19:49 +0200 |
commit | a3282aa9ed749f2e80618c6e2f25047d9a2bb2d8 (patch) | |
tree | 1755f5a8f65f692c3db72365d58dc669c934f3e0 /cli/file_watcher.rs | |
parent | 7ff0c4d8c88027a2157df5e2e6c47ef647a2e614 (diff) |
feat(unstable): deno run --watch (#7382)
Co-authored-by: Sebastian Seedorf <mail@sebse.de>
Diffstat (limited to 'cli/file_watcher.rs')
-rw-r--r-- | cli/file_watcher.rs | 92 |
1 files changed, 92 insertions, 0 deletions
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<Box<dyn Future<Output = std::result::Result<(), deno_core::ErrBox>>>>; + +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<F>( + 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::<Result<NotifyEvent, ErrBox>>(16); + let sender = std::sync::Mutex::new(sender); + + let mut watcher: RecommendedWatcher = + Watcher::new_immediate(move |res: Result<NotifyEvent, NotifyError>| { + 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(()) +} |