From e1c5746aabc81985be1cc4fb1d70a37cff3dfac0 Mon Sep 17 00:00:00 2001 From: Huck Boles Date: Thu, 11 May 2023 11:27:34 -0500 Subject: [PATCH] builds dirs --- src/filetype/builder.rs | 81 ++++++++++++++----------- src/main.rs | 32 +++++++--- src/options.rs | 22 +++++-- src/tests/test_metafile.rs | 2 +- test_site/pattern/test/pattern.meta | 2 +- test_site/source/sub_dir/deep/deep.meta | 14 +++++ test_site/source/sub_dir/sub_dir.meta | 5 ++ tests/metafile_builder.rs | 2 +- 8 files changed, 110 insertions(+), 50 deletions(-) create mode 100644 test_site/source/sub_dir/deep/deep.meta create mode 100644 test_site/source/sub_dir/sub_dir.meta diff --git a/src/filetype/builder.rs b/src/filetype/builder.rs index 982030a..f9de49d 100644 --- a/src/filetype/builder.rs +++ b/src/filetype/builder.rs @@ -1,4 +1,4 @@ -use crate::{parse_file, MetaFile, Options, Source, Substitution}; +use crate::{log, parse_file, MetaFile, Options, Source, Substitution}; use color_eyre::{ eyre::bail, eyre::{eyre, WrapErr}, @@ -11,16 +11,19 @@ use std::{ path::{Path, PathBuf}, }; -pub fn build_metafile(path: &Path, dirs: &Options) -> Result<()> { - let file = fs::read_to_string(path) - .wrap_err_with(|| eyre!("failed to read: {}\n", path.to_string_lossy()))?; - let file = parse_file(&file) - .wrap_err_with(|| eyre!("failed to parse: {}\n", path.to_string_lossy()))?; +pub fn build_metafile(path: &Path, opts: &Options) -> Result<()> { + log!(opts, format!("\t{}", path.display()), 1); + let file = + fs::read_to_string(path).wrap_err_with(|| eyre!("failed to read: {}\n", path.display()))?; - let html = get_source_html(&file, dirs) - .wrap_err_with(|| eyre!("failed converting to html: {}\n", path.to_string_lossy()))?; + log!(opts, "\tparsing", 2); + let file = + parse_file(&file).wrap_err_with(|| eyre!("failed to parse: {}\n", path.display()))?; - let pattern = get_pattern("base", &file, dirs).wrap_err("failed to get base pattern\n")?; + let html = get_source_html(&file, opts) + .wrap_err_with(|| eyre!("failed converting to html: {}\n", path.display()))?; + + let pattern = get_pattern("base", &file, opts).wrap_err("failed to get base pattern\n")?; let mut base = parse_file(&pattern).wrap_err("failed to parse base pattern\n")?; base.variables = file.variables; @@ -29,23 +32,20 @@ pub fn build_metafile(path: &Path, dirs: &Options) -> Result<()> { base.patterns.insert("SOURCE", &html); - let output = metafile_to_string(&base, dirs, Some("base")) - .wrap_err_with(|| eyre!("failed to build: {}\n", path.to_string_lossy()))?; + let output = metafile_to_string(&base, opts, Some("base")) + .wrap_err_with(|| eyre!("failed to build: {}\n", path.display()))?; - let dest = find_dest(path, dirs).wrap_err_with(|| { - format!( - "could not find destination file: {}\n", - path.to_string_lossy() - ) - })?; + log!(opts, "\twriting", 2); + let dest = find_dest(path, opts) + .wrap_err_with(|| format!("could not find destination file: {}\n", path.display()))?; // want newline to end file fs::write(&dest, output + "\n") - .wrap_err_with(|| eyre!("could not write to: {}\n", dest.to_string_lossy()))?; + .wrap_err_with(|| eyre!("could not write to: {}\n", dest.display()))?; Ok(()) } -pub fn metafile_to_string(file: &MetaFile, dirs: &Options, name: Option<&str>) -> Result { +pub fn metafile_to_string(file: &MetaFile, opts: &Options, name: Option<&str>) -> Result { let mut output = String::default(); let mut arrays = false; @@ -64,7 +64,7 @@ pub fn metafile_to_string(file: &MetaFile, dirs: &Options, name: Option<&str>) - .filter(|val| *val != "BLANK" && *val != "DEFAULT") .map(|val| val.to_string()) .unwrap_or_default(), - Substitution::Pattern(key) => get_pattern(key, file, dirs) + Substitution::Pattern(key) => get_pattern(key, file, opts) .wrap_err_with(|| eyre!("could not find pattern for: {}\n", key))?, // comments have already been removed at this point, // so we use them to mark keys for array substitution @@ -79,22 +79,26 @@ pub fn metafile_to_string(file: &MetaFile, dirs: &Options, name: Option<&str>) - } if arrays { + log!(opts, "\t\t\texpanding arrays", 4); expand_arrays(output, file, name) } else { Ok(output) } } -fn get_source_html(file: &MetaFile, dirs: &Options) -> Result { - let file = metafile_to_string(file, dirs, Some("SOURCE")).wrap_err("failed building source")?; +fn get_source_html(file: &MetaFile, opts: &Options) -> Result { + log!(opts, "\tbuilding source", 2); + let file = metafile_to_string(file, opts, Some("SOURCE")).wrap_err("failed building source")?; let mut pandoc = Pandoc::new(); + log!(opts, "\t\tsetting up pandoc", 3); pandoc .set_input(InputKind::Pipe(file)) .set_output(OutputKind::Pipe) .set_input_format(InputFormat::Markdown, vec![]) .set_output_format(OutputFormat::Html, vec![]); + log!(opts, "\t\texecuting pandoc command", 3); if let Ok(PandocOutput::ToBuffer(html)) = pandoc.execute() { Ok(html) } else { @@ -102,14 +106,16 @@ fn get_source_html(file: &MetaFile, dirs: &Options) -> Result { } } -fn get_pattern(key: &str, file: &MetaFile, dirs: &Options) -> Result { +fn get_pattern(key: &str, file: &MetaFile, opts: &Options) -> Result { // SOURCE is already expanded in the initial build_metafile() call // we just need to return that if key == "SOURCE" { + log!(opts, "\t\t\treturning SOURCE", 4); let source = file.patterns.get("SOURCE").unwrap_or(&""); return Ok(source.to_string()); } + log!(opts, format!("\t\tpattern: {}", key), 3); // anything not defined should have a default.meta file to fall back to let mut filename = file.get_pat(key).unwrap_or("default"); @@ -117,49 +123,56 @@ fn get_pattern(key: &str, file: &MetaFile, dirs: &Options) -> Result { // parsing/expansion so we can build and convert source to html // we just want to return the string right now if key == "base" { + log!(opts, "\t\t\treturning base", 4); let pattern_path = key.to_string() + "/" + filename; - let mut path = dirs.pattern.join(pattern_path); + let mut path = opts.pattern.join(pattern_path); path.set_extension("meta"); let base = fs::read_to_string(&path) - .wrap_err_with(|| eyre!("could not read: {}\n", path.to_string_lossy()))?; + .wrap_err_with(|| eyre!("could not read: {}\n", path.display()))?; return Ok(base); } // BLANK returns nothing, so no more processing needs to be done if filename == "BLANK" { + log!(opts, format!("\t\t\treturning blank: {}", key), 4); return Ok(String::new()); }; // DEFAULT override for variables defined higher in chain if filename == "DEFAULT" { + log!(opts, "\t\t\tdefault pattern", 4); filename = "default"; } + log!(opts, "\t\t\tbuilding path from key", 4); let pattern_path = key.replace('.', "/") + "/" + filename; - let mut path = dirs.pattern.join(pattern_path); + let mut path = opts.pattern.join(pattern_path); path.set_extension("meta"); + log!(opts, "\t\t\tparsing file", 4); let pattern = &fs::read_to_string(&path) - .wrap_err_with(|| eyre!("could not read: {}\n", path.to_string_lossy()))?; - let mut pattern = parse_file(pattern) - .wrap_err_with(|| eyre!("could not parse: {}\n", path.to_string_lossy()))?; + .wrap_err_with(|| eyre!("could not read: {}\n", path.display()))?; + let mut pattern = + parse_file(pattern).wrap_err_with(|| eyre!("could not parse: {}\n", path.display()))?; // copy over maps for expanding contained variables pattern.variables = file.variables.clone(); pattern.arrays = file.arrays.clone(); pattern.patterns = file.patterns.clone(); - metafile_to_string(&pattern, dirs, Some(key)) + log!(opts, "\t\t\tbuilding pattern", 4); + metafile_to_string(&pattern, opts, Some(key)) } -fn find_dest(path: &Path, dirs: &Options) -> Result { - let source = dirs.source.to_string_lossy(); - let build = dirs.build.to_string_lossy(); +fn find_dest(path: &Path, opts: &Options) -> Result { + log!(opts, "\t\tfinding destination", 3); + let source = opts.source.to_string_lossy(); + let build = opts.build.to_string_lossy(); let path = path .canonicalize() - .wrap_err_with(|| eyre!("could not get absolute path: {}\n", path.to_string_lossy()))?; + .wrap_err_with(|| eyre!("could not get absolute path: {}\n", path.display()))?; let path = path.to_string_lossy(); let path = path.replace(&*source, &*build); let mut path = PathBuf::from(path); diff --git a/src/main.rs b/src/main.rs index 2146e62..a76ea7e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ -use color_eyre::{eyre::bail, Result}; -use metaforge::{build_metafile, parse_opts}; +use color_eyre::{eyre::eyre, Result}; +use metaforge::{build_metafile, log, parse_opts}; use std::path::PathBuf; use walkdir::WalkDir; @@ -8,23 +8,41 @@ fn main() -> Result<()> { let opts = parse_opts()?; + log!(opts, "finding files", 2); let files: Vec = WalkDir::new(&opts.source) .into_iter() - .filter_map(|file| file.ok()) - .filter(|file| file.file_type().is_file()) - .map(|file| file.into_path()) + .filter_map(|file| { + if file.as_ref().ok()?.file_type().is_dir() { + // need to create directories in build dir + let path = file.unwrap().into_path(); + let path = path.strip_prefix(&opts.source).ok()?; + let path = opts.build.join(path); + log!(opts, format!("\tcreating dir: {}", path.display()), 3); + std::fs::create_dir(path).ok()?; + // don't need them for any further operations so we filter them out + None + } else { + if let Ok(file) = file { + log!(opts, format!("\tadding file: {}", file.path().display()), 3); + Some(file.into_path()) + } else { + None + } + } + }) .collect(); + log!(opts, "building files", 2); for file in files.iter() { match build_metafile(file, &opts) { Ok(_) => continue, Err(e) => { if opts.force { // print a line to stderr about failure but continue with other files - eprintln!("error in {}: {}", file.to_string_lossy(), e); + eprintln!("{}: {}", file.display(), e); continue; } else { - bail!("error in {}: {}", file.to_string_lossy(), e); + return Err(e.wrap_err(eyre!("{}:", file.display()))); } } } diff --git a/src/options.rs b/src/options.rs index 5c22db6..18afa9c 100644 --- a/src/options.rs +++ b/src/options.rs @@ -20,10 +20,11 @@ pub struct Opts { /// Pattern directory [CURRENT_DIR/pattern] #[arg(short, long, value_name = "PATTERN_DIR")] pattern: Option, - /// Extra output [false] - #[arg(short, long, default_value_t = false)] - verbose: bool, - /// Minimal output [false] + /// Enable extra output. + /// Repeated flags give more info + #[arg(short, long, action = clap::ArgAction::Count)] + verbose: u8, + /// Minimal output #[arg(short, long, default_value_t = false)] quiet: bool, /// Don't stop if a single file fails [false] @@ -40,7 +41,7 @@ pub struct Options { pub source: PathBuf, pub build: PathBuf, pub pattern: PathBuf, - pub verbose: bool, + pub verbose: u8, pub quiet: bool, pub force: bool, pub undefined: bool, @@ -53,7 +54,7 @@ impl Options { source: PathBuf::new(), build: PathBuf::new(), pattern: PathBuf::new(), - verbose: false, + verbose: 0, quiet: false, force: false, undefined: false, @@ -61,6 +62,15 @@ impl Options { } } +#[macro_export] +macro_rules! log { + ($opts:ident, $string:expr, $level:expr) => { + if $opts.verbose >= $level { + println!("{}", $string); + } + }; +} + pub fn parse_opts() -> Result { let opts = Opts::parse(); diff --git a/src/tests/test_metafile.rs b/src/tests/test_metafile.rs index f2f7c22..d9a4be6 100644 --- a/src/tests/test_metafile.rs +++ b/src/tests/test_metafile.rs @@ -69,7 +69,7 @@ fn parse_pattern_file() -> Result<()> { pattern_src.next(); assert_eq!(pattern_src.next().unwrap(), source!(arr("array"))); pattern_src.next(); - assert_eq!(pattern_src.next().unwrap(), source!(pat("pattern"))); + assert_eq!(pattern_src.next().unwrap(), source!(pat("test.blank"))); pattern_src.next(); assert_eq!(pattern_src.next(), None); diff --git a/test_site/pattern/test/pattern.meta b/test_site/pattern/test/pattern.meta index 0aaa7cc..7b54269 100644 --- a/test_site/pattern/test/pattern.meta +++ b/test_site/pattern/test/pattern.meta @@ -3,5 +3,5 @@
    @{array}
Other stuff diff --git a/test_site/source/sub_dir/deep/deep.meta b/test_site/source/sub_dir/deep/deep.meta new file mode 100644 index 0000000..cef3adb --- /dev/null +++ b/test_site/source/sub_dir/deep/deep.meta @@ -0,0 +1,14 @@ +${ + variable = 'GOOD' +} + +@{ + test.pattern.array = ["GOOD"] +} + +&{ + test = 'pattern' + test.blank = BLANK +} + +&{test} diff --git a/test_site/source/sub_dir/sub_dir.meta b/test_site/source/sub_dir/sub_dir.meta new file mode 100644 index 0000000..0cbb769 --- /dev/null +++ b/test_site/source/sub_dir/sub_dir.meta @@ -0,0 +1,5 @@ +${ + var = 'variable' +} + +This is a simple filler file with a single variable: ${var} diff --git a/tests/metafile_builder.rs b/tests/metafile_builder.rs index 4498a69..e83e0c7 100644 --- a/tests/metafile_builder.rs +++ b/tests/metafile_builder.rs @@ -40,7 +40,7 @@ fn build_options() -> Result { source: dir.join("source"), build: dir.join("build"), pattern: dir.join("pattern"), - verbose: false, + verbose: 0, quiet: false, force: false, undefined: false, -- 2.44.2