Use ArgsBuilder ourselves

This commit is contained in:
Félix Saparelli 2021-04-11 01:09:06 +12:00
parent 0c6b1bf2e4
commit 757de0d92e
No known key found for this signature in database
GPG Key ID: B948C4BAE44FC474
2 changed files with 50 additions and 65 deletions

View File

@ -14,7 +14,8 @@
//! ``` //! ```
use crate::error; use crate::error;
use clap::{App, Arg, Error}; use clap::{App, Arg};
use log::LevelFilter;
use std::{ use std::{
ffi::OsString, ffi::OsString,
path::{PathBuf, MAIN_SEPARATOR}, path::{PathBuf, MAIN_SEPARATOR},
@ -242,25 +243,30 @@ where
Some(i) => app.get_matches_from(i), Some(i) => app.get_matches_from(i),
}; };
let cmd: Vec<String> = values_t!(args.values_of("command"), String)?; let mut builder = ArgsBuilder::default();
let paths = values_t!(args.values_of("path"), String)
let cmd: Vec<String> = values_t!(args.values_of("command"), String).map_err(|err| err.to_string())?;
builder.cmd(cmd);
let paths: Vec<PathBuf> = values_t!(args.values_of("path"), String)
.unwrap_or_else(|_| vec![".".into()]) .unwrap_or_else(|_| vec![".".into()])
.iter() .iter()
.map(|string_path| string_path.into()) .map(|string_path| string_path.into())
.collect(); .collect();
builder.paths(paths);
// Treat --kill as --signal SIGKILL (for compatibility with older syntax) // Treat --kill as --signal SIGKILL (for compatibility with deprecated syntax)
let signal = if args.is_present("kill") { if args.is_present("kill") {
Some("SIGKILL".to_string()) builder.signal("SIGKILL");
} else { }
// Convert Option<&str> to Option<String>
args.value_of("signal").map(str::to_string) if let Some(signal) = args.value_of("signal") {
}; builder.signal(signal);
}
let mut filters = values_t!(args.values_of("filter"), String).unwrap_or_else(|_| Vec::new()); let mut filters = values_t!(args.values_of("filter"), String).unwrap_or_else(|_| Vec::new());
if let Some(extensions) = args.values_of("extensions") { if let Some(extensions) = args.values_of("extensions") {
for exts in extensions { for exts in extensions { // TODO: refactor with flatten()
filters.extend(exts.split(',').filter_map(|ext| { filters.extend(exts.split(',').filter_map(|ext| {
if ext.is_empty() { if ext.is_empty() {
None None
@ -271,6 +277,8 @@ where
} }
} }
builder.filters(filters);
let mut ignores = vec![]; let mut ignores = vec![];
let default_ignores = vec![ let default_ignores = vec![
format!("**{}.DS_Store", MAIN_SEPARATOR), format!("**{}.DS_Store", MAIN_SEPARATOR),
@ -290,50 +298,33 @@ where
}; };
ignores.extend(values_t!(args.values_of("ignore"), String).unwrap_or_else(|_| Vec::new())); ignores.extend(values_t!(args.values_of("ignore"), String).unwrap_or_else(|_| Vec::new()));
let poll_interval = if args.occurrences_of("poll") > 0 { builder.ignores(ignores);
value_t!(args.value_of("poll"), u32).unwrap_or_else(|e| e.exit())
} else {
1000
};
let debounce = if args.occurrences_of("debounce") > 0 { if args.occurrences_of("poll") > 0 {
value_t!(args.value_of("debounce"), u64).unwrap_or_else(|e| e.exit()) builder.poll_interval(value_t!(args.value_of("poll"), u32).unwrap_or_else(|e| e.exit()));
} else {
500
};
if signal.is_some() && args.is_present("postpone") {
// TODO: Error::argument_conflict() might be the better fit, usage was unclear, though
Error::value_validation_auto("--postpone and --signal are mutually exclusive".to_string())
.exit();
} }
if signal.is_some() && args.is_present("kill") { if args.occurrences_of("debounce") > 0 {
// TODO: Error::argument_conflict() might be the better fit, usage was unclear, though builder.debounce(value_t!(args.value_of("debounce"), u64).unwrap_or_else(|e| e.exit()));
Error::value_validation_auto("--kill and --signal is ambiguous.\n Hint: Use only '--signal SIGKILL' without --kill".to_string())
.exit();
} }
Ok(Args { // TODO: check how postpone + signal behaves
cmd,
paths, builder.clear_screen(args.is_present("clear"));
filters, builder.restart(args.is_present("restart"));
ignores, builder.run_initially(!args.is_present("postpone"));
signal, builder.no_shell(args.is_present("no-shell"));
clear_screen: args.is_present("clear"), builder.no_meta(args.is_present("no-meta"));
restart: args.is_present("restart"), builder.no_environment(args.is_present("no-environment"));
debounce, builder.no_vcs_ignore(args.is_present("no-vcs-ignore"));
debug: args.is_present("verbose"), builder.no_ignore(args.is_present("no-ignore"));
changes: args.is_present("changes"), builder.poll(args.occurrences_of("poll") > 0);
run_initially: !args.is_present("postpone"), builder.watch_when_idle(args.is_present("watch-when-idle"));
no_shell: args.is_present("no-shell"),
no_meta: args.is_present("no-meta"), let mut config = builder.build()?;
no_environment: args.is_present("no-environment"), if args.is_present("once") {
no_vcs_ignore: args.is_present("no-vcs-ignore"), config.once = true;
no_ignore: args.is_present("no-ignore"), }
once: args.is_present("once"),
poll: args.occurrences_of("poll") > 0, Ok(config)
poll_interval,
watch_when_idle: args.is_present("watch-when-idle"),
})
} }

View File

@ -4,24 +4,18 @@ pub type Result<T> = ::std::result::Result<T, Error>;
pub enum Error { pub enum Error {
Canonicalization(String, io::Error), Canonicalization(String, io::Error),
Clap(clap::Error),
Glob(globset::Error), Glob(globset::Error),
Io(io::Error), Io(io::Error),
Notify(notify::Error), Notify(notify::Error),
Generic(String),
PoisonedLock, PoisonedLock,
} }
impl StdError for Error { impl StdError for Error {}
fn description(&self) -> &str {
// This method is soft-deprecated and shouldn't be used,
// see Display for the actual description.
"a watchexec error"
}
}
impl From<clap::Error> for Error { impl From<String> for Error {
fn from(err: clap::Error) -> Self { fn from(err: String) -> Self {
Self::Clap(err) Self::Generic(err)
} }
} }
@ -68,7 +62,7 @@ impl fmt::Display for Error {
"Path", "Path",
format!("couldn't canonicalize '{}':\n{}", path, err), format!("couldn't canonicalize '{}':\n{}", path, err),
), ),
Self::Clap(err) => ("Argument", err.to_string()), Self::Generic(err) => ("", err.clone()),
Self::Glob(err) => ("Globset", err.to_string()), Self::Glob(err) => ("Globset", err.to_string()),
Self::Io(err) => ("I/O", err.to_string()), Self::Io(err) => ("I/O", err.to_string()),
Self::Notify(err) => ("Notify", err.to_string()), Self::Notify(err) => ("Notify", err.to_string()),