"pandoc",
"pest",
"pest_derive",
+ "rayon",
"thiserror",
]
[[package]]
name = "syn"
-version = "2.0.17"
+version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45b6ddbb36c5b969c182aec3c4a0bce7df3fbad4b77114706a49aacc80567388"
+checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
dependencies = [
"proc-macro2",
"quote",
eyre = "0.6"
pest = "2"
pest_derive = "2"
+rayon = "1.7"
[dev-dependencies]
criterion = "0.4"
[[bench]]
name = "pandoc"
harness = false
+
+[[bench]]
+name = "parallel"
+harness = false
--- /dev/null
+use criterion::{black_box, criterion_group, criterion_main, Criterion};
+
+pub fn parallel_build_dir(c: &mut Criterion) {
+ let dir = std::path::PathBuf::from("files/bench_site")
+ .canonicalize()
+ .unwrap();
+
+ let mut opts = metaforge::Options::new();
+ opts.root = dir.clone();
+ opts.source = dir.join("source");
+ opts.build = dir.join("build");
+ opts.pattern = dir.join("pattern");
+ opts.clean = true;
+ opts.parallel = true;
+
+ c.bench_function("build dir", |b| {
+ if opts.build.exists() {
+ std::fs::remove_dir_all(&opts.build).expect("clean build dir");
+ }
+
+ std::fs::create_dir(&opts.build).expect("create build dir");
+ b.iter(|| metaforge::build_site(black_box(&opts)).unwrap())
+ });
+}
+
+criterion_group! {
+ name = benches;
+ config = Criterion::default().sample_size(10).measurement_time(core::time::Duration::from_secs(135));
+ targets = parallel_build_dir
+}
+
+criterion_main!(benches);
mod error;
mod metafile;
mod options;
+mod parallel;
mod parser;
#[cfg(test)]
pub use error::*;
pub use metafile::*;
pub use options::*;
+pub use parallel::*;
pub use parser::*;
use clap::Parser;
};
source.map(&global_init)?;
- source.build_dir()
+
+ if opts.parallel {
+ source.par_dir()
+ } else {
+ source.build_dir()
+ }
}
pub fn single_file(opts: &Options) -> Result<String> {
--- /dev/null
+use crate::{DirNode, MetaError};
+use eyre::Result;
+use rayon::prelude::*;
+use std::fs;
+
+impl<'a> DirNode<'a> {
+ pub fn par_file(&mut self) -> Result<()> {
+ self.files.par_iter_mut().for_each(|file| {
+ file.merge(&self.global);
+ match file.construct() {
+ Ok(str) => {
+ fs::write(file.dest().unwrap(), str).unwrap();
+ }
+ Err(e) => {
+ // print a line to stderr about failure but continue with other files
+ if self.opts.force {
+ eprintln!("ignoring {}: {}", file.path.display(), e);
+ } else {
+ match *e {
+ MetaError::Ignored => {}
+ e => {
+ eprintln!("{}", file.path.display());
+ panic!("{}", e);
+ }
+ }
+ }
+ }
+ }
+ });
+ Ok(())
+ }
+
+ pub fn par_dir(&'a mut self) -> Result<()> {
+ self.build_files()?;
+
+ self.dirs.par_iter_mut().for_each(|dir| {
+ dir.map(&self.global).unwrap();
+ dir.build_dir().unwrap();
+ });
+
+ Ok(())
+ }
+}
Ok(())
}
+
+#[test]
+fn parallel_build_test_site() -> Result<()> {
+ let dir = std::path::PathBuf::from("files/test_site")
+ .canonicalize()
+ .unwrap();
+
+ let mut opts = metaforge::Options::new();
+ opts.root = dir.clone();
+ opts.source = dir.join("source");
+ opts.build = dir.join("build");
+ opts.pattern = dir.join("pattern");
+ opts.clean = true;
+ opts.parallel = true;
+
+ metaforge::build_site(&opts)?;
+
+ assert!(opts.build.join("unit_tests").exists());
+ assert!(opts
+ .build
+ .join("unit_tests/blank/blank_array.html")
+ .exists());
+ assert!(opts
+ .build
+ .join("unit_tests/expand/variable_in_source.html")
+ .exists());
+ assert!(opts
+ .build
+ .join("unit_tests/override/variable.html")
+ .exists());
+ assert!(opts.build.join("unit_tests/global/pattern.html").exists());
+
+ Ok(())
+}