2021-12-30 19:17:42 +00:00
|
|
|
use super::config;
|
2021-12-30 18:18:52 +00:00
|
|
|
use super::config::PathConfig;
|
2021-12-30 19:17:42 +00:00
|
|
|
use super::path;
|
|
|
|
use super::path::{NormalPathBuf, Normalize};
|
|
|
|
use notify::{RecommendedWatcher, Watcher};
|
2021-12-30 18:18:52 +00:00
|
|
|
use std::collections::HashSet;
|
2021-12-30 19:17:42 +00:00
|
|
|
use std::path::PathBuf;
|
2021-12-30 13:37:53 +00:00
|
|
|
use std::sync::mpsc::channel;
|
|
|
|
use std::time::Duration;
|
|
|
|
|
2021-12-30 18:18:52 +00:00
|
|
|
// TODO(jrpotter): Add logging.
|
|
|
|
// TODO(jrpotter): Add pid file to only allow one daemon at a time.
|
2021-12-30 13:37:53 +00:00
|
|
|
|
2021-12-30 19:17:42 +00:00
|
|
|
// ========================================
|
|
|
|
// State
|
|
|
|
// ========================================
|
|
|
|
|
|
|
|
struct WatchState {
|
|
|
|
// Paths that we were not able to watch properly but could potentially do so
|
|
|
|
// in the future. These include paths that did not exist at the time of
|
|
|
|
// canonicalization or did not have environment variables defined that may
|
|
|
|
// be defined later on.
|
|
|
|
pending: HashSet<PathBuf>,
|
|
|
|
// Paths that we are currently watching.
|
|
|
|
watching: HashSet<NormalPathBuf>,
|
|
|
|
// Paths that are not valid and will never become valid. These may include
|
|
|
|
// paths that include prefixes or refer to directories that could never be
|
|
|
|
// reached (e.g. parent of root).
|
|
|
|
invalid: HashSet<PathBuf>,
|
2021-12-30 18:18:52 +00:00
|
|
|
}
|
2021-12-30 13:37:53 +00:00
|
|
|
|
2021-12-30 19:17:42 +00:00
|
|
|
impl WatchState {
|
|
|
|
pub fn new(config: &PathConfig) -> notify::Result<Self> {
|
|
|
|
let mut pending: HashSet<PathBuf> = HashSet::new();
|
|
|
|
let mut watching: HashSet<NormalPathBuf> = HashSet::new();
|
|
|
|
watching.insert(config.0.clone());
|
|
|
|
// We try and resolve our configuration again here. We want to
|
|
|
|
// specifically track any new configs that may pop up with higher
|
|
|
|
// priority.
|
|
|
|
for path in config::default_paths() {
|
|
|
|
match path::normalize(&path)? {
|
|
|
|
// TODO(jrpotter): Check if the path can be canonicalized.
|
|
|
|
Normalize::Done(p) => watching.insert(p),
|
|
|
|
Normalize::Pending => pending.insert(path),
|
|
|
|
};
|
2021-12-30 18:18:52 +00:00
|
|
|
}
|
2021-12-30 19:17:42 +00:00
|
|
|
Ok(WatchState {
|
|
|
|
pending,
|
|
|
|
watching,
|
|
|
|
invalid: HashSet::new(),
|
|
|
|
})
|
2021-12-30 18:18:52 +00:00
|
|
|
}
|
|
|
|
}
|
2021-12-30 13:37:53 +00:00
|
|
|
|
2021-12-30 19:17:42 +00:00
|
|
|
// ========================================
|
|
|
|
// Daemon
|
|
|
|
// ========================================
|
|
|
|
|
|
|
|
fn reload_config(config: &PathConfig) -> notify::Result<WatchState> {
|
|
|
|
let state = WatchState::new(config)?;
|
|
|
|
Ok(state)
|
|
|
|
}
|
|
|
|
|
2021-12-30 18:18:52 +00:00
|
|
|
pub fn launch(config: PathConfig) -> notify::Result<()> {
|
|
|
|
let (tx, rx) = channel();
|
|
|
|
// Create a "debounced" watcher. Events will not trigger until after the
|
|
|
|
// specified duration has passed with no additional changes.
|
|
|
|
let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?;
|
2021-12-30 19:17:42 +00:00
|
|
|
// for (_, package) in &config.1.packages {
|
|
|
|
// for path in &package.configs {
|
|
|
|
// match normalize_path(&path) {
|
|
|
|
// // `notify-rs` is not able to handle files that do not exist and
|
|
|
|
// // are then created. This is handled internally by the library
|
|
|
|
// // via the `fs::canonicalize` which fails on missing paths. So
|
|
|
|
// // track which paths end up missing and apply polling on them.
|
|
|
|
// Ok(normalized) => match watcher.watch(&normalized, RecursiveMode::NonRecursive) {
|
|
|
|
// Ok(_) => {
|
|
|
|
// tracked_paths.insert(normalized);
|
|
|
|
// }
|
|
|
|
// Err(notify::Error::PathNotFound) => {
|
|
|
|
// missing_paths.insert(normalized);
|
|
|
|
// }
|
|
|
|
// Err(e) => return Err(e),
|
|
|
|
// },
|
|
|
|
// // TODO(jrpotter): Retry even in cases where environment
|
|
|
|
// // variables are not defined.
|
|
|
|
// Err(e) => eprintln!("{}", e),
|
|
|
|
// };
|
|
|
|
// }
|
|
|
|
// }
|
2021-12-30 13:37:53 +00:00
|
|
|
// This is a simple loop, but you may want to use more complex logic here,
|
|
|
|
// for example to handle I/O.
|
|
|
|
loop {
|
|
|
|
match rx.recv() {
|
|
|
|
Ok(event) => println!("{:?}", event),
|
|
|
|
Err(e) => println!("watch error: {:?}", e),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|