254 lines
8.6 KiB
Rust
254 lines
8.6 KiB
Rust
use std::fs::File;
|
|
use std::io::Read;
|
|
use std::path::Path;
|
|
use std::path::PathBuf;
|
|
|
|
use pathdiff;
|
|
|
|
use crate::config::Config;
|
|
use crate::error::Error;
|
|
use crate::file_writer;
|
|
use crate::logger::LogLevel;
|
|
use crate::options::Options;
|
|
use crate::renderer;
|
|
use crate::template::Template;
|
|
|
|
const DEFAULT_CSS: &'static str = include_str!("templates/default-css.css");
|
|
const DEFAULT_JS: &'static str = include_str!("templates/default-js.js");
|
|
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");
|
|
|
|
fn fetch_config() -> Result<Config, Error> {
|
|
match Config::new() {
|
|
Ok(config) => Ok(config),
|
|
Err(err) => Err(Error::from(err)),
|
|
}
|
|
}
|
|
|
|
pub fn build(opt: &Options) -> Result<(), Error> {
|
|
log::info!("Starting build");
|
|
let config = fetch_config()?;
|
|
|
|
if config.global_config.website.use_default_css {
|
|
let css_path = file_writer::add_to_beginning(
|
|
PathBuf::from("css/default.css"),
|
|
config
|
|
.clone()
|
|
.global_config
|
|
.website
|
|
.output
|
|
.unwrap_or("public".to_owned()),
|
|
);
|
|
log::debug!("Adding {:?}", css_path);
|
|
file_writer::write_file(&css_path, DEFAULT_CSS, opt.overwrite)?;
|
|
}
|
|
|
|
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()),
|
|
);
|
|
log::debug!("Adding {:?}", js_path);
|
|
file_writer::write_file(&js_path, DEFAULT_JS, opt.overwrite)?;
|
|
}
|
|
|
|
log::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);
|
|
|
|
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);
|
|
log::debug!("Rendering Navbar");
|
|
navbar_content =
|
|
renderer::render_navbar(&config, navbar_item_template, navbar_image_item_template)?;
|
|
}
|
|
|
|
log::info!("Rendering");
|
|
let configs = config.get_configs()?;
|
|
let mut renders = Vec::new();
|
|
for config in configs.clone() {
|
|
log::trace!("Setting up to render {}", config.page_config.page.html_path);
|
|
|
|
// Generate CSS tagstags
|
|
log::trace!("Generating CSS tags");
|
|
let mut css_string = String::new();
|
|
let css_list = config.global_config.website.css.clone();
|
|
|
|
for item in css_list {
|
|
let data = Template::css_tag_data_from(item, false);
|
|
css_string += &*css_tag_template.render(&data);
|
|
}
|
|
|
|
if let Some(list) = config.page_config.page.css.clone() {
|
|
for item in list {
|
|
let data = Template::css_tag_data_from(item, true);
|
|
css_string += &*css_tag_template.render(&data);
|
|
}
|
|
}
|
|
|
|
// Generate JS tags
|
|
log::trace!("Generating JS tags");
|
|
let mut js_string = String::new();
|
|
let js_list = config.global_config.website.javascript.clone();
|
|
|
|
for item in js_list {
|
|
let data = Template::css_tag_data_from(item, false);
|
|
js_string += &*js_tag_template.render(&data);
|
|
}
|
|
|
|
if let Some(list) = config.page_config.page.javascript.clone() {
|
|
for item in list {
|
|
let data = Template::css_tag_data_from(item, true);
|
|
js_string += &*js_tag_template.render(&data);
|
|
}
|
|
}
|
|
|
|
// Generate and render Injections
|
|
log::trace!("Rendering injections.");
|
|
let (before_navbar, before_content, after_content) = renderer::render_injections(&config)?;
|
|
|
|
log::trace!("Rendering");
|
|
|
|
let markdown = renderer::render_markdown_content(&config)?;
|
|
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,
|
|
);
|
|
let rendered = page_template.render(&data);
|
|
renders.push(rendered);
|
|
|
|
log::debug!("Rendered {}", config.page_config.page.html_path);
|
|
}
|
|
|
|
log::info!("Writing");
|
|
for (idx, config) in configs.clone().iter().enumerate() {
|
|
let html_path = config.clone().page_config.page.html_path;
|
|
let html_path = file_writer::add_to_beginning(
|
|
PathBuf::from(html_path),
|
|
config
|
|
.clone()
|
|
.global_config
|
|
.website
|
|
.output
|
|
.unwrap_or("public".to_owned()),
|
|
);
|
|
log::debug!("Writing {:?}", html_path);
|
|
if let Some(render) = renders.get(idx) {
|
|
file_writer::write_file(&html_path, render.clone(), opt.overwrite)?;
|
|
} else {
|
|
return Err(Error::new(
|
|
LogLevel::SEVERE,
|
|
format!("Internal error; Render not found for file: {:?}", html_path),
|
|
));
|
|
}
|
|
}
|
|
|
|
log::info!("Copying resources");
|
|
if let Some(resources) = config.global_config.resources.clone() {
|
|
for resource in resources.values() {
|
|
let path = Path::new(&resource.source);
|
|
if path.exists() {
|
|
let dest = file_writer::add_to_beginning(
|
|
PathBuf::from(resource.destination.clone()),
|
|
config
|
|
.clone()
|
|
.global_config
|
|
.website
|
|
.output
|
|
.unwrap_or("public".to_owned()),
|
|
);
|
|
match write_recursive_resource(
|
|
path.to_path_buf(),
|
|
PathBuf::from(resource.source.clone()),
|
|
dest,
|
|
) {
|
|
Ok(_) => log::debug!("Resource successfully copied."),
|
|
Err(err) => return Err(err),
|
|
}
|
|
} else {
|
|
log::warn!("Resource does not exist: {:?}", path);
|
|
}
|
|
}
|
|
}
|
|
|
|
log::info!("Done!");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
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(read_file) => {
|
|
let bytes: Vec<u8> = match read_file.bytes().collect() {
|
|
Ok(bytes) => bytes,
|
|
Err(_) => Vec::new(),
|
|
};
|
|
|
|
let mut dest_path = destination.clone();
|
|
|
|
if source.is_dir() {
|
|
dest_path = dest_path.join(relative.clone());
|
|
dest_path.set_file_name(resource_path.file_name().unwrap());
|
|
}
|
|
file_writer::write_bytes(&dest_path, &bytes, true)?;
|
|
|
|
Ok(())
|
|
}
|
|
Err(err) => Err(Error::new(
|
|
LogLevel::SEVERE,
|
|
format!("Failed to open read file {:?}: {}", resource_path, err),
|
|
)),
|
|
}
|
|
}
|
|
} else {
|
|
Err(Error::new(
|
|
LogLevel::SEVERE,
|
|
format!(
|
|
"Internal Error: resource relative path invalid: {:?} to {:?}",
|
|
&resource_path, &source
|
|
),
|
|
))
|
|
}
|
|
}
|