teascade-generator/src/builder.rs

261 lines
9.0 KiB
Rust
Raw Normal View History

use std::path::PathBuf;
2018-04-19 00:12:18 +02:00
use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::error::Error as STDError;
use pathdiff;
2018-04-16 15:58:16 +02:00
use config::Config;
use template::Template;
use renderer;
use logger::{LogLevel, Logger};
use error::Error;
use options::{BuildOpt, Opt};
use file_writer;
2018-04-16 15:58:16 +02:00
const DEFAULT_CSS: &'static str = include_str!("templates/default-css.css");
2018-04-19 21:21:49 +02:00
const DEFAULT_JS: &'static str = include_str!("templates/default-js.js");
2018-04-16 15:58:16 +02:00
const PAGE_TEMPLATE: &'static str = include_str!("templates/page-template.html");
const NAVBAR_ITEM: &'static str = include_str!("templates/navbar/item-template.html");
const NAVBAR_IMAGE_ITEM: &'static str = include_str!("templates/navbar/image-item-template.html");
const CSS_TAG: &'static str = include_str!("templates/meta_tags/css_tag.html");
const JS_TAG: &'static str = include_str!("templates/meta_tags/js_tag.html");
2018-04-16 15:58:16 +02:00
fn fetch_config() -> Result<Config, Error> {
match Config::new() {
Ok(config) => Ok(config),
Err(err) => Err(Error::from(err)),
}
}
pub fn build(logger: &Logger, opt: &Opt, _: &BuildOpt) -> Result<(), Error> {
2018-04-16 15:58:16 +02:00
logger.log(LogLevel::INFO, "Starting build");
let config = fetch_config()?;
if config.global_config.website.use_default_css {
2018-04-19 00:42:12 +02:00
let css_path = file_writer::add_to_beginning(
PathBuf::from("css/default.css"),
config
.clone()
.global_config
.website
.output
.unwrap_or("public".to_owned()),
2018-04-19 00:54:03 +02:00
);
logger.log(LogLevel::DETAIL, format!("Adding {:?}", css_path));
file_writer::write_file(&css_path, DEFAULT_CSS, opt.overwrite)?;
2018-04-16 15:58:16 +02:00
}
2018-04-19 21:21:49 +02:00
if config.global_config.website.use_default_js {
let js_path = file_writer::add_to_beginning(
PathBuf::from("js/default.js"),
config
.clone()
.global_config
.website
.output
.unwrap_or("public".to_owned()),
);
logger.log(LogLevel::DETAIL, format!("Adding {:?}", js_path));
file_writer::write_file(&js_path, DEFAULT_JS, opt.overwrite)?;
}
2018-04-16 15:58:16 +02:00
logger.log(LogLevel::INFO, "Generating page templates");
let page_template = Template::new(PAGE_TEMPLATE);
let css_tag_template = Template::new(CSS_TAG);
let js_tag_template = Template::new(JS_TAG);
2018-04-16 15:58:16 +02:00
let mut navbar_content = String::new();
if config.global_config.navbar.is_some() {
let navbar_item_template = Template::new(NAVBAR_ITEM);
let navbar_image_item_template = Template::new(NAVBAR_IMAGE_ITEM);
logger.log(LogLevel::DETAIL, "Rendering Navbar");
navbar_content =
renderer::render_navbar(&config, navbar_item_template, navbar_image_item_template)?;
}
logger.log(LogLevel::INFO, "Rendering");
2018-04-16 16:33:26 +02:00
let configs = config.get_configs()?;
let mut renders = Vec::new();
for config in configs.clone() {
logger.log(
LogLevel::DETAILER,
format!("Setting up to render {}", config.page_config.page.html_path),
);
// Generate CSS tagstags
logger.log(LogLevel::DETAILER, "Generating CSS tags");
let mut css_string = String::new();
let mut css_list = config.global_config.website.css.clone();
if let Some(mut list) = config.page_config.page.css.clone() {
css_list.append(&mut list);
}
for item in css_list {
let data = Template::css_tag_data_from(item);
css_string += &*css_tag_template.render(&data);
}
// Generate JS tags
logger.log(LogLevel::DETAILER, "Generating JS tags");
let mut js_string = String::new();
let mut js_list = config.global_config.website.javascript.clone();
if let Some(mut list) = config.page_config.page.javascript.clone() {
js_list.append(&mut list);
}
for item in js_list {
let data = Template::css_tag_data_from(item);
js_string += &*js_tag_template.render(&data);
}
// Generate and render Injections
logger.log(LogLevel::DETAILER, "Rendering injections.");
let (before_navbar, before_content, after_content) =
renderer::render_injections(&logger, &config)?;
logger.log(LogLevel::DETAILER, "Rendering");
2018-04-16 16:33:26 +02:00
let markdown = renderer::render_markdown_content(&config)?;
2018-04-20 01:52:48 +02:00
let markdown = renderer::render_custom_markdown(markdown)?;
let data = Template::page_data_from(
config.clone(),
navbar_content.clone(),
before_navbar,
before_content,
after_content,
css_string,
js_string,
markdown,
);
2018-04-16 16:33:26 +02:00
let rendered = page_template.render(&data);
renders.push(rendered);
2018-04-19 00:58:03 +02:00
logger.log(
LogLevel::DETAIL,
format!("Rendered {}", config.page_config.page.html_path),
);
2018-04-16 16:33:26 +02:00
}
2018-04-16 15:58:16 +02:00
logger.log(LogLevel::INFO, "Writing");
2018-04-16 16:33:26 +02:00
for (idx, config) in configs.clone().iter().enumerate() {
let html_path = config.clone().page_config.page.html_path;
2018-04-19 00:42:12 +02:00
let html_path = file_writer::add_to_beginning(
PathBuf::from(html_path),
config
.clone()
.global_config
.website
.output
.unwrap_or("public".to_owned()),
2018-04-19 00:54:03 +02:00
);
2018-04-19 00:58:03 +02:00
logger.log(LogLevel::DETAIL, format!("Writing {:?}", html_path));
2018-04-16 16:33:26 +02:00
if let Some(render) = renders.get(idx) {
file_writer::write_file(&html_path, render.clone(), opt.overwrite)?;
2018-04-16 16:33:26 +02:00
} else {
return Err(Error::new(
LogLevel::SEVERE,
format!("Internal error; Render not found for file: {:?}", html_path),
2018-04-16 16:33:26 +02:00
));
}
}
2018-04-16 15:58:16 +02:00
2018-04-19 00:12:18 +02:00
logger.log(LogLevel::INFO, "Copying resources");
2018-04-19 00:42:12 +02:00
if let Some(resources) = config.global_config.resources.clone() {
2018-04-19 00:12:18 +02:00
for resource in resources.values() {
let path = Path::new(&resource.source);
if path.exists() {
2018-04-19 00:54:03 +02:00
let dest = file_writer::add_to_beginning(
PathBuf::from(resource.destination.clone()),
config
.clone()
.global_config
.website
.output
.unwrap_or("public".to_owned()),
);
2018-04-19 00:12:18 +02:00
match write_recursive_resource(
path.to_path_buf(),
PathBuf::from(resource.source.clone()),
2018-04-19 00:54:03 +02:00
dest,
2018-04-19 00:12:18 +02:00
) {
Ok(_) => logger.log(LogLevel::DETAIL, "Resource successfully copied."),
Err(err) => return Err(err),
}
} else {
logger.log(
LogLevel::WARNING,
format!("Resource does not exist: {:?}", path),
);
}
}
}
2018-04-16 15:58:16 +02:00
logger.log(LogLevel::INFO, "Done!");
2018-04-19 00:12:18 +02:00
2018-04-16 15:58:16 +02:00
Ok(())
}
2018-04-19 00:12:18 +02:00
fn write_recursive_resource(
resource_path: PathBuf,
source: PathBuf,
destination: PathBuf,
) -> Result<(), Error> {
if let Some(relative) = pathdiff::diff_paths(&resource_path, &source) {
if resource_path.is_dir() {
for item in resource_path.read_dir().unwrap() {
match item {
Ok(item) => {
match write_recursive_resource(
item.path(),
source.clone(),
destination.clone(),
) {
Ok(_) => {}
Err(err) => return Err(err),
};
}
Err(error) => return Err(Error::from(error)),
}
}
Ok(())
} else {
match File::open(resource_path.clone()) {
Ok(mut read_file) => {
2018-04-19 21:21:49 +02:00
let bytes: Vec<u8> = match read_file.bytes().collect() {
Ok(bytes) => bytes,
Err(_) => Vec::new(),
};
2018-04-19 00:54:03 +02:00
let mut dest_path = destination.clone();
2018-04-19 00:12:18 +02:00
if source.is_dir() {
dest_path = dest_path.join(relative.clone());
dest_path.set_file_name(resource_path.file_name().unwrap());
}
2018-04-19 21:21:49 +02:00
file_writer::write_bytes(&dest_path, &bytes, true)?;
2018-04-19 00:12:18 +02:00
Ok(())
}
Err(err) => Err(Error::new(
LogLevel::SEVERE,
format!(
"Failed to open read file {:?}: {}",
resource_path,
err.description().to_owned()
),
)),
}
}
} else {
Err(Error::new(
LogLevel::SEVERE,
format!(
"Internal Error: resource relative path invalid: {:?} to {:?}",
&resource_path, &source
),
))
}
}