mirror of
https://github.com/watchexec/watchexec.git
synced 2024-09-29 22:51:33 +02:00
Move Args and builder to Config, and deprecate old names
This commit is contained in:
parent
31fd818247
commit
cd3b8c6cba
98
src/cli.rs
98
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
|
//! # 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
96
src/config.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
15
src/run.rs
15
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::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)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user