Merge pull request 'Separate application logic and improve error handling' (#3) from eprintln into main
Reviewed-on: #3
This commit is contained in:
commit
9b6c43a951
|
@ -171,7 +171,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nyf"
|
name = "nyf"
|
||||||
version = "0.3.0"
|
version = "0.4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"regex",
|
"regex",
|
||||||
"rss",
|
"rss",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "nyf"
|
name = "nyf"
|
||||||
version = "0.3.1"
|
version = "0.4.0"
|
||||||
authors = ["glyph <glyph@mycelial.technology>"]
|
authors = ["glyph <glyph@mycelial.technology>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "html splicer and rss generator"
|
description = "html splicer and rss generator"
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
//! # nyf
|
||||||
|
//!
|
||||||
|
//! _glyph's static site generator_
|
||||||
|
//!
|
||||||
|
//! This is an opinionated, custom-built HTML splicer. It reads HTML templates, splices
|
||||||
|
//! them into a base template and writes the output.
|
||||||
|
//!
|
||||||
|
//! Templates are expected at `./templates` and output is written to `./site`. The `./site`
|
||||||
|
//! directory will be created if it doesn't exist.
|
||||||
|
//!
|
||||||
|
//! A base template is expected at `./templates/base.html`. It must contain two tags:
|
||||||
|
//! `[[ title ]]` and `[[ content ]]`.
|
||||||
|
//!
|
||||||
|
//! The root index template is expected at `./templates/index.html`. All other templates are
|
||||||
|
//! expected to be in sub-directories; for example: `./templates/plants/index.html` or
|
||||||
|
//! `./templates/fungi/entomopathogens.html`.
|
||||||
|
//!
|
||||||
|
//! The splicer crawls the sub-directories of `./templates`, reads each HTML file, splices
|
||||||
|
//! it into the `[[ content ]]` tag of the base HTML template and writes the output to the
|
||||||
|
//! `./site` directory (preserving the sub-directory structure). The contents of the `<h2>`
|
||||||
|
//! element are spliced into the `[[ title ]]` tag of the base HTML template for each
|
||||||
|
//! sub-directory template.
|
||||||
|
//!
|
||||||
|
use std::{fs, io, path::Path};
|
||||||
|
|
||||||
|
// define the path for the template directory
|
||||||
|
const TEMPLATE_DIR: &str = "./templates";
|
||||||
|
// define the path for the generated site output
|
||||||
|
const SITE_DIR: &str = "./site";
|
||||||
|
|
||||||
|
pub fn run() -> Result<(), &'static str> {
|
||||||
|
// read the base html template to a string
|
||||||
|
let base = format!("{}/base.html", TEMPLATE_DIR);
|
||||||
|
let base_path = Path::new(&base);
|
||||||
|
let base_html = fs::read_to_string(base_path)
|
||||||
|
.map_err(|_| "couldn't read from templates/base.html; does it exist?")?;
|
||||||
|
|
||||||
|
// read the index html template to a string
|
||||||
|
let index = format!("{}/index.html", TEMPLATE_DIR);
|
||||||
|
let index_path = Path::new(&index);
|
||||||
|
let index_html = fs::read_to_string(index_path)
|
||||||
|
.map_err(|_| "couldn't read from templates/index.html; does it exist?")?;
|
||||||
|
|
||||||
|
// create site directory if it doesn't already exist
|
||||||
|
let site_dir_path = Path::new(&SITE_DIR);
|
||||||
|
if !site_dir_path.is_dir() {
|
||||||
|
fs::create_dir(site_dir_path).map_err(|_| "failed to create site output directory")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// integrate the content from the index template into the base template
|
||||||
|
let mut index_output = base_html.replace("[[ content ]]", &index_html);
|
||||||
|
// set the page title
|
||||||
|
index_output = index_output.replace("[[ title ]]", "mycelial technology");
|
||||||
|
let index_output_path = format!("{}/index.html", SITE_DIR);
|
||||||
|
// write the generated index html to file
|
||||||
|
fs::write(index_output_path, index_output.trim())
|
||||||
|
.map_err(|_| "failed to write the root index.html file")?;
|
||||||
|
|
||||||
|
// walk the template directory and collect paths for all files and sub-directories
|
||||||
|
let template_files: Vec<_> = fs::read_dir(TEMPLATE_DIR)
|
||||||
|
.map_err(|_| "failed to read template directory")?
|
||||||
|
.map(|res| res.map(|e| e.path()))
|
||||||
|
.collect::<Result<Vec<_>, io::Error>>()
|
||||||
|
.map_err(|_| "failed to collect template file paths")?;
|
||||||
|
|
||||||
|
// loop through each file and sub-directory
|
||||||
|
for entry in template_files {
|
||||||
|
if entry.is_dir() {
|
||||||
|
// replicate templates sub-directory structure in site output directory
|
||||||
|
let template_sub_dir_suffix = entry
|
||||||
|
.strip_prefix(TEMPLATE_DIR)
|
||||||
|
.map_err(|_| "failed to strip prefix from template directory path")?;
|
||||||
|
let site_sub_dir = Path::new(SITE_DIR).join(template_sub_dir_suffix);
|
||||||
|
// create the sub-directory if it doesn't already exist
|
||||||
|
if !site_sub_dir.is_dir() {
|
||||||
|
fs::create_dir(site_sub_dir)
|
||||||
|
.map_err(|_| "failed to create a site output sub-directory")?;
|
||||||
|
}
|
||||||
|
// read each file from the sub-directory
|
||||||
|
for file in fs::read_dir(entry)
|
||||||
|
.map_err(|_| "failed to enumerate template sub-directory files")?
|
||||||
|
{
|
||||||
|
let file = file.map_err(|_| "failed to obtain sub-directory file data")?;
|
||||||
|
let file_path = file.path();
|
||||||
|
let file_html = fs::read_to_string(&file_path)
|
||||||
|
.map_err(|_| "failed to read template html file to string")?;
|
||||||
|
// find the index of the h2 tag (represents the page title)
|
||||||
|
let mut title_start = file_html.find("<h2>").ok_or("<h2> tag not found in html")?;
|
||||||
|
// increment the index to represent the start of the title text
|
||||||
|
title_start += 4;
|
||||||
|
// find the index of the h2 closing tag
|
||||||
|
let title_end = file_html
|
||||||
|
.find("</h2>")
|
||||||
|
.ok_or("</h2> tag not found in html")?;
|
||||||
|
// obtain the title text as a string slice
|
||||||
|
let title = &file_html[title_start..title_end];
|
||||||
|
// integrate the content from the template into the base template
|
||||||
|
let mut file_output = base_html.replace("[[ content ]]", &file_html);
|
||||||
|
// integrate the title of the page into the file output
|
||||||
|
file_output = file_output.replace("[[ title ]]", title);
|
||||||
|
// define the path to which the output html file will be written
|
||||||
|
let file_output_path = file_path.to_string_lossy();
|
||||||
|
// replace the template directory path with the site output path
|
||||||
|
let output_path = file_output_path.replace(TEMPLATE_DIR, SITE_DIR);
|
||||||
|
// trim whitespace from the end of the generated html and write to file
|
||||||
|
fs::write(output_path, file_output.trim())
|
||||||
|
.map_err(|_| "failed to write html file to site directory")?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
107
src/main.rs
107
src/main.rs
|
@ -1,107 +1,8 @@
|
||||||
//! # nyf
|
use std::process;
|
||||||
//!
|
|
||||||
//! _glyph's static site generator_
|
|
||||||
//!
|
|
||||||
//! This is an opinionated, custom-built HTML splicer. It reads HTML templates, splices
|
|
||||||
//! them into a base template and writes the output.
|
|
||||||
//!
|
|
||||||
//! Templates are expected at `./templates` and output is written to `./site`. The `./site`
|
|
||||||
//! directory will be created if it doesn't exist.
|
|
||||||
//!
|
|
||||||
//! A base template is expected at `./templates/base.html`. It must contain two tags:
|
|
||||||
//! `[[ title ]]` and `[[ content ]]`.
|
|
||||||
//!
|
|
||||||
//! The root index template is expected at `./templates/index.html`. All other templates are
|
|
||||||
//! expected to be in sub-directories; for example: `./templates/plants/index.html` or
|
|
||||||
//! `./templates/fungi/entomopathogens.html`.
|
|
||||||
//!
|
|
||||||
//! The splicer crawls the sub-directories of `./templates`, reads each HTML file, splices
|
|
||||||
//! it into the `[[ content ]]` tag of the base HTML template and writes the output to the
|
|
||||||
//! `./site` directory (preserving the sub-directory structure). The contents of the `<h2>`
|
|
||||||
//! element are spliced into the `[[ title ]]` tag of the base HTML template for each
|
|
||||||
//! sub-directory template.
|
|
||||||
//!
|
|
||||||
use std::{fs, io, path::Path};
|
|
||||||
|
|
||||||
// define the path for the template directory
|
|
||||||
const TEMPLATE_DIR: &str = "./templates";
|
|
||||||
// define the path for the generated site output
|
|
||||||
const SITE_DIR: &str = "./site";
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// read the base html template to a string
|
if let Err(e) = nyf::run() {
|
||||||
let base = format!("{}/base.html", TEMPLATE_DIR);
|
eprintln!("{}", e);
|
||||||
let base_path = Path::new(&base);
|
process::exit(1);
|
||||||
let base_html = fs::read_to_string(base_path)
|
|
||||||
.expect("couldn't read from templates/base.html; does it exist?");
|
|
||||||
|
|
||||||
// read the index html template to a string
|
|
||||||
let index = format!("{}/index.html", TEMPLATE_DIR);
|
|
||||||
let index_path = Path::new(&index);
|
|
||||||
let index_html = fs::read_to_string(index_path)
|
|
||||||
.expect("couldn't read from templates/index.html; does it exist?");
|
|
||||||
|
|
||||||
// create site directory if it doesn't already exist
|
|
||||||
let site_dir_path = Path::new(&SITE_DIR);
|
|
||||||
if !site_dir_path.is_dir() {
|
|
||||||
fs::create_dir(site_dir_path).expect("failed to create site output directory");
|
|
||||||
}
|
|
||||||
|
|
||||||
// integrate the content from the index template into the base template
|
|
||||||
let mut index_output = base_html.replace("[[ content ]]", &index_html);
|
|
||||||
// set the page title
|
|
||||||
index_output = index_output.replace("[[ title ]]", "mycelial technology");
|
|
||||||
let index_output_path = format!("{}/index.html", SITE_DIR);
|
|
||||||
// write the generated index html to file
|
|
||||||
fs::write(index_output_path, index_output.trim())
|
|
||||||
.expect("failed to write the root index.html file");
|
|
||||||
|
|
||||||
// walk the template directory and collect paths for all files and sub-directories
|
|
||||||
let template_files: Vec<_> = fs::read_dir(TEMPLATE_DIR)
|
|
||||||
.expect("failed to read template directory")
|
|
||||||
.map(|res| res.map(|e| e.path()))
|
|
||||||
.collect::<Result<Vec<_>, io::Error>>()
|
|
||||||
.expect("failed to collect template file paths");
|
|
||||||
|
|
||||||
// loop through each file and sub-directory
|
|
||||||
for entry in template_files {
|
|
||||||
if entry.is_dir() {
|
|
||||||
// replicate templates sub-directory structure in site output directory
|
|
||||||
let template_sub_dir_suffix = entry
|
|
||||||
.strip_prefix(TEMPLATE_DIR)
|
|
||||||
.expect("failed to strip prefix from template directory path");
|
|
||||||
let site_sub_dir = Path::new(SITE_DIR).join(template_sub_dir_suffix);
|
|
||||||
// create the sub-directory if it doesn't already exist
|
|
||||||
if !site_sub_dir.is_dir() {
|
|
||||||
fs::create_dir(site_sub_dir).expect("failed to create a site output sub-directory");
|
|
||||||
}
|
|
||||||
// read each file from the sub-diretory
|
|
||||||
for file in fs::read_dir(entry).expect("failed to read file in template sub-directory")
|
|
||||||
{
|
|
||||||
let file = file.unwrap();
|
|
||||||
let file_path = file.path();
|
|
||||||
let file_html = fs::read_to_string(&file_path)
|
|
||||||
.expect("failed to read template html file to string");
|
|
||||||
// find the index of the h2 tag (represents the page title)
|
|
||||||
let mut title_start = file_html.find("<h2>").expect("<h2> tag not found");
|
|
||||||
// increment the index to represent the start of the title text
|
|
||||||
title_start += 4;
|
|
||||||
// find the index of the h2 closing tag
|
|
||||||
let title_end = file_html.find("</h2>").expect("</h2> tag not found");
|
|
||||||
// obtain the title text as a string slice
|
|
||||||
let title = &file_html[title_start..title_end];
|
|
||||||
// integrate the content from the template into the base template
|
|
||||||
let mut file_output = base_html.replace("[[ content ]]", &file_html);
|
|
||||||
// integrate the title of the page into the file output
|
|
||||||
file_output = file_output.replace("[[ title ]]", title);
|
|
||||||
// define the path to which the output html file will be written
|
|
||||||
let file_output_path = file_path.to_string_lossy();
|
|
||||||
// replace the template directory path with the site output path
|
|
||||||
let output_path = file_output_path.replace(TEMPLATE_DIR, SITE_DIR);
|
|
||||||
// trim whitespace from the end of the generated html and write to file
|
|
||||||
fs::write(output_path, file_output.trim())
|
|
||||||
.expect("failed to write html file to site directory")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue