use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::time::SystemTime;
use crate::builder::{load_templates, Builder};
use crate::error::DocError;
use crate::walk;
pub struct Watcher<'b> {
builder: &'b Builder,
md_mtimes: HashMap<PathBuf, SystemTime>,
template_mtimes: HashMap<PathBuf, SystemTime>,
}
impl<'b> Watcher<'b> {
pub(crate) fn new(builder: &'b Builder) -> Result<Self, DocError> {
builder.build()?;
Ok(Self {
builder,
md_mtimes: snapshot_mtimes(builder.input_dir(), "md")?,
template_mtimes: snapshot_mtimes(builder.templates_dir(), "html")?,
})
}
pub fn tick(&mut self) -> Result<Vec<PathBuf>, DocError> {
let current_templates = snapshot_mtimes(self.builder.templates_dir(), "html")?;
let templates_changed = current_templates != self.template_mtimes;
self.template_mtimes = current_templates;
let current_md = snapshot_mtimes(self.builder.input_dir(), "md")?;
let md_set_changed = current_md != self.md_mtimes;
let changed: Vec<PathBuf> = if templates_changed {
current_md.keys().cloned().collect()
} else {
current_md
.iter()
.filter(|(path, mtime)| self.md_mtimes.get(path.as_path()) != Some(*mtime))
.map(|(path, _)| path.clone())
.collect()
};
if !changed.is_empty() {
let tera = load_templates(self.builder.templates_dir())?;
for md_path in &changed {
self.builder.build_one(&tera, md_path)?;
}
}
if md_set_changed {
self.builder.rebuild_data_json()?;
}
self.md_mtimes = current_md;
Ok(changed)
}
}
fn snapshot_mtimes(dir: &Path, extension: &str) -> Result<HashMap<PathBuf, SystemTime>, DocError> {
let mut mtimes = HashMap::new();
for path in walk::walk_files_with_extension(dir, extension)? {
let mtime = std::fs::metadata(&path)?.modified()?;
mtimes.insert(path, mtime);
}
Ok(mtimes)
}