From: Huck Boles Date: Fri, 5 May 2023 02:38:44 +0000 (-0500) Subject: metafile builder and helping functions X-Git-Url: https://git.huck.website/?a=commitdiff_plain;h=afe95a0102c9b3ca40f26b32b7fbc1a24edd5d36;p=metaforge.git metafile builder and helping functions --- diff --git a/src/filetype.rs b/src/filetype.rs new file mode 100644 index 0000000..6727256 --- /dev/null +++ b/src/filetype.rs @@ -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 index 0000000..0ea4c55 --- /dev/null +++ b/src/filetype/builder.rs @@ -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 { + 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 { + 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 { + 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 { + 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) +} diff --git a/src/metafile.rs b/src/filetype/metafile.rs similarity index 50% rename from src/metafile.rs rename to src/filetype/metafile.rs index 8a9248a..adc24f6 100644 --- a/src/metafile.rs +++ b/src/filetype/metafile.rs @@ -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 index 0000000..57b8945 --- /dev/null +++ b/src/filetype/structs.rs @@ -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(), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 7b33542..aaa324c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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)]