2023-10-22 17:31:12 -04:00
|
|
|
use std::ffi::OsStr;
|
2023-10-22 16:10:41 -04:00
|
|
|
use std::path::PathBuf;
|
|
|
|
|
2023-10-22 17:31:12 -04:00
|
|
|
use include_dir::include_dir;
|
|
|
|
use include_dir::Dir;
|
|
|
|
|
2023-10-23 20:30:43 -04:00
|
|
|
use crate::blog_post::convert_blog_post_page_to_render_context;
|
2023-10-22 16:10:41 -04:00
|
|
|
use crate::blog_post::BlogPost;
|
|
|
|
use crate::error::CustomError;
|
2023-10-22 16:26:43 -04:00
|
|
|
use crate::render::DusterRenderer;
|
2023-10-22 16:40:58 -04:00
|
|
|
use crate::render::RendererIntegration;
|
2023-10-22 16:10:41 -04:00
|
|
|
|
2023-10-22 17:31:12 -04:00
|
|
|
static MAIN_TEMPLATES: Dir = include_dir!("$CARGO_MANIFEST_DIR/default_environment/templates/html");
|
|
|
|
|
2023-10-22 16:10:41 -04:00
|
|
|
pub(crate) struct SiteRenderer {
|
2023-10-22 17:31:12 -04:00
|
|
|
output_directory: PathBuf,
|
|
|
|
blog_posts: Vec<BlogPost>,
|
2023-10-22 16:10:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl SiteRenderer {
|
2023-10-22 17:31:12 -04:00
|
|
|
pub(crate) fn new<P: Into<PathBuf>>(
|
|
|
|
output_directory: P,
|
|
|
|
blog_posts: Vec<BlogPost>,
|
|
|
|
) -> SiteRenderer {
|
|
|
|
SiteRenderer {
|
|
|
|
output_directory: output_directory.into(),
|
|
|
|
blog_posts,
|
|
|
|
}
|
|
|
|
}
|
2023-10-22 16:10:41 -04:00
|
|
|
pub(crate) async fn render_blog_posts(&self) -> Result<(), CustomError> {
|
2023-10-22 17:31:12 -04:00
|
|
|
let mut renderer_integration = DusterRenderer::new();
|
|
|
|
|
2023-10-22 18:39:05 -04:00
|
|
|
let sources: Vec<_> = MAIN_TEMPLATES
|
2023-10-22 17:31:12 -04:00
|
|
|
.files()
|
|
|
|
.filter(|f| f.path().extension() == Some(OsStr::new("dust")))
|
2023-10-22 18:39:05 -04:00
|
|
|
.collect();
|
|
|
|
if sources
|
|
|
|
.iter()
|
|
|
|
.filter(|f| f.path().file_stem() == Some(OsStr::new("main")))
|
|
|
|
.count()
|
|
|
|
!= 1
|
|
|
|
{
|
2023-10-22 17:31:12 -04:00
|
|
|
return Err("Expect exactly 1 main.dust template file.".into());
|
|
|
|
}
|
|
|
|
|
2023-10-22 17:43:30 -04:00
|
|
|
let decoded_templates = {
|
2023-10-22 18:39:05 -04:00
|
|
|
let mut decoded_templates = Vec::with_capacity(sources.len());
|
|
|
|
for entry in sources {
|
2023-10-22 17:43:30 -04:00
|
|
|
decoded_templates.push(build_name_contents_pairs(entry)?);
|
|
|
|
}
|
|
|
|
decoded_templates
|
|
|
|
};
|
2023-10-22 17:31:12 -04:00
|
|
|
|
2023-10-22 17:43:30 -04:00
|
|
|
for (name, contents) in decoded_templates {
|
|
|
|
renderer_integration.load_template(name, contents)?;
|
2023-10-22 17:31:12 -04:00
|
|
|
}
|
|
|
|
|
2023-10-22 16:10:41 -04:00
|
|
|
for blog_post in &self.blog_posts {
|
2023-10-23 20:30:43 -04:00
|
|
|
for blog_post_page in &blog_post.pages {
|
|
|
|
let output_path = self
|
|
|
|
.output_directory
|
|
|
|
.join("posts")
|
|
|
|
.join(&blog_post.id)
|
|
|
|
.join(blog_post_page.get_output_path());
|
|
|
|
println!("Output path: {:?}", output_path);
|
|
|
|
let render_context =
|
|
|
|
convert_blog_post_page_to_render_context(blog_post, blog_post_page);
|
|
|
|
let rendered_output = renderer_integration.render(render_context)?;
|
|
|
|
println!("Rendered: {}", rendered_output);
|
|
|
|
let parent_directory = output_path
|
|
|
|
.parent()
|
|
|
|
.ok_or("Output file should have a containing directory.")?;
|
|
|
|
tokio::fs::create_dir_all(parent_directory).await?;
|
|
|
|
tokio::fs::write(output_path, rendered_output).await?;
|
|
|
|
}
|
2023-10-22 16:10:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2023-10-22 17:31:12 -04:00
|
|
|
|
2023-10-22 17:43:30 -04:00
|
|
|
fn build_name_contents_pairs<'a>(
|
|
|
|
entry: &'a include_dir::File<'_>,
|
|
|
|
) -> Result<(&'a str, &'a str), CustomError> {
|
2023-10-22 17:31:12 -04:00
|
|
|
let path = entry.path();
|
|
|
|
let name = path
|
|
|
|
.file_stem()
|
|
|
|
.ok_or("All templates should have a stem.")?
|
|
|
|
.to_str()
|
|
|
|
.ok_or("All template filenames should be valid utf-8.")?;
|
|
|
|
let contents = std::str::from_utf8(entry.contents())?;
|
2023-10-22 17:43:30 -04:00
|
|
|
Ok((name, contents))
|
2023-10-22 17:31:12 -04:00
|
|
|
}
|