You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

88 lines
2.8KB

  1. use std::collections::HashMap;
  2. use std::fs::{create_dir, remove_dir_all};
  3. use std::path::Path;
  4. use glob::glob;
  5. use tera::{Tera, Context};
  6. use config:: Config;
  7. use errors::{Result, ResultExt};
  8. use page::{Page, order_pages};
  9. use utils::create_file;
  10. pub fn build(config: Config) -> Result<()> {
  11. if Path::new("public").exists() {
  12. // Delete current `public` directory so we can start fresh
  13. remove_dir_all("public").chain_err(|| "Couldn't delete `public` directory")?;
  14. }
  15. let tera = Tera::new("templates/**/*").chain_err(|| "Error parsing templates")?;
  16. // ok we got all the pages HTML, time to write them down to disk
  17. create_dir("public")?;
  18. let public = Path::new("public");
  19. let mut pages: Vec<Page> = vec![];
  20. let mut sections: HashMap<String, Vec<Page>> = HashMap::new();
  21. // First step: do all the articles and group article by sections
  22. // hardcoded pattern so can't error
  23. for entry in glob("content/**/*.md").unwrap().filter_map(|e| e.ok()) {
  24. let path = entry.as_path();
  25. let mut page = Page::from_file(&path)?;
  26. let mut current_path = public.to_path_buf();
  27. for section in &page.sections {
  28. current_path.push(section);
  29. if !current_path.exists() {
  30. create_dir(&current_path)?;
  31. }
  32. let str_path = current_path.as_path().to_string_lossy().to_string();
  33. sections.entry(str_path).or_insert_with(|| vec![page.clone()]);
  34. }
  35. if let Some(ref url) = page.meta.url {
  36. println!("URL: {:?}", url);
  37. current_path.push(url);
  38. } else {
  39. println!("REMOVE ME IF YOU DONT SEE ME");
  40. current_path.push(&page.get_slug());
  41. }
  42. create_dir(&current_path)?;
  43. create_file(current_path.join("index.html"), &page.render_html(&tera, &config)?)?;
  44. pages.push(page);
  45. }
  46. for (section, pages) in sections {
  47. render_section_index(section, pages, &tera, &config)?;
  48. }
  49. // and now the index page
  50. let mut context = Context::new();
  51. context.add("pages", &order_pages(pages));
  52. context.add("config", &config);
  53. create_file(public.join("index.html"), &tera.render("index.html", &context)?)?;
  54. Ok(())
  55. }
  56. fn render_section_index(section: String, pages: Vec<Page>, tera: &Tera, config: &Config) -> Result<()> {
  57. let path = Path::new(&section);
  58. let mut context = Context::new();
  59. context.add("pages", &order_pages(pages));
  60. context.add("config", &config);
  61. let section_name = match path.components().into_iter().last() {
  62. Some(s) => s.as_ref().to_string_lossy().to_string(),
  63. None => bail!("Couldn't find a section name in {:?}", path.display())
  64. };
  65. create_file(path.join("index.html"), &tera.render(&format!("{}.html", section_name), &context)?)
  66. }