diff --git a/default_environment/templates/html/main.dust b/default_environment/templates/html/main.dust
new file mode 100644
index 0000000..2d07f56
--- /dev/null
+++ b/default_environment/templates/html/main.dust
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+ Hello world!
+
+
diff --git a/src/command/build/render.rs b/src/command/build/render.rs
index 5b4ce4c..cb2224d 100644
--- a/src/command/build/render.rs
+++ b/src/command/build/render.rs
@@ -1,19 +1,51 @@
+use std::ffi::OsStr;
use std::path::PathBuf;
+use include_dir::include_dir;
+use include_dir::Dir;
+
use crate::blog_post::convert_blog_post_to_render_context;
use crate::blog_post::BlogPost;
use crate::error::CustomError;
use crate::render::DusterRenderer;
use crate::render::RendererIntegration;
+static MAIN_TEMPLATES: Dir = include_dir!("$CARGO_MANIFEST_DIR/default_environment/templates/html");
+
pub(crate) struct SiteRenderer {
- pub(crate) output_directory: PathBuf,
- pub(crate) blog_posts: Vec,
+ output_directory: PathBuf,
+ blog_posts: Vec,
}
impl SiteRenderer {
+ pub(crate) fn new>(
+ output_directory: P,
+ blog_posts: Vec,
+ ) -> SiteRenderer {
+ SiteRenderer {
+ output_directory: output_directory.into(),
+ blog_posts,
+ }
+ }
pub(crate) async fn render_blog_posts(&self) -> Result<(), CustomError> {
- let mut renderer_integration = DusterRenderer {};
+ let mut renderer_integration = DusterRenderer::new();
+
+ let (main_template, other_templates): (Vec<_>, Vec<_>) = MAIN_TEMPLATES
+ .files()
+ .filter(|f| f.path().extension() == Some(OsStr::new("dust")))
+ .partition(|f| f.path().file_stem() == Some(OsStr::new("main")));
+ if main_template.len() != 1 {
+ return Err("Expect exactly 1 main.dust template file.".into());
+ }
+
+ for entry in main_template {
+ load_template_from_include_dir(&mut renderer_integration, entry)?;
+ }
+
+ for entry in other_templates {
+ load_template_from_include_dir(&mut renderer_integration, entry)?;
+ }
+
for blog_post in &self.blog_posts {
let render_context = convert_blog_post_to_render_context(blog_post);
renderer_integration.render(render_context)?;
@@ -22,3 +54,18 @@ impl SiteRenderer {
Ok(())
}
}
+
+fn load_template_from_include_dir(
+ renderer_integration: &mut RI,
+ entry: &include_dir::File<'_>,
+) -> Result<(), CustomError> {
+ 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())?;
+ renderer_integration.load_template(name, contents)?;
+ Ok(())
+}
diff --git a/src/command/build/runner.rs b/src/command/build/runner.rs
index 8b859e5..7f970bd 100644
--- a/src/command/build/runner.rs
+++ b/src/command/build/runner.rs
@@ -9,10 +9,7 @@ use crate::error::CustomError;
pub(crate) async fn build_site(args: BuildArgs) -> Result<(), CustomError> {
let config = Config::load_from_file(args.config).await?;
let blog_posts = load_blog_posts(&config).await?;
- let renderer = SiteRenderer {
- output_directory: get_output_directory(&config).await?,
- blog_posts,
- };
+ let renderer = SiteRenderer::new(get_output_directory(&config).await?, blog_posts);
renderer.render_blog_posts().await?;
Ok(())
diff --git a/src/error/error.rs b/src/error/error.rs
index 78f109f..5daa7d6 100644
--- a/src/error/error.rs
+++ b/src/error/error.rs
@@ -1,3 +1,6 @@
+use std::str::Utf8Error;
+use std::string::FromUtf8Error;
+
#[derive(Debug)]
pub(crate) enum CustomError {
Static(&'static str),
@@ -7,6 +10,8 @@ pub(crate) enum CustomError {
WalkDir(walkdir::Error),
Tokio(tokio::task::JoinError),
Serde(serde_json::Error),
+ Utf8(Utf8Error),
+ FromUtf8(FromUtf8Error),
}
impl From for CustomError {
@@ -50,3 +55,15 @@ impl From for CustomError {
CustomError::Serde(value)
}
}
+
+impl From for CustomError {
+ fn from(value: Utf8Error) -> Self {
+ CustomError::Utf8(value)
+ }
+}
+
+impl From for CustomError {
+ fn from(value: FromUtf8Error) -> Self {
+ CustomError::FromUtf8(value)
+ }
+}
diff --git a/src/render/duster_renderer.rs b/src/render/duster_renderer.rs
index 435aab0..ec19b6a 100644
--- a/src/render/duster_renderer.rs
+++ b/src/render/duster_renderer.rs
@@ -4,13 +4,18 @@ use serde::Serialize;
pub(crate) struct DusterRenderer {}
+impl DusterRenderer {
+ pub(crate) fn new() -> DusterRenderer {
+ DusterRenderer {}
+ }
+}
+
impl RendererIntegration for DusterRenderer {
- fn load_templates(&mut self, dust_templates: I) -> Result<(), crate::error::CustomError>
+ fn load_template(&mut self, name: N, contents: C) -> Result<(), crate::error::CustomError>
where
- I: Iterator- ,
- P: Into,
+ N: Into,
+ C: Into,
{
- // TODO
Ok(())
}
diff --git a/src/render/renderer_integration.rs b/src/render/renderer_integration.rs
index 4fbbba1..3087739 100644
--- a/src/render/renderer_integration.rs
+++ b/src/render/renderer_integration.rs
@@ -1,14 +1,12 @@
-use std::path::PathBuf;
-
use serde::Serialize;
use crate::error::CustomError;
pub(crate) trait RendererIntegration {
- fn load_templates(&mut self, dust_templates: I) -> Result<(), CustomError>
+ fn load_template(&mut self, name: N, contents: C) -> Result<(), CustomError>
where
- I: Iterator
- ,
- P: Into;
+ N: Into,
+ C: Into;
fn render(&self, context: C) -> Result
where