Move Args and builder to Config, and deprecate old names

This commit is contained in:
Félix Saparelli 2021-04-11 01:23:24 +12:00
parent 31fd818247
commit cd3b8c6cba
No known key found for this signature in database
GPG Key ID: B948C4BAE44FC474
4 changed files with 124 additions and 93 deletions

View File

@ -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 //! # Examples
//! //!
//! ``` //! ```
//! # use watchexec::cli::ArgsBuilder; //! # use watchexec::cli::ConfigBuilder;
//! ArgsBuilder::default() //! ConfigBuilder::default()
//! .cmd(vec!["echo hello world".into()]) //! .cmd(vec!["echo hello world".into()])
//! .paths(vec![".".into()]) //! .paths(vec![".".into()])
//! .build() //! .build()
@ -22,85 +22,13 @@ use std::{
process::Command, process::Command,
}; };
/// Arguments to the watcher use crate::config::{Config, ConfigBuilder};
#[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<String>,
/// List of paths to watch for changes.
pub paths: Vec<PathBuf>,
/// Positive filters (trigger only on matching changes). Glob format.
#[builder(default)]
pub filters: Vec<String>,
/// Negative filters (do not trigger on matching changes). Glob format.
#[builder(default)]
pub ignores: Vec<String>,
/// 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<String>,
/// 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 ArgsBuilder { #[deprecated(since = "1.15.0", note = "Config has moved to config::Config")]
fn validate(&self) -> Result<(), String> { pub type Args = Config;
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) { #[deprecated(since = "1.15.0", note = "ConfigBuilder has moved to config::ConfigBuilder")]
return Err("paths must not be empty".into()); pub type ArgsBuilder = ConfigBuilder;
}
Ok(())
}
#[deprecated(since = "1.15.0", note = "does nothing. set the log level instead")]
pub fn debug(&mut self, _: impl Into<bool>) -> &mut Self {
self
}
}
/// Clear the screen. /// Clear the screen.
#[cfg(target_family = "windows")] #[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")] #[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]>) get_args_impl(None::<&[&str]>)
} }
#[deprecated(since = "1.15.0", note = "this will be removed from the library API. use the builder")] #[deprecated(since = "1.15.0", note = "this will be removed from the library API. use the builder")]
pub fn get_args_from<I, T>(from: I) -> error::Result<(Args, LevelFilter)> pub fn get_args_from<I, T>(from: I) -> error::Result<(Config, LevelFilter)>
where where
I: IntoIterator<Item = T>, I: IntoIterator<Item = T>,
T: Into<OsString> + Clone, T: Into<OsString> + Clone,
@ -133,7 +61,7 @@ where
get_args_impl(Some(from)) get_args_impl(Some(from))
} }
fn get_args_impl<I, T>(from: Option<I>) -> error::Result<(Args, LevelFilter)> fn get_args_impl<I, T>(from: Option<I>) -> error::Result<(Config, LevelFilter)>
where where
I: IntoIterator<Item = T>, I: IntoIterator<Item = T>,
T: Into<OsString> + Clone, T: Into<OsString> + Clone,
@ -243,7 +171,7 @@ where
Some(i) => app.get_matches_from(i), Some(i) => app.get_matches_from(i),
}; };
let mut builder = ArgsBuilder::default(); let mut builder = ConfigBuilder::default();
let cmd: Vec<String> = values_t!(args.values_of("command"), String).map_err(|err| err.to_string())?; let cmd: Vec<String> = values_t!(args.values_of("command"), String).map_err(|err| err.to_string())?;
builder.cmd(cmd); builder.cmd(cmd);

96
src/config.rs Normal file
View File

@ -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<String>,
/// List of paths to watch for changes.
pub paths: Vec<PathBuf>,
/// Positive filters (trigger only on matching changes). Glob format.
#[builder(default)]
pub filters: Vec<String>,
/// Negative filters (do not trigger on matching changes). Glob format.
#[builder(default)]
pub ignores: Vec<String>,
/// 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<String>,
/// 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<bool>) -> &mut Self {
self
}
}

View File

@ -24,6 +24,7 @@ extern crate log;
extern crate lazy_static; extern crate lazy_static;
pub mod cli; pub mod cli;
pub mod config;
pub mod error; pub mod error;
mod gitignore; mod gitignore;
mod ignore; mod ignore;
@ -34,5 +35,10 @@ pub mod run;
mod signal; mod signal;
mod watcher; mod watcher;
pub use cli::{Args, ArgsBuilder};
pub use run::{run, watch, Handler}; 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;

View File

@ -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::error::{Error, Result};
use crate::gitignore; use crate::gitignore;
use crate::ignore; use crate::ignore;
@ -48,9 +49,9 @@ pub trait Handler {
/// ///
/// Not called again; any changes will never be picked up. /// 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). /// 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. /// Starts watching, and calls a handler when something happens.
@ -130,13 +131,13 @@ where
} }
pub struct ExecHandler { pub struct ExecHandler {
args: Args, args: Config,
signal: Option<Signal>, signal: Option<Signal>,
child_process: Arc<RwLock<Option<Process>>>, child_process: Arc<RwLock<Option<Process>>>,
} }
impl ExecHandler { impl ExecHandler {
pub fn new(args: Args) -> Result<Self> { pub fn new(args: Config) -> Result<Self> {
let child_process: Arc<RwLock<Option<Process>>> = Arc::new(RwLock::new(None)); let child_process: Arc<RwLock<Option<Process>>> = Arc::new(RwLock::new(None));
let weak_child = Arc::downgrade(&child_process); let weak_child = Arc::downgrade(&child_process);
@ -190,7 +191,7 @@ impl ExecHandler {
} }
impl Handler for ExecHandler { impl Handler for ExecHandler {
fn args(&self) -> Args { fn args(&self) -> Config {
self.args.clone() 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)?) watch(&ExecHandler::new(args)?)
} }