]> git.huck.website - metaforge.git/commitdiff
refactored: options from hashtable, incorporated parallel flag
authorHuck Boles <huck@huck.website>
Sun, 21 May 2023 17:37:41 +0000 (12:37 -0500)
committerHuck Boles <huck@huck.website>
Sun, 21 May 2023 17:37:41 +0000 (12:37 -0500)
Cargo.lock
src/dir.rs [new file with mode: 0644]
src/metafile/dir.rs
src/options.rs

index 82c8970af6d113fadccc2167552492e04ecb38f5..a52e12c3457efdc22cf2d0092ad92756a347baad 100644 (file)
@@ -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 (file)
index 0000000..f807902
--- /dev/null
@@ -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<MetaFile<'a>>,
+    dirs: Vec<DirNode<'a>>,
+}
+
+impl<'a> DirNode<'a> {
+    pub fn build(path: PathBuf, opts: &'a Options) -> Result<Self> {
+        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<MetaFile> = Vec::new();
+        let dirs: Vec<DirNode> = 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(())
+    }
+}
index c24654d1142e3dc5c40d8245350f94c3899ed350..b12d8f1e9baa84807b831cae8e6442426b4c2098 100644 (file)
@@ -1,5 +1,6 @@
 use crate::{MetaError, Options};
 use eyre::Result;
+use rayon::prelude::*;
 use std::{fs, path::PathBuf};
 
 use super::*;
index b66300acd47e089542820bfdbab2a8a80971119f..0d771cba0798b17253f80324a625ecb16a981584 100644 (file)
@@ -23,6 +23,9 @@ pub struct Opts {
     /// only build a single file
     #[arg(short, long, value_name = "FILENAME")]
     pub file: Option<String>,
+    /// 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<crate::Opts> 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)
     }