Update clap version and cleanup some new warnings

This commit is contained in:
Jeremy Wall 2021-12-30 18:57:24 -05:00
parent 7bce901323
commit eb1d17407e
4 changed files with 90 additions and 66 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "runwhen"
version = "0.0.3"
version = "0.0.4"
authors = ["Jeremy Wall <jeremy@marzhillstudios.com>"]
description = "Runs a command on user specified triggers."
repository = "https://github.com/zaphar/runwhen"
@ -9,6 +9,6 @@ keywords = ["file", "watcher", "command-line", "trigger"]
license = "Apache-2.0"
[dependencies]
clap = "~2.19.0"
clap = "~2.34"
humantime = "~1.0.0"
notify = "~3.0.0"

View File

@ -11,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::error::Error;
use std::fmt;
use notify;
@ -35,6 +34,6 @@ impl fmt::Display for CommandError {
impl From<notify::Error> for CommandError {
fn from(e: notify::Error) -> CommandError {
CommandError::new(e.description().to_string())
CommandError::new(format!("{}", e))
}
}

View File

@ -11,18 +11,18 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::thread;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::path::Path;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
use notify::{Watcher, RecursiveMode, watcher};
use notify::{watcher, RecursiveMode, Watcher};
use traits::Process;
use error::CommandError;
use events::WatchEventType;
use exec::run_cmd;
use traits::Process;
pub struct FileProcess<'a> {
cmd: &'a str,
@ -33,12 +33,13 @@ pub struct FileProcess<'a> {
}
impl<'a> FileProcess<'a> {
pub fn new(cmd: &'a str,
env: Option<Vec<&'a str>>,
file: &'a str,
method: WatchEventType,
poll: Duration)
-> FileProcess<'a> {
pub fn new(
cmd: &'a str,
env: Option<Vec<&'a str>>,
file: &'a str,
method: WatchEventType,
poll: Duration,
) -> FileProcess<'a> {
FileProcess {
cmd: cmd,
env: env,
@ -49,9 +50,20 @@ impl<'a> FileProcess<'a> {
}
}
fn spawn_runner_thread(lock: Arc<Mutex<bool>>, cmd: String,
env: Option<Vec<&str>>, poll: Duration) {
let copied_env = env.and_then(|v| Some(v.iter().cloned().map(|s| String::from(s)).collect::<Vec<String>>()));
fn spawn_runner_thread(
lock: Arc<Mutex<bool>>,
cmd: String,
env: Option<Vec<&str>>,
poll: Duration,
) {
let copied_env = env.and_then(|v| {
Some(
v.iter()
.cloned()
.map(|s| String::from(s))
.collect::<Vec<String>>(),
)
});
thread::spawn(move || {
let copied_env_refs: Option<Vec<&str>> = match copied_env {
Some(ref vec) => {
@ -60,7 +72,7 @@ fn spawn_runner_thread(lock: Arc<Mutex<bool>>, cmd: String,
refs.push(s);
}
Some(refs)
},
}
None => None,
};
loop {
@ -68,34 +80,37 @@ fn spawn_runner_thread(lock: Arc<Mutex<bool>>, cmd: String,
thread::sleep(poll);
// Default to not running the command.
match lock.lock() {
Ok(mut signal) => if *signal {
// set signal to false so we won't trigger on the
// next loop iteration unless we recieved more events.
*signal = false;
// Run our command!
println!("exec: {}", cmd);
if let Err(err) = run_cmd(&cmd, &copied_env_refs) {
println!("{:?}", err)
Ok(mut signal) => {
if *signal {
// set signal to false so we won't trigger on the
// next loop iteration unless we recieved more events.
*signal = false;
// Run our command!
println!("exec: {}", cmd);
if let Err(err) = run_cmd(&cmd, &copied_env_refs) {
println!("{:?}", err)
}
}
},
}
Err(err) => {
println!("Unexpected error; {}", err);
return
return;
}
}
}
});
}
fn wait_for_fs_events(lock: Arc<Mutex<bool>>,
method: WatchEventType,
file: &str)
-> Result<(), CommandError> {
fn wait_for_fs_events(
lock: Arc<Mutex<bool>>,
method: WatchEventType,
file: &str,
) -> Result<(), CommandError> {
// Notify requires a channel for communication.
let (tx, rx) = channel();
let mut watcher = try!(watcher(tx, Duration::from_secs(1)));
let mut watcher = watcher(tx, Duration::from_secs(1))?;
// TODO(jwall): Better error handling.
try!(watcher.watch(file, RecursiveMode::Recursive));
watcher.watch(file, RecursiveMode::Recursive)?;
println!("Watching {:?}", file);
loop {
let evt: WatchEventType = match rx.recv() {
@ -115,15 +130,13 @@ fn wait_for_fs_events(lock: Arc<Mutex<bool>>,
*signal = true;
}
}
WatchEventType::Changed => {
match lock.lock() {
Ok(mut signal) => *signal = true,
Err(err) => {
println!("Unexpected error; {}", err);
return Ok(())
}
WatchEventType::Changed => match lock.lock() {
Ok(mut signal) => *signal = true,
Err(err) => {
println!("Unexpected error; {}", err);
return Ok(());
}
}
},
}
}
}
@ -133,12 +146,19 @@ impl<'a> Process for FileProcess<'a> {
// NOTE(jwall): this is necessary because notify::fsEventWatcher panics
// if the path doesn't exist. :-(
if !Path::new(self.file).exists() {
return Err(CommandError::new(format!("No such path! {0}", self.file).to_string()));
return Err(CommandError::new(
format!("No such path! {0}", self.file).to_string(),
));
}
// TODO(jeremy): Is this sufficent or do we want to ignore
// any events that come in while the command is running?
let lock = Arc::new(Mutex::new(false));
spawn_runner_thread(lock.clone(), self.cmd.to_string(), self.env.clone(), self.poll);
spawn_runner_thread(
lock.clone(),
self.cmd.to_string(),
self.env.clone(),
self.poll,
);
wait_for_fs_events(lock, self.method.clone(), self.file)
}
}

View File

@ -20,18 +20,18 @@ extern crate notify;
use std::process;
use std::str::FromStr;
mod traits;
mod file;
mod timer;
mod error;
mod events;
mod exec;
mod file;
mod timer;
mod traits;
use traits::Process;
use events::WatchEventType;
use exec::ExecProcess;
use file::FileProcess;
use timer::TimerProcess;
use exec::ExecProcess;
use events::WatchEventType;
use traits::Process;
fn do_flags<'a>() -> clap::ArgMatches<'a> {
clap_app!(
@ -68,7 +68,7 @@ fn do_flags<'a>() -> clap::ArgMatches<'a> {
"How frequently to test command (default 5s)")
)
)
.get_matches()
.get_matches()
}
fn main() {
@ -83,7 +83,7 @@ fn main() {
}
maybe_env = Some(env_vec);
}
let mut process: Option<Box<Process>> = None;
let mut process: Option<Box<dyn Process>> = None;
if let Some(matches) = app.subcommand_matches("watch") {
// Unwrap because this flag is required.
let file = matches.value_of("file").unwrap_or(".");
@ -94,11 +94,15 @@ fn main() {
let poll = matches.value_of("poll").unwrap_or("5s");
let dur = humantime::parse_duration(poll).expect("Invalid poll value.");
process = Some(Box::new(FileProcess::new(
cmd, maybe_env, file, method, dur)));
cmd, maybe_env, file, method, dur,
)));
} else if let Some(matches) = app.subcommand_matches("timer") {
// Unwrap because this flag is required.
let dur = humantime::parse_duration(matches.value_of("duration")
.expect("duration flag is required"));
let dur = humantime::parse_duration(
matches
.value_of("duration")
.expect("duration flag is required"),
);
match dur {
Ok(duration) => {
let max_repeat = if let Some(val) = matches.value_of("repeat") {
@ -114,7 +118,8 @@ fn main() {
None
};
process = Some(Box::new(TimerProcess::new(
cmd, maybe_env, duration, max_repeat)));
cmd, maybe_env, duration, max_repeat,
)));
}
Err(msg) => {
println!("Malformed duration {:?}", msg);
@ -127,7 +132,9 @@ fn main() {
let negate = matches.is_present("not");
let dur = humantime::parse_duration(matches.value_of("poll").unwrap_or("5s"));
process = match dur {
Ok(duration) => Some(Box::new(ExecProcess::new(ifcmd, cmd, negate, maybe_env, duration))),
Ok(duration) => Some(Box::new(ExecProcess::new(
ifcmd, cmd, negate, maybe_env, duration,
))),
Err(msg) => {
println!("Malformed poll {:?}", msg);
process::exit(1)
@ -135,15 +142,13 @@ fn main() {
}
}
match process {
Some(process) => {
match process.run() {
Ok(_) => return,
Err(err) => {
println!("{0}", err);
process::exit(1)
}
Some(process) => match process.run() {
Ok(_) => return,
Err(err) => {
println!("{0}", err);
process::exit(1)
}
}
},
None => {
println!("You must specify a subcommand.");
process::exit(1)