Run Rust Code When File Change With watchexec
This is more for running external commands than running internal code. Took me a while to figure that out. I'm looking at the notify crate now for watching the system and running code that way.
https : //docs.rs/notify/latest/notify/index.html
I wasn't able to use CTRL+c to stop a running app until I added the Signal : : Interrupt check. I had to use [TODO: Code shorthand span ] to find the pocess ID and then use [TODO: Code shorthand span ] to stop it. Turned out to not be a big deal but I would have preferred to know that going in
New Vervion
TODO : clean up and put this version in place for this post
TODO : Look at the neo process for a solution to only running one process at a time (assuming you solve for that)
// use eyre::Error;
// use anyhow::Error;
// use anyhow::Result;
use ;
// use std::path::PathBuf;
use Error;
use Command;
use ;
use Signal;
use Duration;
Don't delte this until you've updated the post
-- id: 2p7c45vj
// NOTE: This is a temporary process. Eventually
// it'll be rolled into the main script....
// use tokio::process::Command;
// #[derive(Debug)]
// enum PointOfInterest {
// Include(&str, Vec<&str>)
// }
async
// use core::fmt::Error;
// use miette::Result;
// use std::path::PathBuf;
// use std::time::Duration;
// use watchexec::action::Action;
// use watchexec::action::Outcome;
// use watchexec::config::InitConfig;
// use watchexec::config::RuntimeConfig;
// use watchexec::Watchexec;
// use watchexec_signals::Signal;
//struct Widget {}
// impl Widget {
// pub fn update(&mut self, path: PathBuf) {
// dbg!(path);
// }
// }
// #[tokio::main]
// async fn main() -> Result<()> {
// println!("Starting process");
// let mut widget = Widget {};
// let init = InitConfig::default();
// let mut runtime = RuntimeConfig::default();
// runtime.pathset([
// "/Users/alan/workshop/alanwsmith.com/templates",
// "/Users/alan/Grimoire",
// "/Users/alan/workshop/neopolengine/target/release",
// ]);
// runtime.action_throttle(Duration::new(0, 3000000000));
// runtime.on_action(move |action: Action| {
// let mut stop: bool = false;
// // let mut paths: Vec<PathBuf> = vec![];
// action.events.iter().for_each(|event| {
// event.signals().for_each(|sig| match sig {
// Signal::Interrupt => {
// println!("Caught Interrupt: Stopping");
// stop = true;
// }
// _ => {}
// });
// event
// .paths()
// // .for_each(|path| paths.push(path.0.to_path_buf()));
// });
// if stop {
// action.outcome(Outcome::Exit);
// }
// // paths.dedup();
// // paths
// // .iter()
// // .filter(|p| is_visible(p.to_path_buf()))
// // .for_each(|path| {
// // widget.update(path.to_path_buf());
// // });
// async move { Ok::<(), Error>(()) }
// });
// let we = Watchexec::new(init, runtime)?;
// we.main().await.unwrap().unwrap();
// Ok(())
// }
// fn is_visible(entry: PathBuf) -> bool {
// entry
// .file_name()
// .unwrap()
// .to_str()
// .map(|s| !s.starts_with(".") && !s.ends_with("~"))
// .unwrap_or(false)
// }
Original Notes
TODO : Remove this prior version of the code when the new version is polished
This is what I'm doing to automatically run my site built process when content files change.
use Error;
use Result;
use PathBuf;
use Duration;
use Action;
use Outcome;
use InitConfig;
use RuntimeConfig;
use Watchexec;
use Signal;
async
Dependencies
cargo add watchexec miette tokio watchexec_signals
- The ` .action _ throttle() [TODO: Code shorthand span ] value of 100000000 is nanoseconds and translates to 0.1 seconds for debouncing. I thought the method was broken at first becuase I was using a value based on milliseconds which made it seem like there was no delay at all.
- I've got a dedupe in place to try to work alongside the debounce throttle, but it's not working yet
- The ` .action _ throttle() [TODO: Code shorthand span ] is there in an effort to debounce but it's not doing what I want. Needs more investigation.
- There are often several file events that fire for one file change. I'm pushing all the paths for any batch into a vec then deduping it as a partial measure to debounce
- You can use CTRL c to stop the process
- Using the struct that's outside of the ` .on _ action() [TODO: Code shorthand span ] requires keeping it outside of the ` async [TODO: Code shorthand span ] call. It took a while to figure that part out. It seems like there should be a way to get it in there, but this is fine for my purpose because the build files should probably go synchronously anyway.
-
[]
Link over to the other piece that points to just catching Control - C.
-
[]
Refine this post as an alternative and then cross link it with this one : 2p1t9jxc5gmb
References
-
The Rust crate that powers all this and things like cargo watch too