git-next/crates/cli/src/file_watcher.rs
Paul Campbell 3c01a822fd
All checks were successful
Rust / build (push) Successful in 10m8s
ci/woodpecker/push/push-next Pipeline was successful
ci/woodpecker/push/cron-docker-builder Pipeline was successful
ci/woodpecker/push/tag-created Pipeline was successful
Release Please / Release-plz (push) Successful in 1m8s
feat: improved error display when startup fails
2024-09-01 13:10:14 +01:00

66 lines
2 KiB
Rust

//
use actix::prelude::*;
use actix::Recipient;
use anyhow::{Context, Result};
use notify::{event::ModifyKind, Watcher};
use tracing::{error, info};
use std::{
path::PathBuf,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
time::Duration,
};
#[derive(Debug, Message)]
#[rtype(result = "()")]
pub struct FileUpdated;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("io")]
Io(#[from] std::io::Error),
}
pub fn watch_file(path: PathBuf, recipient: Recipient<FileUpdated>) -> Result<Arc<AtomicBool>> {
let (tx, rx) = std::sync::mpsc::channel();
let shutdown = Arc::new(AtomicBool::default());
let mut handler = notify::recommended_watcher(tx).context("file watcher")?;
handler
.watch(&path, notify::RecursiveMode::NonRecursive)
.with_context(|| format!("Watching: {path:?}"))?;
let thread_shutdown = shutdown.clone();
actix_rt::task::spawn_blocking(move || {
loop {
if thread_shutdown.load(Ordering::Relaxed) {
drop(handler);
break;
}
for result in rx.try_iter() {
match result {
Ok(event) => match event.kind {
notify::EventKind::Modify(ModifyKind::Data(_)) => {
info!("File modified");
recipient.do_send(FileUpdated);
break;
}
notify::EventKind::Modify(_)
| notify::EventKind::Create(_)
| notify::EventKind::Remove(_)
| notify::EventKind::Any
| notify::EventKind::Access(_)
| notify::EventKind::Other => { /* do nothing */ }
},
Err(err) => {
error!(?err, "Watching file: {path:?}");
}
}
}
std::thread::sleep(Duration::from_millis(1000));
}
});
Ok(shutdown)
}