Working generator & added whole site
This commit is contained in:
123
src/generator/generate.rs
Normal file
123
src/generator/generate.rs
Normal file
@@ -0,0 +1,123 @@
|
||||
use std::fs::{ File, create_dir_all };
|
||||
use std::path::Path;
|
||||
|
||||
use handlebars::Handlebars;
|
||||
use serde::Serialize;
|
||||
|
||||
use super::loader;
|
||||
use super::models::post::Post;
|
||||
use super::models::section::Section;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct TemplateData<'a> {
|
||||
section: &'a Section,
|
||||
post: Option<&'a Post>,
|
||||
}
|
||||
|
||||
pub fn landing_page() {
|
||||
let mut handlebars = Handlebars::new();
|
||||
|
||||
match handlebars.register_template_file("landing", "./templates/landing.hbs") {
|
||||
Err(error) => panic!("Could not load landing template: {}", error),
|
||||
Ok(_) => (),
|
||||
};
|
||||
|
||||
match handlebars.register_template_file("header", "./templates/header.hbs") {
|
||||
Err(error) => panic!("Could not load header template: {}", error),
|
||||
Ok(_) => (),
|
||||
};
|
||||
|
||||
let data = "";
|
||||
let mut output_file = match File::create("./generated/index.html") {
|
||||
Err(error) => panic!("Could not create landing index: {}", error),
|
||||
Ok(file) => file,
|
||||
};
|
||||
|
||||
match handlebars.render_to_write("landing", &data, &mut output_file) {
|
||||
Err(error) => panic!("Error rendering landing: {}", error),
|
||||
Ok(_) => (),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn sections() {
|
||||
let sections = loader::sections();
|
||||
let mut handlebars = Handlebars::new();
|
||||
|
||||
load_templates(&mut handlebars);
|
||||
|
||||
for section in §ions {
|
||||
let section_path = Path::new("./generated").join(section.url.to_owned());
|
||||
match create_dir_all(section_path) {
|
||||
Ok(_) => println!("[GEN] {} -> Created folder at url {}", section.title, section.url),
|
||||
Err(error) => panic!("Error creating section folder: {}", error),
|
||||
};
|
||||
|
||||
// Generate posts
|
||||
for post in §ion.posts {
|
||||
let data = TemplateData {
|
||||
post: Some(post),
|
||||
section: section,
|
||||
};
|
||||
|
||||
let post_path = Path::new("./generated").join(section.url.to_owned()).join(post.url.to_owned());
|
||||
let mut output_file = match File::create(post_path) {
|
||||
Err(error) => panic!("Could not create post: {}", error),
|
||||
Ok(file) => file,
|
||||
};
|
||||
|
||||
match handlebars.render_to_write("base", &data, &mut output_file) {
|
||||
Err(error) => panic!("Error rendering post: {}", error),
|
||||
Ok(_) => println!("[GEN] {} -> Rendered post {}", section.title, post.title),
|
||||
};
|
||||
}
|
||||
|
||||
// Generate section index
|
||||
|
||||
let data = TemplateData {
|
||||
post: None,
|
||||
section: section,
|
||||
};
|
||||
let index_path = Path::new("./generated").join(section.url.to_owned()).join("index.html");
|
||||
let mut output_file = match File::create(index_path) {
|
||||
Err(error) => panic!("Could not create section index: {}", error),
|
||||
Ok(file) => file,
|
||||
};
|
||||
|
||||
match handlebars.render_to_write("base_section", &data, &mut output_file) {
|
||||
Err(error) => panic!("Error rendering post: {}", error),
|
||||
Ok(_) => println!("[GEN] {} -> Rendered index", section.title),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn load_templates(handlebars: &mut Handlebars) {
|
||||
match handlebars.register_template_file("base", "./templates/base.hbs") {
|
||||
Err(error) => panic!("Could not load base template: {}", error),
|
||||
Ok(_) => (),
|
||||
};
|
||||
|
||||
match handlebars.register_template_file("base_section", "./templates/base_section.hbs") {
|
||||
Err(error) => panic!("Could not load base template: {}", error),
|
||||
Ok(_) => (),
|
||||
};
|
||||
|
||||
match handlebars.register_template_file("header", "./templates/header.hbs") {
|
||||
Err(error) => panic!("Could not load header template: {}", error),
|
||||
Ok(_) => (),
|
||||
};
|
||||
|
||||
match handlebars.register_template_file("menu", "./templates/menu.hbs") {
|
||||
Err(error) => panic!("Could not load menu template: {}", error),
|
||||
Ok(_) => (),
|
||||
};
|
||||
|
||||
match handlebars.register_template_file("submenu", "./templates/submenu.hbs") {
|
||||
Err(error) => panic!("Could not load submenu template: {}", error),
|
||||
Ok(_) => (),
|
||||
};
|
||||
|
||||
match handlebars.register_template_file("article", "./templates/article.hbs") {
|
||||
Err(error) => panic!("Could not load article template: {}", error),
|
||||
Ok(_) => (),
|
||||
};
|
||||
}
|
||||
73
src/generator/loader.rs
Normal file
73
src/generator/loader.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
use std::fs::File;
|
||||
use std::fs::DirEntry;
|
||||
use std::fs::read_dir;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::markdown::marky::Marky;
|
||||
|
||||
use super::models::section::Section;
|
||||
use super::models::post::Post;
|
||||
|
||||
pub fn sections() -> Vec<Section> {
|
||||
let dir = match read_dir("./raws") {
|
||||
Err(error) => panic!("Could read raws directory: {}", error),
|
||||
Ok(dir) => dir,
|
||||
};
|
||||
|
||||
let mut sections: Vec<Section> = Vec::new();
|
||||
|
||||
for entry in dir {
|
||||
let entry = match entry {
|
||||
Err(error) => panic!("Could not read file: {}", error),
|
||||
Ok(entry) => entry,
|
||||
};
|
||||
|
||||
if entry.path().is_file() {
|
||||
|
||||
} else {
|
||||
sections.push(load_section(&entry));
|
||||
}
|
||||
}
|
||||
return sections;
|
||||
}
|
||||
|
||||
fn load_section(dir_entry: &DirEntry) -> Section {
|
||||
let dir = match read_dir(dir_entry.path()) {
|
||||
Err(error) => panic!("Could read raws sub directory: {}", error),
|
||||
Ok(dir) => dir,
|
||||
};
|
||||
|
||||
let mut section_posts: Vec<Post> = Vec::new();
|
||||
|
||||
for entry in dir {
|
||||
let entry = match entry {
|
||||
Err(error) => panic!("Could not read file: {}", error),
|
||||
Ok(entry) => entry.path(),
|
||||
};
|
||||
|
||||
if entry.is_file() {
|
||||
section_posts.push(load_post(&entry));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let section_name = dir_entry.file_name().into_string().unwrap();
|
||||
let section_url = section_name.to_lowercase().trim().replace(" ", "_");
|
||||
|
||||
println!("[LOADER] Loaded section {} with {} posts", section_name, section_posts.len());
|
||||
|
||||
return Section {
|
||||
title: section_name,
|
||||
url: section_url,
|
||||
posts: section_posts,
|
||||
}
|
||||
}
|
||||
|
||||
fn load_post(path: &Path) -> Post {
|
||||
let file = match File::open(path) {
|
||||
Err(error) => panic!("Could not read file: {}", error),
|
||||
Ok(file) => file,
|
||||
};
|
||||
let marky = Marky::from_file(&file);
|
||||
return Post::from_marky(marky);
|
||||
}
|
||||
3
src/generator/mod.rs
Normal file
3
src/generator/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod generate;
|
||||
pub mod loader;
|
||||
pub mod models;
|
||||
2
src/generator/models/mod.rs
Normal file
2
src/generator/models/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod post;
|
||||
pub mod section;
|
||||
34
src/generator/models/post.rs
Normal file
34
src/generator/models/post.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
use serde::Serialize;
|
||||
use markdown::to_html;
|
||||
|
||||
use crate::markdown::marky::Marky;
|
||||
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Post {
|
||||
pub title: String,
|
||||
pub date: String,
|
||||
pub url: String,
|
||||
pub description: String,
|
||||
pub tags: Vec<String>,
|
||||
pub body: String,
|
||||
pub is_year_only: bool,
|
||||
}
|
||||
|
||||
impl Post {
|
||||
pub fn from_marky(marky: Marky) -> Post {
|
||||
Post {
|
||||
title: marky.metadata.get("title").map_or(String::from("none"), String::from),
|
||||
date: marky.metadata.get("date").map_or(String::from("none"), String::from),
|
||||
url: marky.metadata.get("url").map_or(String::from("none"), String::from),
|
||||
description: marky.metadata.get("description").map_or(String::from("none"), String::from),
|
||||
tags: tags_string_to_vec(marky.metadata.get("tags").map_or(String::from("none"), String::from)),
|
||||
is_year_only: marky.metadata.get("yearonly").map_or(false, |a| a == "true"),
|
||||
body: to_html(&marky.content),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tags_string_to_vec(tags: String) -> Vec<String> {
|
||||
return tags.split(",").map(String::from).collect();
|
||||
}
|
||||
10
src/generator/models/section.rs
Normal file
10
src/generator/models/section.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
use serde::Serialize;
|
||||
|
||||
use super::post::Post;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Section {
|
||||
pub title: String,
|
||||
pub url: String,
|
||||
pub posts: Vec<Post>,
|
||||
}
|
||||
21
src/main.rs
Normal file
21
src/main.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
use std::fs;
|
||||
|
||||
mod generator;
|
||||
mod markdown;
|
||||
|
||||
use generator::generate;
|
||||
|
||||
fn main() {
|
||||
println!("[MAIN] Starting...");
|
||||
check_generated_folder();
|
||||
generate::landing_page();
|
||||
generate::sections();
|
||||
println!("[MAIN] Generation completed !");
|
||||
}
|
||||
|
||||
fn check_generated_folder() {
|
||||
match fs::create_dir_all("./generated") {
|
||||
Ok(_) => println!("[MAIN] Folder generated created"),
|
||||
Err(error) => println!("Error creating generated folder: {}", error),
|
||||
};
|
||||
}
|
||||
40
src/markdown/converter.rs
Normal file
40
src/markdown/converter.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
use super::marky::Marky;
|
||||
|
||||
pub fn marky_to_html (marky: Marky) -> String {
|
||||
let mut html = String::new();
|
||||
|
||||
for line in marky.content.lines() {
|
||||
if line.starts_with("####") {
|
||||
html.push_str("<h4>");
|
||||
html.push_str(&line.to_owned());
|
||||
html.push_str("</h4>");
|
||||
|
||||
} else if line.starts_with("###") {
|
||||
html.push_str("<h3>");
|
||||
html.push_str(&line.to_owned());
|
||||
html.push_str("</h3>");
|
||||
|
||||
} else if line.starts_with("##") {
|
||||
html.push_str("<h2>");
|
||||
html.push_str(&line.to_owned());
|
||||
html.push_str("</h2>");
|
||||
|
||||
} else if line.starts_with("#") {
|
||||
html.push_str("<h1>");
|
||||
html.push_str(&line.to_owned());
|
||||
html.push_str("</h1>");
|
||||
|
||||
} else if line.starts_with("*") || line.starts_with("-") {
|
||||
html.push_str("<h1>");
|
||||
html.push_str(&line.to_owned());
|
||||
html.push_str("</h1>");
|
||||
|
||||
} else {
|
||||
html.push_str("<p>");
|
||||
html.push_str(&line.to_owned());
|
||||
html.push_str("</p>");
|
||||
}
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
62
src/markdown/marky.rs
Normal file
62
src/markdown/marky.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
use std::collections::HashMap;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::fs::File;
|
||||
|
||||
pub struct Marky {
|
||||
pub metadata: HashMap<String, String>,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
impl Marky {
|
||||
pub fn from_file(file: &File) -> Marky {
|
||||
let reader = BufReader::new(file);
|
||||
|
||||
let mut is_metadata = false;
|
||||
let mut metadata = HashMap::new();
|
||||
let mut content = String::new();
|
||||
|
||||
for line in reader.lines() {
|
||||
let line = match line {
|
||||
Err(error) => panic!("Could not read line: {}", error),
|
||||
Ok(line) => line,
|
||||
};
|
||||
|
||||
match line.trim() {
|
||||
"---" => {
|
||||
if metadata.len() != 0 && !is_metadata {
|
||||
is_metadata = false;
|
||||
content.push_str(&line);
|
||||
} else {
|
||||
is_metadata = !is_metadata;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if is_metadata {
|
||||
if let Some(metadata_entry) = line_to_metadata(line) {
|
||||
metadata.insert(metadata_entry.0, metadata_entry.1);
|
||||
}
|
||||
} else {
|
||||
content.push_str(&line);
|
||||
content.push_str("\n");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Marky {
|
||||
metadata,
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn line_to_metadata(line: String) -> Option<(String, String)> {
|
||||
let separator_index = match line.find(":") {
|
||||
None => return None,
|
||||
Some(index) => index,
|
||||
};
|
||||
|
||||
let (key, value) = line.split_at(separator_index);
|
||||
|
||||
return Some((String::from(key), String::from(value.trim_start_matches(":").trim())));
|
||||
}
|
||||
2
src/markdown/mod.rs
Normal file
2
src/markdown/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod converter;
|
||||
pub mod marky;
|
||||
Reference in New Issue
Block a user