diff --git a/src/cli.rs b/src/cli.rs index 3d09eb5..9e73abd 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,12 +1,12 @@ -//! CLI arguments and library Args struct +//! CLI arguments and library Config struct //! -//! The [`Args`] struct is not constructable, use [`ArgsBuilder`]. +//! The [`Config`] struct is not constructable, use [`ConfigBuilder`]. //! //! # Examples //! //! ``` -//! # use watchexec::cli::ArgsBuilder; -//! ArgsBuilder::default() +//! # use watchexec::cli::ConfigBuilder; +//! ConfigBuilder::default() //! .cmd(vec!["echo hello world".into()]) //! .paths(vec![".".into()]) //! .build() @@ -22,85 +22,13 @@ use std::{ process::Command, }; -/// Arguments to the watcher -#[derive(Builder, Clone, Debug)] -#[builder(setter(into, strip_option))] -#[builder(build_fn(validate = "Self::validate"))] -#[non_exhaustive] -pub struct Args { - /// Command to execute in popen3 format (first program, rest arguments). - pub cmd: Vec, - /// List of paths to watch for changes. - pub paths: Vec, - /// Positive filters (trigger only on matching changes). Glob format. - #[builder(default)] - pub filters: Vec, - /// Negative filters (do not trigger on matching changes). Glob format. - #[builder(default)] - pub ignores: Vec, - /// Clear the screen before each run. - #[builder(default)] - pub clear_screen: bool, - /// If Some, send that signal (e.g. SIGHUP) to the child on change. - #[builder(default)] - pub signal: Option, - /// If true, kill the child if it's still running when a change comes in. - #[builder(default)] - pub restart: bool, - /// Interval to debounce the changes. (milliseconds) - #[builder(default = "500")] - pub debounce: u64, - /// Run the commands right after starting. - #[builder(default = "true")] - pub run_initially: bool, - /// Do not wrap the commands in a shell. - #[builder(default)] - pub no_shell: bool, - /// Ignore metadata changes. - #[builder(default)] - pub no_meta: bool, - /// Do not set WATCHEXEC_*_PATH environment variables for child process. - #[builder(default)] - pub no_environment: bool, - /// Skip auto-loading .gitignore files - #[builder(default)] - pub no_vcs_ignore: bool, - /// Skip auto-loading .ignore files - #[builder(default)] - pub no_ignore: bool, - /// For testing only, always set to false. - #[builder(setter(skip))] - #[builder(default)] - #[doc(hidden)] - pub once: bool, - /// Force using the polling backend. - #[builder(default)] - pub poll: bool, - /// Interval for polling. (milliseconds) - #[builder(default = "1000")] - pub poll_interval: u32, - #[builder(default)] - pub watch_when_idle: bool, -} +use crate::config::{Config, ConfigBuilder}; -impl ArgsBuilder { - fn validate(&self) -> Result<(), String> { - if self.cmd.as_ref().map_or(true, Vec::is_empty) { - return Err("cmd must not be empty".into()); - } +#[deprecated(since = "1.15.0", note = "Config has moved to config::Config")] +pub type Args = Config; - if self.paths.as_ref().map_or(true, Vec::is_empty) { - return Err("paths must not be empty".into()); - } - - Ok(()) - } - - #[deprecated(since = "1.15.0", note = "does nothing. set the log level instead")] - pub fn debug(&mut self, _: impl Into) -> &mut Self { - self - } -} +#[deprecated(since = "1.15.0", note = "ConfigBuilder has moved to config::ConfigBuilder")] +pub type ArgsBuilder = ConfigBuilder; /// Clear the screen. #[cfg(target_family = "windows")] @@ -120,12 +48,12 @@ pub fn clear_screen() { } #[deprecated(since = "1.15.0", note = "this will be removed from the library API. use the builder")] -pub fn get_args() -> error::Result<(Args, LevelFilter)> { +pub fn get_args() -> error::Result<(Config, LevelFilter)> { get_args_impl(None::<&[&str]>) } #[deprecated(since = "1.15.0", note = "this will be removed from the library API. use the builder")] -pub fn get_args_from(from: I) -> error::Result<(Args, LevelFilter)> +pub fn get_args_from(from: I) -> error::Result<(Config, LevelFilter)> where I: IntoIterator, T: Into + Clone, @@ -133,7 +61,7 @@ where get_args_impl(Some(from)) } -fn get_args_impl(from: Option) -> error::Result<(Args, LevelFilter)> +fn get_args_impl(from: Option) -> error::Result<(Config, LevelFilter)> where I: IntoIterator, T: Into + Clone, @@ -243,7 +171,7 @@ where Some(i) => app.get_matches_from(i), }; - let mut builder = ArgsBuilder::default(); + let mut builder = ConfigBuilder::default(); let cmd: Vec = values_t!(args.values_of("command"), String).map_err(|err| err.to_string())?; builder.cmd(cmd); diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..5de60f1 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,96 @@ +//! Configuration for watchexec. +//! +//! The [`Config`] struct is not constructable, use [`ConfigBuilder`]. +//! +//! # Examples +//! +//! ``` +//! # use watchexec::config::ConfigBuilder; +//! ConfigBuilder::default() +//! .cmd(vec!["echo hello world".into()]) +//! .paths(vec![".".into()]) +//! .build() +//! .expect("mission failed"); +//! ``` + +use std::path::PathBuf; + +/// Arguments to the watcher +#[derive(Builder, Clone, Debug)] +#[builder(setter(into, strip_option))] +#[builder(build_fn(validate = "Self::validate"))] +#[non_exhaustive] +pub struct Config { + /// Command to execute in popen3 format (first program, rest arguments). + pub cmd: Vec, + /// List of paths to watch for changes. + pub paths: Vec, + /// Positive filters (trigger only on matching changes). Glob format. + #[builder(default)] + pub filters: Vec, + /// Negative filters (do not trigger on matching changes). Glob format. + #[builder(default)] + pub ignores: Vec, + /// Clear the screen before each run. + #[builder(default)] + pub clear_screen: bool, + /// If Some, send that signal (e.g. SIGHUP) to the child on change. + #[builder(default)] + pub signal: Option, + /// If true, kill the child if it's still running when a change comes in. + #[builder(default)] + pub restart: bool, + /// Interval to debounce the changes. (milliseconds) + #[builder(default = "500")] + pub debounce: u64, + /// Run the commands right after starting. + #[builder(default = "true")] + pub run_initially: bool, + /// Do not wrap the commands in a shell. + #[builder(default)] + pub no_shell: bool, + /// Ignore metadata changes. + #[builder(default)] + pub no_meta: bool, + /// Do not set WATCHEXEC_*_PATH environment variables for child process. + #[builder(default)] + pub no_environment: bool, + /// Skip auto-loading .gitignore files + #[builder(default)] + pub no_vcs_ignore: bool, + /// Skip auto-loading .ignore files + #[builder(default)] + pub no_ignore: bool, + /// For testing only, always set to false. + #[builder(setter(skip))] + #[builder(default)] + #[doc(hidden)] + pub once: bool, + /// Force using the polling backend. + #[builder(default)] + pub poll: bool, + /// Interval for polling. (milliseconds) + #[builder(default = "1000")] + pub poll_interval: u32, + #[builder(default)] + pub watch_when_idle: bool, +} + +impl ConfigBuilder { + fn validate(&self) -> Result<(), String> { + if self.cmd.as_ref().map_or(true, Vec::is_empty) { + return Err("cmd must not be empty".into()); + } + + if self.paths.as_ref().map_or(true, Vec::is_empty) { + return Err("paths must not be empty".into()); + } + + Ok(()) + } + + #[deprecated(since = "1.15.0", note = "does nothing. set the log level instead")] + pub fn debug(&mut self, _: impl Into) -> &mut Self { + self + } +} diff --git a/src/lib.rs b/src/lib.rs index 2e6c34d..4235ad6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ extern crate log; extern crate lazy_static; pub mod cli; +pub mod config; pub mod error; mod gitignore; mod ignore; @@ -34,5 +35,10 @@ pub mod run; mod signal; mod watcher; -pub use cli::{Args, ArgsBuilder}; pub use run::{run, watch, Handler}; + +#[deprecated(since = "1.15.0", note = "Config has moved to config::Config")] +pub type Args = config::Config; + +#[deprecated(since = "1.15.0", note = "ConfigBuilder has moved to config::ConfigBuilder")] +pub type ArgsBuilder = config::ConfigBuilder; diff --git a/src/run.rs b/src/run.rs index 996f8af..594b87a 100644 --- a/src/run.rs +++ b/src/run.rs @@ -1,4 +1,5 @@ -use crate::cli::{clear_screen, Args}; +use crate::cli::{clear_screen}; +use crate::config::Config; use crate::error::{Error, Result}; use crate::gitignore; use crate::ignore; @@ -48,9 +49,9 @@ pub trait Handler { /// /// Not called again; any changes will never be picked up. /// - /// The `Args` instance should be created using `ArgsBuilder` rather than direct initialisation + /// The `Config` instance should be created using `ConfigBuilder` rather than direct initialisation /// to resist potential breaking changes (see semver policy on crate root). - fn args(&self) -> Args; + fn args(&self) -> Config; } /// Starts watching, and calls a handler when something happens. @@ -130,13 +131,13 @@ where } pub struct ExecHandler { - args: Args, + args: Config, signal: Option, child_process: Arc>>, } impl ExecHandler { - pub fn new(args: Args) -> Result { + pub fn new(args: Config) -> Result { let child_process: Arc>> = Arc::new(RwLock::new(None)); let weak_child = Arc::downgrade(&child_process); @@ -190,7 +191,7 @@ impl ExecHandler { } impl Handler for ExecHandler { - fn args(&self) -> Args { + fn args(&self) -> Config { self.args.clone() } @@ -267,7 +268,7 @@ impl Handler for ExecHandler { } } -pub fn run(args: Args) -> Result<()> { +pub fn run(args: Config) -> Result<()> { watch(&ExecHandler::new(args)?) }