Cached building
This commit is contained in:
parent
ac0c4050eb
commit
c8d35a7dc3
3 changed files with 250 additions and 136 deletions
|
@ -9,9 +9,6 @@ use crate::document::document::Document;
|
||||||
use crate::document::document::ElemReference;
|
use crate::document::document::ElemReference;
|
||||||
use crate::document::variable::Variable;
|
use crate::document::variable::Variable;
|
||||||
|
|
||||||
use super::navigation::NavEntry;
|
|
||||||
use super::navigation::Navigation;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum Target {
|
pub enum Target {
|
||||||
HTML,
|
HTML,
|
||||||
|
@ -133,80 +130,128 @@ impl Compiler {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn navigation(&self, navigation: &Navigation, document: &dyn Document) -> String
|
|
||||||
{
|
|
||||||
let mut result = String::new();
|
|
||||||
match self.target()
|
|
||||||
{
|
|
||||||
Target::HTML => {
|
|
||||||
result += r#"<ul id="navbar">"#;
|
|
||||||
|
|
||||||
fn process(result: &mut String, name: &String, ent: &NavEntry, depth: usize)
|
|
||||||
{
|
|
||||||
let ent_path = ent.path.as_ref()
|
|
||||||
.map_or("#".to_string(),|path| path.clone());
|
|
||||||
result.push_str(format!(r#"<li><a href="{ent_path}">{name}</a></li>"#).as_str());
|
|
||||||
|
|
||||||
if let Some(children) = ent.children.as_ref()
|
|
||||||
{
|
|
||||||
result.push_str("<ul>");
|
|
||||||
for (name, ent) in children
|
|
||||||
{
|
|
||||||
process(result, name, ent, depth+1);
|
|
||||||
}
|
|
||||||
result.push_str("</ul>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (name, ent) in &navigation.entries
|
|
||||||
{
|
|
||||||
process(&mut result, name, ent, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
result += r#"</ul>"#;
|
|
||||||
},
|
|
||||||
_ => todo!("")
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn footer(&self, _document: &dyn Document) -> String {
|
pub fn footer(&self, _document: &dyn Document) -> String {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
match self.target() {
|
match self.target() {
|
||||||
Target::HTML => {
|
Target::HTML => {
|
||||||
result += "</body></html>";
|
result += "</body></html>";
|
||||||
}
|
}
|
||||||
Target::LATEX => todo!("")
|
Target::LATEX => todo!(""),
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(&self, navigation: &Navigation, document: &dyn Document) -> String {
|
pub fn compile(&self, document: &dyn Document) -> CompiledDocument {
|
||||||
let mut out = String::new();
|
|
||||||
let borrow = document.content().borrow();
|
let borrow = document.content().borrow();
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
out += self.header(document).as_str();
|
let header = self.header(document);
|
||||||
|
|
||||||
// Navigation
|
|
||||||
out += self.navigation(navigation, document).as_str();
|
|
||||||
|
|
||||||
// Body
|
// Body
|
||||||
|
let mut body = String::new();
|
||||||
for i in 0..borrow.len() {
|
for i in 0..borrow.len() {
|
||||||
let elem = &borrow[i];
|
let elem = &borrow[i];
|
||||||
|
|
||||||
match elem.compile(self, document) {
|
match elem.compile(self, document) {
|
||||||
Ok(result) => {
|
Ok(result) => body.push_str(result.as_str()),
|
||||||
out.push_str(result.as_str())
|
|
||||||
}
|
|
||||||
Err(err) => println!("Unable to compile element: {err}\n{}", elem.to_string()),
|
Err(err) => println!("Unable to compile element: {err}\n{}", elem.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Footer
|
// Footer
|
||||||
out += self.footer(document).as_str();
|
let footer = self.footer(document);
|
||||||
|
|
||||||
out
|
// Variables
|
||||||
|
let variables = document
|
||||||
|
.scope()
|
||||||
|
.borrow_mut()
|
||||||
|
.variables
|
||||||
|
.iter()
|
||||||
|
.map(|(key, var)| (key.clone(), var.to_string()))
|
||||||
|
.collect::<HashMap<String, String>>();
|
||||||
|
|
||||||
|
CompiledDocument {
|
||||||
|
input: document.source().name().clone(),
|
||||||
|
mtime: 0,
|
||||||
|
variables,
|
||||||
|
header,
|
||||||
|
body,
|
||||||
|
footer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CompiledDocument {
|
||||||
|
/// Input path relative to the input directory
|
||||||
|
pub input: String,
|
||||||
|
/// Modification time (i.e seconds since last epoch)
|
||||||
|
pub mtime: u64,
|
||||||
|
|
||||||
|
// TODO: Also store exported references
|
||||||
|
// so they can be referenced from elsewhere
|
||||||
|
// This will also require rebuilding in case some exported references have changed...
|
||||||
|
/// Variables exported to string, so they can be querried later
|
||||||
|
pub variables: HashMap<String, String>,
|
||||||
|
|
||||||
|
/// Compiled document's header
|
||||||
|
pub header: String,
|
||||||
|
/// Compiled document's body
|
||||||
|
pub body: String,
|
||||||
|
/// Compiled document's footer
|
||||||
|
pub footer: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompiledDocument {
|
||||||
|
pub fn get_variable(&self, name: &str) -> Option<&String> { self.variables.get(name) }
|
||||||
|
|
||||||
|
fn sql_table() -> &'static str {
|
||||||
|
"CREATE TABLE IF NOT EXISTS compiled_documents (
|
||||||
|
input TEXT PRIMARY KEY,
|
||||||
|
mtime INTEGER NOT NULL,
|
||||||
|
variables TEXT NOT NULL,
|
||||||
|
header TEXT NOT NULL,
|
||||||
|
body TEXT NOT NULL,
|
||||||
|
footer TEXT NOT NULL
|
||||||
|
);"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sql_get_query() -> &'static str { "SELECT * FROM compiled_documents WHERE input = (?1)" }
|
||||||
|
|
||||||
|
fn sql_insert_query() -> &'static str {
|
||||||
|
"INSERT OR REPLACE INTO compiled_documents (input, mtime, variables, header, body, footer) VALUES (?1, ?2, ?3, ?4, ?5, ?6)"
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_cache(con: &Connection) -> Result<usize, rusqlite::Error> {
|
||||||
|
con.execute(Self::sql_table(), [])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_cache(con: &Connection, input: &String) -> Option<Self> {
|
||||||
|
con.query_row(Self::sql_get_query(), [input], |row| {
|
||||||
|
Ok(CompiledDocument {
|
||||||
|
input: input.clone(),
|
||||||
|
mtime: row.get_unwrap::<_, u64>(1),
|
||||||
|
variables: serde_json::from_str(row.get_unwrap::<_, String>(2).as_str()).unwrap(),
|
||||||
|
header: row.get_unwrap::<_, String>(3),
|
||||||
|
body: row.get_unwrap::<_, String>(4),
|
||||||
|
footer: row.get_unwrap::<_, String>(5),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inserts [`CompiledDocument`] into cache
|
||||||
|
pub fn insert_cache(&self, con: &Connection) -> Result<usize, rusqlite::Error> {
|
||||||
|
con.execute(
|
||||||
|
Self::sql_insert_query(),
|
||||||
|
(
|
||||||
|
&self.input,
|
||||||
|
&self.mtime,
|
||||||
|
serde_json::to_string(&self.variables).unwrap(),
|
||||||
|
&self.header,
|
||||||
|
&self.body,
|
||||||
|
&self.footer,
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::document::document::Document;
|
use super::compiler::CompiledDocument;
|
||||||
|
use super::compiler::Target;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NavEntry {
|
pub struct NavEntry {
|
||||||
|
@ -14,7 +15,43 @@ pub struct Navigation {
|
||||||
pub(crate) entries: HashMap<String, NavEntry>,
|
pub(crate) entries: HashMap<String, NavEntry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_navigation(docs: &Vec<Box<dyn Document>>) -> Result<Navigation, String> {
|
impl Navigation {
|
||||||
|
pub fn compile(&self, target: Target) -> String {
|
||||||
|
let mut result = String::new();
|
||||||
|
match target {
|
||||||
|
Target::HTML => {
|
||||||
|
result += r#"<ul id="navbar">"#;
|
||||||
|
|
||||||
|
fn process(result: &mut String, name: &String, ent: &NavEntry, depth: usize) {
|
||||||
|
let ent_path = ent
|
||||||
|
.path
|
||||||
|
.as_ref()
|
||||||
|
.map_or("#".to_string(), |path| path.clone());
|
||||||
|
result
|
||||||
|
.push_str(format!(r#"<li><a href="{ent_path}">{name}</a></li>"#).as_str());
|
||||||
|
|
||||||
|
if let Some(children) = ent.children.as_ref() {
|
||||||
|
result.push_str("<ul>");
|
||||||
|
for (name, ent) in children {
|
||||||
|
process(result, name, ent, depth + 1);
|
||||||
|
}
|
||||||
|
result.push_str("</ul>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (name, ent) in &self.entries {
|
||||||
|
process(&mut result, name, ent, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
result += r#"</ul>"#;
|
||||||
|
}
|
||||||
|
_ => todo!(""),
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_navigation(docs: &Vec<CompiledDocument>) -> Result<Navigation, String> {
|
||||||
let mut nav = Navigation {
|
let mut nav = Navigation {
|
||||||
entries: HashMap::new(),
|
entries: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
@ -30,63 +67,57 @@ pub fn create_navigation(docs: &Vec<Box<dyn Document>>) -> Result<Navigation, St
|
||||||
let (cat, title, path) = match (cat, title, path) {
|
let (cat, title, path) = match (cat, title, path) {
|
||||||
(Some(cat), Some(title), Some(path)) => (cat, title, path),
|
(Some(cat), Some(title), Some(path)) => (cat, title, path),
|
||||||
_ => {
|
_ => {
|
||||||
println!(
|
println!("Skipping navigation generation for `{}`", doc.input);
|
||||||
"Skipping navigation generation for `{}`",
|
|
||||||
doc.source().name()
|
|
||||||
);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(subcat) = subcat {
|
if let Some(subcat) = subcat {
|
||||||
// Get parent entry
|
// Get parent entry
|
||||||
let cat_name = cat.to_string();
|
let mut pent = match nav.entries.get_mut(cat.as_str()) {
|
||||||
let mut pent = match nav.entries.get_mut(cat_name.as_str()) {
|
|
||||||
Some(pent) => pent,
|
Some(pent) => pent,
|
||||||
None => {
|
None => {
|
||||||
// Create parent entry
|
// Create parent entry
|
||||||
nav.entries.insert(
|
nav.entries.insert(
|
||||||
cat_name.clone(),
|
cat.clone(),
|
||||||
NavEntry {
|
NavEntry {
|
||||||
name: cat_name.clone(),
|
name: cat.clone(),
|
||||||
path: None,
|
path: None,
|
||||||
children: Some(HashMap::new()),
|
children: Some(HashMap::new()),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
nav.entries.get_mut(cat_name.as_str()).unwrap()
|
nav.entries.get_mut(cat.as_str()).unwrap()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Insert into parent
|
// Insert into parent
|
||||||
let subcat_name = subcat.to_string();
|
|
||||||
if let Some(previous) = pent.children.as_mut().unwrap().insert(
|
if let Some(previous) = pent.children.as_mut().unwrap().insert(
|
||||||
subcat_name.clone(),
|
subcat.clone(),
|
||||||
NavEntry {
|
NavEntry {
|
||||||
name: subcat_name.clone(),
|
name: subcat.clone(),
|
||||||
path: Some(path.to_string()),
|
path: Some(path.to_string()),
|
||||||
children: None,
|
children: None,
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"Duplicate subcategory:\n{subcat:#?}\nclashes with:\n{previous:#?}"
|
"Duplicate subcategory:\n{subcat}\nclashes with:\n{previous:#?}"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Get entry
|
// Get entry
|
||||||
let cat_name = cat.to_string();
|
let mut ent = match nav.entries.get_mut(cat.as_str()) {
|
||||||
let mut ent = match nav.entries.get_mut(cat_name.as_str()) {
|
|
||||||
Some(ent) => ent,
|
Some(ent) => ent,
|
||||||
None => {
|
None => {
|
||||||
// Create parent entry
|
// Create parent entry
|
||||||
nav.entries.insert(
|
nav.entries.insert(
|
||||||
cat_name.clone(),
|
cat.clone(),
|
||||||
NavEntry {
|
NavEntry {
|
||||||
name: cat_name.clone(),
|
name: cat.clone(),
|
||||||
path: None,
|
path: None,
|
||||||
children: Some(HashMap::new()),
|
children: Some(HashMap::new()),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
nav.entries.get_mut(cat_name.as_str()).unwrap()
|
nav.entries.get_mut(cat.as_str()).unwrap()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
164
src/main.rs
164
src/main.rs
|
@ -7,9 +7,14 @@ mod lua;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::BufWriter;
|
||||||
|
use std::io::Write;
|
||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::time::UNIX_EPOCH;
|
||||||
|
|
||||||
|
use compiler::compiler::CompiledDocument;
|
||||||
use compiler::compiler::Compiler;
|
use compiler::compiler::Compiler;
|
||||||
use compiler::compiler::Target;
|
use compiler::compiler::Target;
|
||||||
use compiler::navigation::create_navigation;
|
use compiler::navigation::create_navigation;
|
||||||
|
@ -18,6 +23,7 @@ use document::document::Document;
|
||||||
use getopts::Options;
|
use getopts::Options;
|
||||||
use parser::langparser::LangParser;
|
use parser::langparser::LangParser;
|
||||||
use parser::parser::Parser;
|
use parser::parser::Parser;
|
||||||
|
use rusqlite::Connection;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use crate::parser::source::SourceFile;
|
use crate::parser::source::SourceFile;
|
||||||
|
@ -42,38 +48,7 @@ NML version: 0.4\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile(
|
fn parse(input: &String, debug_opts: &Vec<String>) -> Result<Box<dyn Document<'static>>, String> {
|
||||||
target: Target,
|
|
||||||
doc: &Box<dyn Document>,
|
|
||||||
output: &String,
|
|
||||||
db_path: &Option<String>,
|
|
||||||
navigation: &Navigation,
|
|
||||||
multi_mode: bool,
|
|
||||||
) -> bool {
|
|
||||||
let compiler = Compiler::new(target, db_path.clone());
|
|
||||||
|
|
||||||
// Get output from file
|
|
||||||
if multi_mode {
|
|
||||||
let out_file = match doc.get_variable("compiler.output") {
|
|
||||||
None => {
|
|
||||||
eprintln!("Missing required variable `compiler.output` for multifile mode");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Some(var) => output.clone() + "/" + var.to_string().as_str(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let out = compiler.compile(navigation, doc.as_ref());
|
|
||||||
std::fs::write(out_file, out).is_ok()
|
|
||||||
} else {
|
|
||||||
let out = compiler.compile(navigation, doc.as_ref());
|
|
||||||
std::fs::write(output, out).is_ok()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse(
|
|
||||||
input: &String,
|
|
||||||
debug_opts: &Vec<String>,
|
|
||||||
) -> Result<Box<dyn Document<'static>>, String> {
|
|
||||||
println!("Parsing {input}...");
|
println!("Parsing {input}...");
|
||||||
let parser = LangParser::default();
|
let parser = LangParser::default();
|
||||||
|
|
||||||
|
@ -108,12 +83,69 @@ fn parse(
|
||||||
}
|
}
|
||||||
|
|
||||||
if parser.has_error() {
|
if parser.has_error() {
|
||||||
return Err("Parsing failed aborted due to errors while parsing".to_string())
|
return Err("Parsing failed aborted due to errors while parsing".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(doc)
|
Ok(doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process(
|
||||||
|
target: Target,
|
||||||
|
files: Vec<String>,
|
||||||
|
db_path: &Option<String>,
|
||||||
|
debug_opts: &Vec<String>,
|
||||||
|
) -> Result<Vec<CompiledDocument>, String> {
|
||||||
|
let mut compiled = vec![];
|
||||||
|
|
||||||
|
let con = db_path
|
||||||
|
.as_ref()
|
||||||
|
.map_or(Connection::open_in_memory(), |path| Connection::open(path))
|
||||||
|
.map_err(|err| format!("Unable to open connection to the database: {err}"))?;
|
||||||
|
CompiledDocument::init_cache(&con)
|
||||||
|
.map_err(|err| format!("Failed to initialize cached document table: {err}"))?;
|
||||||
|
|
||||||
|
for file in files {
|
||||||
|
let meta = std::fs::metadata(&file)
|
||||||
|
.map_err(|err| format!("Failed to get metadata for `{file}`: {err}"))?;
|
||||||
|
|
||||||
|
let modified = meta
|
||||||
|
.modified()
|
||||||
|
.map_err(|err| format!("Unable to query modification time for `{file}`: {err}"))?;
|
||||||
|
|
||||||
|
let parse_and_compile = || -> Result<CompiledDocument, String> {
|
||||||
|
// Parse
|
||||||
|
let doc = parse(&file, debug_opts)?;
|
||||||
|
|
||||||
|
// Compile
|
||||||
|
let compiler = Compiler::new(target, db_path.clone());
|
||||||
|
let mut compiled = compiler.compile(&*doc);
|
||||||
|
|
||||||
|
// Insert into cache
|
||||||
|
compiled.mtime = modified.duration_since(UNIX_EPOCH).unwrap().as_secs();
|
||||||
|
compiled.insert_cache(&con).map_err(|err| {
|
||||||
|
format!("Failed to insert compiled document from `{file}` into cache: {err}")
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(compiled)
|
||||||
|
};
|
||||||
|
|
||||||
|
let cdoc = match CompiledDocument::from_cache(&con, &file) {
|
||||||
|
Some(compiled) => {
|
||||||
|
if compiled.mtime < modified.duration_since(UNIX_EPOCH).unwrap().as_secs() {
|
||||||
|
parse_and_compile()?
|
||||||
|
} else {
|
||||||
|
compiled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => parse_and_compile()?,
|
||||||
|
};
|
||||||
|
|
||||||
|
compiled.push(cdoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(compiled)
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
let program = args[0].clone();
|
let program = args[0].clone();
|
||||||
|
@ -177,8 +209,7 @@ fn main() -> ExitCode {
|
||||||
let debug_opts = matches.opt_strs("z");
|
let debug_opts = matches.opt_strs("z");
|
||||||
let db_path = matches.opt_str("d");
|
let db_path = matches.opt_str("d");
|
||||||
|
|
||||||
let mut docs = vec![];
|
let mut files = vec![];
|
||||||
|
|
||||||
if input_meta.is_dir() {
|
if input_meta.is_dir() {
|
||||||
if db_path.is_none() {
|
if db_path.is_none() {
|
||||||
eprintln!("Please specify a database (-d) for directory mode.");
|
eprintln!("Please specify a database (-d) for directory mode.");
|
||||||
|
@ -221,46 +252,53 @@ fn main() -> ExitCode {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
match parse(&path, &debug_opts)
|
files.push(path);
|
||||||
{
|
|
||||||
Ok(doc) => docs.push(doc),
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("{e}");
|
|
||||||
return ExitCode::FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match parse(&input, &debug_opts)
|
files.push(input);
|
||||||
{
|
|
||||||
Ok(doc) => docs.push(doc),
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("{e}");
|
|
||||||
return ExitCode::FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build navigation
|
// Parse, compile using the cache
|
||||||
let navigation = match create_navigation(&docs)
|
let compiled = match process(Target::HTML, files, &db_path, &debug_opts) {
|
||||||
{
|
Ok(compiled) => compiled,
|
||||||
Ok(nav) => nav,
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("{e}");
|
eprintln!("{e}");
|
||||||
return ExitCode::FAILURE;
|
return ExitCode::FAILURE;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("{navigation:#?}");
|
// Build navigation
|
||||||
|
let navigation = match create_navigation(&compiled) {
|
||||||
let multi_mode = input_meta.is_dir();
|
Ok(nav) => nav,
|
||||||
for doc in docs
|
Err(e) => {
|
||||||
{
|
eprintln!("{e}");
|
||||||
if !compile(Target::HTML, &doc, &output, &db_path, &navigation, multi_mode)
|
|
||||||
{
|
|
||||||
eprintln!("Compilation failed, processing aborted");
|
|
||||||
return ExitCode::FAILURE;
|
return ExitCode::FAILURE;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
let compiled_navigation = navigation.compile(Target::HTML);
|
||||||
|
|
||||||
|
// Output
|
||||||
|
for doc in compiled {
|
||||||
|
let out_path = match doc
|
||||||
|
.get_variable("compiler.output")
|
||||||
|
.or(input_meta.is_file().then_some(&output))
|
||||||
|
{
|
||||||
|
Some(path) => path.clone(),
|
||||||
|
None => {
|
||||||
|
eprintln!("Unable to get output file for `{}`", doc.input);
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let file = std::fs::File::create(output.clone() + "/" + out_path.as_str()).unwrap();
|
||||||
|
let mut writer = BufWriter::new(file);
|
||||||
|
|
||||||
|
write!(
|
||||||
|
writer,
|
||||||
|
"{}{}{}{}",
|
||||||
|
doc.header, compiled_navigation, doc.body, doc.footer
|
||||||
|
);
|
||||||
|
writer.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExitCode::SUCCESS;
|
return ExitCode::SUCCESS;
|
||||||
|
|
Loading…
Reference in a new issue