]> git.huck.website - metaforge.git/commitdiff
metafile builder and helping functions
authorHuck Boles <huck@huck.website>
Fri, 5 May 2023 02:38:44 +0000 (21:38 -0500)
committerHuck Boles <huck@huck.website>
Fri, 5 May 2023 02:38:44 +0000 (21:38 -0500)
src/filetype.rs [new file with mode: 0644]
src/filetype/builder.rs [new file with mode: 0644]
src/filetype/metafile.rs [moved from src/metafile.rs with 50% similarity]
src/filetype/structs.rs [new file with mode: 0644]
src/lib.rs

diff --git a/src/filetype.rs b/src/filetype.rs
new file mode 100644 (file)
index 0000000..6727256
--- /dev/null
@@ -0,0 +1,7 @@
+mod builder;
+mod metafile;
+mod structs;
+
+pub use builder::*;
+pub use metafile::*;
+pub use structs::*;
diff --git a/src/filetype/builder.rs b/src/filetype/builder.rs
new file mode 100644 (file)
index 0000000..0ea4c55
--- /dev/null
@@ -0,0 +1,99 @@
+use crate::{parse_file, MetaFile, RootDirs, Source, Substitution};
+use color_eyre::Result;
+use std::{
+    collections::HashMap,
+    path::{Path, PathBuf},
+};
+
+pub fn build_metafile(file: &MetaFile, dirs: &RootDirs, path: &Path) -> Result<()> {
+    Ok(std::fs::write(
+        find_dest(path, dirs)?,
+        metafile_to_string(file, dirs, None)?,
+    )?)
+}
+
+fn metafile_to_string(file: &MetaFile, dirs: &RootDirs, name: Option<&str>) -> Result<String> {
+    let mut output = String::default();
+
+    for section in file.source.iter() {
+        match section {
+            // concatenate any char sequences
+            Source::Str(str) => output.push_str(str),
+            // expand all variables and recursively expand patterns
+            Source::Sub(sub) => {
+                let expanded = match sub {
+                    Substitution::Variable(key) => file
+                        .get_var(key)
+                        .map(|val| val.to_string())
+                        .unwrap_or_default(),
+                    Substitution::Pattern(key) => get_pattern(key, file, dirs)?,
+                    // comments have already been removed at this point,
+                    // so we use them to mark keys for array substitution
+                    Substitution::Array(key) => format!("-{{{key}}}"),
+                };
+                output.push_str(&expanded);
+            }
+        }
+    }
+
+    // deal with arrays
+    Ok(expand_arrays(output, file, name)?)
+}
+
+fn get_pattern(key: &str, file: &MetaFile, dirs: &RootDirs) -> Result<String> {
+    let filename = match file.get_pat(key) {
+        Some(file) => file,
+        None => "default",
+    };
+
+    let pattern_path = key.replace('.', "/") + "/" + filename;
+    let mut path = dirs.pattern.join(pattern_path).canonicalize()?;
+    path.set_extension(".meta");
+    let pattern = parse_file(path.to_str().unwrap_or_default())?;
+    metafile_to_string(&pattern, dirs, Some(key))
+}
+
+fn find_dest(path: &Path, dirs: &RootDirs) -> Result<PathBuf> {
+    let path = path.to_string_lossy().to_string().replace(
+        dirs.source.to_str().unwrap_or_default(),
+        dirs.build.to_str().unwrap_or_default(),
+    );
+
+    Ok(PathBuf::from(path).canonicalize()?)
+}
+
+fn expand_arrays(output: String, file: &MetaFile, name: Option<&str>) -> Result<String> {
+    let map: HashMap<&str, &[&str]> = file
+        .source
+        .iter()
+        // filter out arrays from source vec
+        .filter_map(|section| {
+            if let Source::Sub(Substitution::Array(array)) = section {
+                Some(array)
+            } else {
+                None
+            }
+        })
+        // make a hash map of keys in the source to previously defined arrays
+        .map(|array| {
+            let key = name.unwrap_or_default().to_owned() + "." + array;
+            let value = file.get_arr(&key).unwrap_or_default();
+            (*array, value)
+        })
+        .collect();
+
+    let mut expanded = String::new();
+    // loop to duplicate the output template for each array member
+    for i in 0.. {
+        // get a fresh copy of the file
+        let mut str = output.clone();
+        // replace each key in the file
+        for (key, val) in map.iter() {
+            str = str.replace(&format!("-{{{key}}}"), val[i]);
+        }
+        // concatenate to final file
+        expanded.push_str(&str);
+    }
+
+    Ok(expanded)
+}
similarity index 50%
rename from src/metafile.rs
rename to src/filetype/metafile.rs
index 8a9248a5fdf43a3528ab474846797eda6ce0472b..adc24f6f81130d60514516b09e014215426ae30d 100644 (file)
@@ -1,4 +1,5 @@
-use std::{collections::HashMap, path::PathBuf};
+use crate::Source;
+use std::collections::HashMap;
 
 #[derive(Debug, Default, Clone)]
 pub struct MetaFile<'a> {
@@ -9,8 +10,8 @@ pub struct MetaFile<'a> {
 }
 
 impl<'a> MetaFile<'a> {
-    pub fn new() -> MetaFile<'a> {
-        MetaFile {
+    pub fn new() -> Self {
+        Self {
             variables: HashMap::new(),
             arrays: HashMap::new(),
             patterns: HashMap::new(),
@@ -30,31 +31,3 @@ impl<'a> MetaFile<'a> {
         self.patterns.get(key).copied()
     }
 }
-
-#[macro_export]
-macro_rules! source (
-    (var($s:expr)) => { Source::Sub(Substitution::Variable($s))};
-    (arr($s:expr)) => { Source::Sub(Substitution::Array($s))};
-    (pat($s:expr)) => { Source::Sub(Substitution::Pattern($s))};
-    ($s:expr) => { Source::Str($s)};
-);
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum Source<'a> {
-    Str(&'a str),
-    Sub(Substitution<'a>),
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum Substitution<'a> {
-    Variable(&'a str),
-    Array(&'a str),
-    Pattern(&'a str),
-}
-
-#[derive(Debug, Clone)]
-pub struct RootDirs {
-    pub source: PathBuf,
-    pub build: PathBuf,
-    pub pattern: PathBuf,
-}
diff --git a/src/filetype/structs.rs b/src/filetype/structs.rs
new file mode 100644 (file)
index 0000000..57b8945
--- /dev/null
@@ -0,0 +1,39 @@
+use std::path::PathBuf;
+
+#[macro_export]
+macro_rules! source (
+    (var($s:expr)) => { Source::Sub(Substitution::Variable($s))};
+    (arr($s:expr)) => { Source::Sub(Substitution::Array($s))};
+    (pat($s:expr)) => { Source::Sub(Substitution::Pattern($s))};
+    ($s:expr) => { Source::Str($s)};
+);
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum Source<'a> {
+    Str(&'a str),
+    Sub(Substitution<'a>),
+}
+
+#[derive(Debug, Clone, PartialEq)]
+pub enum Substitution<'a> {
+    Variable(&'a str),
+    Array(&'a str),
+    Pattern(&'a str),
+}
+
+#[derive(Debug, Clone)]
+pub struct RootDirs {
+    pub source: PathBuf,
+    pub build: PathBuf,
+    pub pattern: PathBuf,
+}
+
+impl RootDirs {
+    pub fn new() -> Self {
+        Self {
+            source: PathBuf::new(),
+            build: PathBuf::new(),
+            pattern: PathBuf::new(),
+        }
+    }
+}
index 7b33542656ef7ffde6587a46d7e3123b3989e1d9..aaa324ced026c9f4a91069aa8c4e5e978938ec56 100644 (file)
@@ -2,10 +2,10 @@ extern crate pest;
 #[macro_use]
 extern crate pest_derive;
 
-mod metafile;
+mod filetype;
 mod parser;
 
-pub use metafile::*;
+pub use filetype::*;
 pub use parser::*;
 
 #[cfg(test)]