A small, fast, static site generator
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 128 lines 3.4 kB view raw
1use anyhow::Result; 2use copy_dir::copy_dir; 3use std::{ 4 fs::{create_dir_all, remove_dir_all, write}, 5 path::Path, 6}; 7use walkdir::WalkDir; 8 9use crate::{ 10 config::Config, 11 markdown::Page, 12 template::{TemplateContext, TemplateEnvironment}, 13}; 14 15pub struct Builder<'a> { 16 template_env: TemplateEnvironment<'a>, 17 pages: Vec<Page>, 18 config: &'a Config, 19 content_root: &'a Path, 20 static_root: &'a Path, 21 build_root: &'a Path, 22 built: bool, 23} 24 25impl<'a> Builder<'a> { 26 pub fn new(config: &'a Config) -> Self { 27 Self { 28 template_env: TemplateEnvironment::new(), 29 pages: Vec::new(), 30 config, 31 content_root: Path::new(&config.build.content_dir), 32 static_root: Path::new(&config.build.static_dir), 33 build_root: Path::new(&config.build.build_dir), 34 built: false, 35 } 36 } 37 38 pub fn clean(&self) -> Result<()> { 39 // Clean any existing build 40 if self.build_root.is_dir() { 41 remove_dir_all(self.build_root)?; 42 } 43 44 Ok(()) 45 } 46 47 pub fn copy_static(&self) -> Result<()> { 48 // Copy the static content directory 49 if self.static_root.is_dir() { 50 copy_dir( 51 self.static_root, 52 self.build_root.join(&self.config.build.static_dir), 53 )?; 54 println!("Copied static content directory"); 55 } 56 57 Ok(()) 58 } 59 60 pub fn load_pages(&mut self) -> Result<()> { 61 for entry in WalkDir::new(self.content_root) { 62 let entry = entry?; 63 let entry_type = entry.file_type(); 64 let path = entry.path(); 65 let rel_path = path.strip_prefix(self.content_root)?; 66 let dst_path = self.build_root.join(rel_path); 67 68 if entry_type.is_file() { 69 let page = Page::from_file(self.config, self.content_root, &path.to_path_buf())?; 70 self.pages.push(page); 71 } else if entry_type.is_dir() { 72 create_dir_all(dst_path)?; 73 } 74 } 75 76 Ok(()) 77 } 78 79 pub fn generate_pages(&mut self) -> Result<()> { 80 for i in 0..self.pages.len() { 81 let page = &self.pages[i]; 82 83 if !self.config.build.drafts && page.meta.draft { 84 continue; 85 } 86 87 let ctx = TemplateContext::new(&self.pages, page); 88 89 let mut dst_path = self.build_root.join(&page.rel_path); 90 dst_path.set_extension("html"); 91 92 if let Some(tmpl_name) = &page.meta.template { 93 let render_str = self.template_env.render_template(&ctx, tmpl_name)?; 94 write(&dst_path, render_str)?; 95 } else { 96 write(&dst_path, &page.content)?; 97 } 98 99 println!("Generated {}", dst_path.display()); 100 } 101 102 Ok(()) 103 } 104 105 pub fn rebuild(&mut self) -> Result<()> { 106 self.built = false; 107 self.template_env = TemplateEnvironment::new(); 108 self.pages = Vec::new(); 109 110 self.build() 111 } 112 113 pub fn build(&mut self) -> Result<()> { 114 self.clean()?; 115 116 create_dir_all(self.build_root)?; 117 118 self.copy_static()?; 119 120 self.template_env.load_templates(self.config)?; 121 self.load_pages()?; 122 self.generate_pages()?; 123 124 self.built = true; 125 126 Ok(()) 127 } 128}