treehouse/src/generate.rs

118 lines
3.6 KiB
Rust
Raw Normal View History

2024-11-27 19:02:30 +01:00
mod atom;
mod dir_helper;
mod include_static_helper;
mod simple_template;
mod tree;
use std::{ops::ControlFlow, sync::Arc};
2024-11-27 19:02:30 +01:00
use atom::FeedDir;
use dir_helper::DirHelper;
2024-07-19 18:04:11 +02:00
use handlebars::{handlebars_helper, Handlebars};
use include_static_helper::IncludeStaticHelper;
2023-08-18 21:19:31 +02:00
use serde::Serialize;
2024-11-26 22:00:02 +01:00
use tracing::{error, info_span, instrument};
2023-08-18 21:19:31 +02:00
2023-08-22 22:19:43 +02:00
use crate::{
config::Config,
dirs::Dirs,
2024-03-08 22:40:19 +01:00
fun::seasons::Season,
generate::{
simple_template::SimpleTemplateDir,
tree::{DirIndex, TreehouseDir},
},
sources::Sources,
vfs::{
self, layered_dir, AnchoredAtExt, Cd, Content, ContentCache, Dir, DynDir, Entries,
HtmlCanonicalize, MemDir, Overlay, ToDynDir, VPath, VPathBuf,
},
2023-08-22 22:19:43 +02:00
};
2024-02-21 23:17:19 +01:00
#[derive(Serialize)]
struct BaseTemplateData<'a> {
2024-02-21 23:17:19 +01:00
config: &'a Config,
import_map: String,
2024-03-08 22:40:19 +01:00
season: Option<Season>,
2024-11-23 19:12:00 +01:00
dev: bool,
2024-11-27 19:02:30 +01:00
feeds: Vec<String>,
2024-02-21 23:17:19 +01:00
}
impl<'a> BaseTemplateData<'a> {
fn new(sources: &'a Sources) -> Self {
Self {
config: &sources.config,
import_map: serde_json::to_string_pretty(&sources.import_map)
.expect("import map should be serializable to JSON"),
season: Season::current(),
dev: cfg!(debug_assertions),
2024-11-27 19:02:30 +01:00
feeds: sources.treehouse.feeds_by_name.keys().cloned().collect(),
}
}
}
fn create_handlebars(site: &str, static_: DynDir) -> Handlebars<'static> {
let mut handlebars = Handlebars::new();
handlebars_helper!(cat: |a: String, b: String| a + &b);
2023-08-18 21:19:31 +02:00
handlebars.register_helper("cat", Box::new(cat));
handlebars.register_helper("asset", Box::new(DirHelper::new(site, static_.clone())));
handlebars.register_helper(
"include_static",
Box::new(IncludeStaticHelper::new(static_)),
);
handlebars
}
#[instrument(skip(handlebars))]
fn load_templates(handlebars: &mut Handlebars, dir: &dyn Dir) {
vfs::walk_dir_rec(dir, VPath::ROOT, &mut |path| {
if path.extension() == Some("hbs") {
if let Some(content) = vfs::query::<Content>(dir, path).and_then(|c| c.string().ok()) {
let _span = info_span!("register_template", ?path).entered();
if let Err(err) = handlebars.register_template_string(path.as_str(), content) {
error!("in template: {err}");
}
}
2023-08-18 21:19:31 +02:00
}
ControlFlow::Continue(())
});
}
pub fn target(dirs: Arc<Dirs>, sources: Arc<Sources>) -> DynDir {
2024-11-27 19:02:30 +01:00
let mut handlebars = create_handlebars(&sources.config.site, dirs.static_.clone());
load_templates(&mut handlebars, &dirs.template);
let handlebars = Arc::new(handlebars);
let mut root = MemDir::new();
2024-11-27 19:02:30 +01:00
root.add(
VPath::new("feed"),
ContentCache::new(FeedDir::new(
dirs.clone(),
sources.clone(),
handlebars.clone(),
))
.to_dyn(),
);
root.add(VPath::new("static"), dirs.static_.clone());
root.add(
VPath::new("robots.txt"),
Cd::new(dirs.static_.clone(), VPathBuf::new("robots.txt")).to_dyn(),
);
let dir_index = DirIndex::new(sources.treehouse.files_by_tree_path.keys().map(|x| &**x));
let treehouse_dir = layered_dir(&[
TreehouseDir::new(dirs, sources.clone(), handlebars.clone(), dir_index).to_dyn(),
SimpleTemplateDir::new(sources.clone(), handlebars.clone()).to_dyn(),
]);
2024-11-23 21:42:25 +01:00
let tree_view = ContentCache::new(treehouse_dir);
2024-11-23 21:42:25 +01:00
tree_view.warm_up();
let tree_view = HtmlCanonicalize::new(tree_view);
layered_dir(&[tree_view.to_dyn(), root.to_dyn()])
.anchored_at(VPath::ROOT.to_owned())
.to_dyn()
2023-08-18 21:19:31 +02:00
}