diff --git a/Cargo.lock b/Cargo.lock index 1b4347f..4272eb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,6 +16,33 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "autocfg" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "backtrace" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "0.7.0" @@ -40,6 +67,11 @@ dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cc" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cfg-if" version = "0.1.6" @@ -79,8 +111,38 @@ dependencies = [ name = "entr" version = "0.1.0" dependencies = [ - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "exitfailure 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "notify 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "exitfailure" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -130,6 +192,14 @@ name = "futures" version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "inotify" version = "0.6.1" @@ -307,6 +377,22 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro2" +version = "0.4.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.5.5" @@ -345,6 +431,11 @@ dependencies = [ "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustc-demangle" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc_version" version = "0.2.3" @@ -402,6 +493,47 @@ name = "strsim" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "structopt" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "structopt-derive" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "0.15.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termion" version = "1.5.1" @@ -455,11 +587,21 @@ dependencies = [ "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "unicode-segmentation" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-width" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unreachable" version = "1.0.0" @@ -537,20 +679,28 @@ dependencies = [ [metadata] "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" +"checksum autocfg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e5f34df7a019573fb8bdc7e24a2bfebe51a2a1d6bfdbaeccedb3c41fc574727" +"checksum backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b5b493b66e03090ebc4343eb02f94ff944e0cbc9ac6571491d170ba026741eb5" +"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" +"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "41ee4864f4797060e52044376f7d107429ce1fb43460021b126424b7180ee21a" +"checksum exitfailure 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ff5bd832af37f366c6c194d813a11cd90ac484f124f079294f28e357ae40515" +"checksum failure 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e945b93ec214c6e97b520ec6c5d80267fc97af327658ee5b9f35984626e51fbf" +"checksum failure_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c395a14ab27b42704e85bf2435c5c51f334ad7a96e16fe23c6e63a1cad6cc12" "checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646" "checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05" "checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" +"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718" "checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" @@ -569,11 +719,14 @@ dependencies = [ "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" "checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" +"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" +"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" "checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" "checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" "checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" "checksum redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a84bcd297b87a545980a2d25a0beb72a1f490c31f0a9fde52fca35bfbb1ceb70" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum rustc-demangle 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "01b90379b8664dd83460d59bdc5dd1fd3172b8913788db483ed1325171eab2f7" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" @@ -583,12 +736,18 @@ dependencies = [ "checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" +"checksum structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "670ad348dc73012fcf78c71f06f9d942232cdd4c859d4b6975e27836c3efc0c3" +"checksum structopt-derive 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ef98172b1a00b0bec738508d3726540edcbd186d50dfd326f2b1febbb3559f04" +"checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc" +"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" "checksum tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c117b6cf86bb730aab4834f10df96e4dd586eff2c3c27d3781348da49e255bde" "checksum tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "7392fe0a70d5ce0c882c4778116c519bd5dbaa8a7c3ae3d04578b3afafdcda21" "checksum tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "502b625acb4ee13cbb3b90b8ca80e0addd263ddacf6931666ef751e610b07fb5" +"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/Cargo.toml b/Cargo.toml index df8932c..e2fcbbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,6 @@ edition = "2018" [dependencies] notify = "4.0.0" -clap = "2.32.0" +failure = "0.1.4" +exitfailure = "0.5.1" +structopt = "0.2.14" diff --git a/src/main.rs b/src/main.rs index 24c393c..2aa8c40 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,139 +1,150 @@ extern crate notify; +extern crate structopt; #[macro_use] -extern crate clap; +extern crate failure; +extern crate exitfailure; -use clap::{Arg, App}; -use notify::{RecommendedWatcher, Watcher, RecursiveMode, DebouncedEvent}; -use std::sync::mpsc; +use std::sync::mpsc::{self, Receiver}; use std::time::Duration; -use std::io::{self, Read, ErrorKind}; +use std::io::{self, Read}; use std::env; -use std::process::{Command, ExitStatus}; - -fn main() { - let matches = App::new("entr") - .version(&crate_version!()[..]) - .author("Mauri de Souza nunes ") - .about( - "Cross platform way to run arbitrary commands when files change", - ) - .arg(Arg::with_name("clear").short("c").help( - "Clear the screen before invoking the utility", - )) - .arg(Arg::with_name("postpone").short("p").help( - "Postpone the first execution of the utility until a file is modified", - )) - .arg(Arg::with_name("recursive").short("R").help( - "Watch for changes in directories recursively", - )) - .arg(Arg::with_name("shell").short("s").help( - "Evaluate the first argument using the default interpreter", - )) - .arg(Arg::with_name("utility").multiple(true).help( - "The utility to run when files change", - )) - .get_matches(); - - let clear_term = matches.is_present("clear"); - let postpone = matches.is_present("postpone"); - let recursive = matches.is_present("recursive"); - let use_shell = matches.is_present("shell"); - - let utility = match matches.values_of_lossy("utility") { - Some(mut val) => { - if !use_shell { - val - } else { - let mut shell = get_shell_cmd(); - shell.append(&mut val); - shell - } +use std::process::Command; + +use notify::{RecommendedWatcher, Watcher, RecursiveMode, DebouncedEvent}; +use structopt::StructOpt; +use failure::{Error, ResultExt}; +use exitfailure::ExitFailure; + +#[derive(Debug, Fail)] +enum EntrError { + #[fail(display = "No files or dirs to watch")] + NoFilesToWatch, +} + +#[derive(Debug, StructOpt)] +#[structopt(name = "entr", + about = "Cross platform way to run arbitrary commands when files change")] +struct Entr { + /// Clear the screen before invoking the utility + #[structopt(short = "c")] + clear_term: bool, + /// Postpone the first execution of the utility until a file is modified + #[structopt(short = "p")] + postpone: bool, + /// Watch for changes in directories recursively + #[structopt(short = "R")] + recursive: bool, + /// Evaluate the first argument using the default interpreter + #[structopt(short = "s")] + use_shell: bool, + /// The utility to run when files change + utility: Vec, +} + +impl Entr { + /// Run the application + fn run( + mut self, + rx: Receiver, + mut watcher: RecommendedWatcher, + ) -> Result<(), ExitFailure> { + self.utility = if !self.use_shell { + self.utility + } else { + let mut shell = Entr::get_shell_cmd(); + shell.append(&mut self.utility); + shell + }; + + let mut buf = String::new(); + io::stdin().read_to_string(&mut buf).with_context(|_| { + format!("Failed to read files to watch") + })?; + + let files: Vec = buf.trim() + .split("\n") + .filter(|s| !s.is_empty()) + .map(|s| s.to_owned()) + .collect(); + + if files.is_empty() { + Err(EntrError::NoFilesToWatch)? } - None => panic!("No utility provided"), - }; - - let mut buf = String::new(); - io::stdin().read_to_string(&mut buf).expect( - "Failed to read files to watch", - ); - - let files: Vec = buf.trim() - .split("\n") - .filter(|s| !s.is_empty()) - .map(|s| s.to_owned()) - .collect(); - - if files.is_empty() { - panic!("No files or dirs to watch"); - } - let (tx, rx) = mpsc::channel(); - let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(0)).unwrap(); - - let recursive_mode = if recursive { - RecursiveMode::Recursive - } else { - RecursiveMode::NonRecursive - }; - for f in &files { - if let Err(err) = watcher.watch(f, recursive_mode) { - panic!("Failed to watch {} - {}", f, err); + let recursive_mode = if self.recursive { + RecursiveMode::Recursive + } else { + RecursiveMode::NonRecursive + }; + for f in &files { + watcher.watch(f, recursive_mode).with_context(|_| { + format!("Failed to watch {}", f) + })?; } - } - // Running first iteration manually - if !postpone { - run_command(&utility, clear_term); - } + // Running first iteration manually + if !self.postpone { + self.run_utility()?; + } - loop { - match rx.recv() { - // Discard initial notices - Ok(DebouncedEvent::NoticeWrite(_)) => continue, - Ok(DebouncedEvent::NoticeRemove(_)) => continue, - Ok(DebouncedEvent::Chmod(_)) => continue, - Ok(_) => run_command(&utility, clear_term), - Err(e) => panic!("watch error: {}", e), + loop { + match rx.recv() { + // Discard initial notices + Ok(DebouncedEvent::NoticeWrite(_)) => continue, + Ok(DebouncedEvent::NoticeRemove(_)) => continue, + Ok(DebouncedEvent::Chmod(_)) => continue, + Ok(_) => self.run_utility()?, + Err(e) => Err(e).with_context(|_| format!("Error watching files"))?, + } } } -} -fn get_shell_cmd() -> Vec { - if cfg!(windows) { - vec!["cmd".to_string(), "/c".to_string()] - } else { - // Assume GNU - let shell = env::var("SHELL").unwrap_or("/bin/sh".to_string()); - vec![shell, "-c".to_string()] + /// Get the sytem's shell command string + fn get_shell_cmd() -> Vec { + if cfg!(windows) { + vec!["cmd".to_string(), "/c".to_string()] + } else { + // Assume GNU + let shell = env::var("SHELL").unwrap_or("/bin/sh".to_string()); + vec![shell, "-c".to_string()] + } } -} -fn clear_term_screen() -> io::Result { - let clear_cmd = if cfg!(windows) { - "cls" - } else { - // Assume POSIX - "clear" - }; - Command::new(clear_cmd).status() -} + /// Clear the terminal screen + fn clear_term_screen(&self) -> Result<(), Error> { + let clear_cmd = if cfg!(windows) { + "cls" + } else { + // Assume POSIX + "clear" + }; + Command::new(clear_cmd).status()?; -fn run_command(utility: &Vec, clear_term: bool) { - if clear_term { - clear_term_screen().expect("Failed to clear terminal screen"); + Ok(()) } - match Command::new(&utility[0]).args(&utility[1..]).spawn() { - Err(e) => { - if let ErrorKind::NotFound = e.kind() { - panic!( - "{} was not found! Check your PATH or the provided utility!", - &utility[0] - ); - } else { - panic!("Error running the specified utility: {}", e); - } + /// Run the provided utility + fn run_utility(&self) -> Result<(), Error> { + if self.clear_term { + self.clear_term_screen().with_context(|_| { + format!("Failed to clear terminal screen") + })?; } - _ => {} + + Command::new(&self.utility[0]) + .args(&self.utility[1..]) + .spawn() + .with_context(|_| { + format!("{} Failed to run the provided utility", &self.utility[0]) + })?; + + Ok(()) } } + +fn main() -> Result<(), ExitFailure> { + let (tx, rx) = mpsc::channel(); + let watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(0)).unwrap(); + + Entr::from_args().run(rx, watcher) +}