From 9c48c879989596eb96f4fbee27a504b8afd8d452 Mon Sep 17 00:00:00 2001 From: Huck Boles Date: Sun, 21 May 2023 12:37:41 -0500 Subject: [PATCH] refactored: options from hashtable, incorporated parallel flag --- Cargo.lock | 5 ++- src/dir.rs | 101 ++++++++++++++++++++++++++++++++++++++++++++ src/metafile/dir.rs | 1 + src/options.rs | 54 ++++++++++++----------- 4 files changed, 135 insertions(+), 26 deletions(-) create mode 100644 src/dir.rs diff --git a/Cargo.lock b/Cargo.lock index 82c8970..a52e12c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -492,9 +492,9 @@ checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "linux-raw-sys" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "log" @@ -524,6 +524,7 @@ dependencies = [ "pandoc", "pest", "pest_derive", + "rayon", "thiserror", ] diff --git a/src/dir.rs b/src/dir.rs new file mode 100644 index 0000000..f807902 --- /dev/null +++ b/src/dir.rs @@ -0,0 +1,101 @@ +use crate::{MetaError, Options}; +use eyre::Result; +use rayon::prelude::*; +use std::{fs, path::PathBuf}; + +use super::*; + +#[derive(Debug, Clone)] +pub struct DirNode<'a> { + path: PathBuf, + opts: &'a Options, + global: MetaFile<'a>, + files: Vec>, + dirs: Vec>, +} + +impl<'a> DirNode<'a> { + pub fn build(path: PathBuf, opts: &'a Options) -> Result { + assert!(path.is_dir() && path.exists()); + + // copy over directory structure from source dir + let build_dir = opts.build.join(path.strip_prefix(&opts.source)?); + if !build_dir.exists() { + fs::create_dir_all(build_dir)?; + } + + let files: Vec = Vec::new(); + let dirs: Vec = Vec::new(); + let global = MetaFile::new(opts); + + Ok(Self { + path, + opts, + global, + files, + dirs, + }) + } + + // parses all contained files and directories and pushes + // parsed structures into the files and directories vectors + pub fn map(&mut self, global: &'a MetaFile) -> Result<()> { + if self.opts.parallel {} + + for f in fs::read_dir(&self.path)? { + let file = f?.path(); + + if file.is_dir() { + let dir = DirNode::build(file, self.opts)?; + self.dirs.push(dir); + } else if file.file_name().and_then(|f| f.to_str()) == Some("default.meta") { + let mut new_global = MetaFile::build(file, self.opts)?; + new_global.merge(global); + self.global = new_global; + } else if file.extension().and_then(|f| f.to_str()) == Some("meta") { + let file = MetaFile::build(file, self.opts)?; + self.files.push(file) + } + } + + Ok(()) + } + + pub fn build_files(&mut self) -> Result<()> { + for file in self.files.iter_mut() { + file.merge(&self.global); + match file.construct() { + Ok(str) => { + fs::write(file.dest()?, str)?; + } + Err(e) => { + // print a line to stderr about failure but continue with other files + if self.opts.force { + eprintln!("ignoring {}: {}", file.path.display(), e); + continue; + } else { + // we raise an ignored error to quickly abort any file parsing + if let MetaError::Ignored = *e { + continue; + // anything else gets wrapped up and passed up the calling chain + } else { + return Err(e.into()); + } + } + } + } + } + Ok(()) + } + + pub fn build_dir(&'a mut self) -> Result<()> { + self.build_files()?; + + for dir in self.dirs.iter_mut() { + dir.map(&self.global)?; + dir.build_dir()?; + } + + Ok(()) + } +} diff --git a/src/metafile/dir.rs b/src/metafile/dir.rs index c24654d..b12d8f1 100644 --- a/src/metafile/dir.rs +++ b/src/metafile/dir.rs @@ -1,5 +1,6 @@ use crate::{MetaError, Options}; use eyre::Result; +use rayon::prelude::*; use std::{fs, path::PathBuf}; use super::*; diff --git a/src/options.rs b/src/options.rs index b66300a..0d771cb 100644 --- a/src/options.rs +++ b/src/options.rs @@ -23,6 +23,9 @@ pub struct Opts { /// only build a single file #[arg(short, long, value_name = "FILENAME")] pub file: Option, + /// parallel processing + #[arg(short, long, default_value_t = false)] + pub parallel: bool, /// create a new skeleton directory #[arg(long, default_value_t = false)] pub new: bool, @@ -62,6 +65,7 @@ pub struct Options { pub input: String, pub output: String, pub verbose: u8, + pub parallel: bool, pub quiet: bool, pub force: bool, pub undefined: bool, @@ -81,6 +85,7 @@ impl Options { input: String::default(), output: String::default(), verbose: 0, + parallel: false, quiet: false, force: false, undefined: false, @@ -103,46 +108,47 @@ impl TryFrom for Options { opts.clean = value.clean; opts.no_pandoc = value.no_pandoc; opts.new = value.new; + opts.parallel = value.parallel; - if let Some(root) = value.root.as_deref() { - opts.root = PathBuf::from(root).canonicalize()?; + opts.root = if let Some(root) = value.root.as_deref() { + PathBuf::from(root).canonicalize() } else { - opts.root = std::env::current_dir()?; - } + std::env::current_dir() + }?; - if let Some(source) = value.source.as_deref() { - opts.source = PathBuf::from(source).canonicalize()?; + opts.source = if let Some(source) = value.source.as_deref() { + PathBuf::from(source).canonicalize() } else { - opts.source = opts.root.join("source"); - } + Ok(opts.root.join("source")) + }?; - if let Some(build) = value.build.as_deref() { - opts.build = PathBuf::from(build).canonicalize()?; + opts.build = if let Some(build) = value.build.as_deref() { + PathBuf::from(build).canonicalize() } else { - opts.build = opts.root.join("build"); - } + Ok(opts.root.join("build")) + }?; - if let Some(pattern) = value.pattern.as_deref() { - opts.pattern = PathBuf::from(pattern).canonicalize()?; + opts.pattern = if let Some(pattern) = value.pattern.as_deref() { + PathBuf::from(pattern).canonicalize() } else { - opts.pattern = opts.root.join("pattern"); - } + Ok(opts.root.join("pattern")) + }?; if let Some(file) = value.file.as_deref() { opts.file = Some(PathBuf::from(file).canonicalize()?); } - if let Some(input) = value.input { - opts.input = input; + opts.input = if let Some(input) = value.input { + input } else { - opts.input = String::from("html"); - } + String::from("html") + }; - if let Some(output) = value.output { - opts.output = output; + opts.output = if let Some(output) = value.output { + output } else { - opts.output = String::from("markdown"); - } + String::from("markdown") + }; Ok(opts) } -- 2.45.2