1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
mod watcher;
use ignore::overrides::OverrideBuilder;
use ignore::WalkBuilder;
pub use watcher::wait_for_changes;

use crate::build::command;
use crate::settings::toml::{Target, TargetType};
use crate::terminal::message;
use crate::wranglerjs;
use crate::{commands, install};

use notify::{self, RecursiveMode, Watcher};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

pub const COOLDOWN_PERIOD: Duration = Duration::from_millis(2000);
const JAVASCRIPT_PATH: &str = "./";
const RUST_PATH: &str = "./";

// Paths to ignore live watching in Rust Workers
const RUST_IGNORE: &[&str] = &["pkg", "target", "worker/generated"];

// watch a project for changes and re-build it when necessary,
// outputting a build event to tx.
pub fn watch_and_build(
    target: &Target,
    tx: Option<mpsc::Sender<()>>,
) -> Result<(), failure::Error> {
    let target_type = &target.target_type;
    match target_type {
        TargetType::JavaScript => {
            thread::spawn(move || {
                let (watcher_tx, watcher_rx) = mpsc::channel();
                let mut watcher = notify::watcher(watcher_tx, Duration::from_secs(1)).unwrap();

                watcher
                    .watch(JAVASCRIPT_PATH, RecursiveMode::Recursive)
                    .unwrap();
                message::info(&format!("watching {:?}", &JAVASCRIPT_PATH));

                loop {
                    match wait_for_changes(&watcher_rx, COOLDOWN_PERIOD) {
                        Ok(_path) => {
                            if let Some(tx) = tx.clone() {
                                tx.send(()).expect("--watch change message failed to send");
                            }
                        }
                        Err(e) => {
                            log::debug!("{:?}", e);
                            message::user_error("Something went wrong while watching.")
                        }
                    }
                }
            });
        }
        TargetType::Rust => {
            let binary_path = install::install_wasm_pack()?;
            let args = ["build", "--target", "no-modules"];

            thread::spawn(move || {
                let (watcher_tx, watcher_rx) = mpsc::channel();
                let mut watcher = notify::watcher(watcher_tx, Duration::from_secs(1)).unwrap();

                // Populate walker with ignored files so we ensure that the watcher does not watch
                // ignored directories
                let mut ignored_files = OverrideBuilder::new("./");
                for ignore in RUST_IGNORE {
                    ignored_files.add(&format!("!{}", ignore)).unwrap();
                }
                let ignored_file_override = ignored_files.build().unwrap();

                let walker = WalkBuilder::new("./")
                    .overrides(ignored_file_override)
                    .build();

                for entry in walker {
                    let entry = entry.unwrap();
                    if entry.path().is_dir() {
                        continue;
                    }
                    watcher
                        .watch(entry.path(), RecursiveMode::Recursive)
                        .unwrap();
                }
                message::info(&format!("watching {:?}", &RUST_PATH));

                loop {
                    match wait_for_changes(&watcher_rx, COOLDOWN_PERIOD) {
                        Ok(_path) => {
                            let command = command(&args, &binary_path);
                            let command_name = format!("{:?}", command);
                            if commands::run(command, &command_name).is_ok() {
                                if let Some(tx) = tx.clone() {
                                    tx.send(()).expect("--watch change message failed to send");
                                }
                            }
                        }
                        Err(_) => message::user_error("Something went wrong while watching."),
                    }
                }
            });
        }
        TargetType::Webpack => {
            wranglerjs::run_build_and_watch(target, tx)?;
        }
    }

    Ok(())
}