From f5c7c14d2e122ab0dd6e396e640b6df85eb86d00 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sat, 11 Jan 2025 17:22:25 -0500 Subject: [PATCH] Copy static files --- src/generator/mod.rs | 12 +++- src/generator/static_files.rs | 120 ++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/generator/static_files.rs diff --git a/src/generator/mod.rs b/src/generator/mod.rs index 0371894..6f982ad 100644 --- a/src/generator/mod.rs +++ b/src/generator/mod.rs @@ -3,6 +3,7 @@ mod css; mod home; mod markdown; mod posts; +mod static_files; mod tags; mod templates; mod util; @@ -57,7 +58,16 @@ fn make_graph(watcher: Rc>) -> anyhow::Result, + watcher: Rc>, +) -> Input<()> { + let (read_statics, invalidate) = + builder.add_invalidatable_dynamic_rule(ReadStatics::new(Rc::clone(&watcher))); + watcher + .borrow_mut() + .watch(content_path("static"), move || invalidate.invalidate()); + builder.add_rule(MapDynamicToVoid(read_statics)) +} + +#[derive(InputVisitable)] +struct ReadStatics { + #[skip_visit] + watcher: Rc>, + factory: DynamicNodeFactory, +} +impl ReadStatics { + fn new(watcher: Rc>) -> Self { + Self { + watcher, + factory: DynamicNodeFactory::new(), + } + } +} +impl DynamicRule for ReadStatics { + type ChildOutput = (); + fn evaluate(&mut self, ctx: &mut impl DynamicRuleContext) -> Vec> { + let files = read_files_recursive(content_path("static")).expect("reading static directory"); + for ent in files { + if let Ok(ent) = ent { + assert!(ent.file_type().unwrap().is_file()); + self.factory.add_node(ctx, ent.path(), |ctx| { + let (node, invalidate) = + ctx.add_invalidatable_rule(CopyStatic { path: ent.path() }); + self.watcher + .borrow_mut() + .watch(ent.path(), move || invalidate.invalidate()); + node + }); + } + } + self.factory.all_nodes(ctx) + } +} + +#[derive(InputVisitable)] +struct CopyStatic { + #[skip_visit] + path: PathBuf, +} +impl Rule for CopyStatic { + type Output = (); + fn evaluate(&mut self) -> Self::Output { + let relative_path = self + .path + .strip_prefix(content_path("static")) + .expect("CopyStatic path should be relative to static directory"); + let output_path = output_path(relative_path); + std::fs::copy(&self.path, output_path).expect("copying static"); + } +} + +#[derive(Debug)] +struct ReadFilesRecursive { + read_dir: ReadDir, + recurse: Option>, +} + +impl Iterator for ReadFilesRecursive { + type Item = ::Item; + fn next(&mut self) -> Option { + if let Some(ref mut recursive) = self.recurse { + match recursive.next() { + Some(item) => Some(item), + None => { + self.recurse = None; + self.next() + } + } + } else { + match self.read_dir.next() { + Some(Ok(ent)) => { + if let Ok(ft) = ent.file_type() + && ft.is_dir() + && let Ok(recurse) = read_files_recursive(ent.path()) + { + self.recurse = Some(Box::new(recurse)); + self.next() + } else { + Some(Ok(ent)) + } + } + result => result, + } + } + } +} + +fn read_files_recursive(path: PathBuf) -> std::io::Result { + std::fs::read_dir(path).map(|read_dir| ReadFilesRecursive { + read_dir, + recurse: None, + }) +}