From 398fbc7e1bdc8f01366b77080a6449576718652f Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Wed, 22 Aug 2018 00:13:11 -0500 Subject: [PATCH] FEATURE: Support limited help for the available converters. --- src/convert/env.rs | 4 +++ src/convert/exec.rs | 4 +++ src/convert/flags.rs | 4 +++ src/convert/json.rs | 4 +++ src/convert/mod.rs | 60 +++++++++++++++++++------------------------ src/convert/traits.rs | 1 + src/main.rs | 58 ++++++++++++++++++++++++----------------- 7 files changed, 78 insertions(+), 57 deletions(-) diff --git a/src/convert/env.rs b/src/convert/env.rs index 216689b..b4eda68 100644 --- a/src/convert/env.rs +++ b/src/convert/env.rs @@ -91,4 +91,8 @@ impl Converter for EnvConverter { fn file_ext(&self) -> String { String::from("env") } + + fn description(&self) -> String { + "Convert ucg Vals into environment variables.".to_string() + } } diff --git a/src/convert/exec.rs b/src/convert/exec.rs index 8714c18..6d23fa2 100644 --- a/src/convert/exec.rs +++ b/src/convert/exec.rs @@ -186,6 +186,10 @@ impl Converter for ExecConverter { fn file_ext(&self) -> String { String::from("sh") } + + fn description(&self) -> String { + "Convert ucg Vals into an bash script with \nenvironment variables set and command line arguments sent..".to_string() + } } #[cfg(test)] diff --git a/src/convert/flags.rs b/src/convert/flags.rs index 52d2793..fe1aba7 100644 --- a/src/convert/flags.rs +++ b/src/convert/flags.rs @@ -111,6 +111,10 @@ impl Converter for FlagConverter { fn file_ext(&self) -> String { String::from("txt") } + + fn description(&self) -> String { + "Convert ucg Vals into command line flags.".to_string() + } } // We need some unit tests for this now :D diff --git a/src/convert/json.rs b/src/convert/json.rs index d4a966f..efa8dbb 100644 --- a/src/convert/json.rs +++ b/src/convert/json.rs @@ -92,4 +92,8 @@ impl Converter for JsonConverter { fn file_ext(&self) -> String { String::from("json") } + + fn description(&self) -> String { + "Convert ucg Vals into valid json.".to_string() + } } diff --git a/src/convert/mod.rs b/src/convert/mod.rs index 78433ab..540ce45 100644 --- a/src/convert/mod.rs +++ b/src/convert/mod.rs @@ -19,54 +19,46 @@ pub mod flags; pub mod json; pub mod traits; -use std::io::Write; -use std::rc::Rc; - -use build::Val; +use std::collections::HashMap; /// ConverterRunner knows how to run a given converter on a Val. -pub struct ConverterRunner { - converter: Box, +pub struct ConverterRegistry { + converters: HashMap>, } -impl ConverterRunner { +impl ConverterRegistry { /// new creates a new ConverterRunner with a converter for the provided output target. /// /// * flags /// * json /// * env /// * exec - pub fn new(typ: &str) -> Result { - if typ == "flags" { - return Ok(ConverterRunner { - converter: Box::new(flags::FlagConverter::new()), - }); + fn new() -> Self { + ConverterRegistry { + converters: HashMap::new(), } - if typ == "json" { - return Ok(ConverterRunner { - converter: Box::new(json::JsonConverter::new()), - }); - } - if typ == "env" { - return Ok(ConverterRunner { - converter: Box::new(env::EnvConverter::new()), - }); - } - if typ == "exec" { - return Ok(ConverterRunner { - converter: Box::new(exec::ExecConverter::new()), - }); - } - return Err(format!("Unknown Target output type: {}", typ)); } - /// convert runs the Converter on a Val and writes the output to the provided writer. - pub fn convert(&self, v: Rc, mut w: Box) -> traits::Result { - self.converter.convert(v, &mut w) + pub fn make_registry() -> Self { + let mut registry = Self::new(); + registry.register("json", Box::new(json::JsonConverter::new())); + registry.register("env", Box::new(env::EnvConverter::new())); + registry.register("flags", Box::new(flags::FlagConverter::new())); + registry.register("exec", Box::new(exec::ExecConverter::new())); + registry } - /// ext returns the expected file extension for this conversion. - pub fn ext(&self) -> String { - self.converter.file_ext() + pub fn register>(&mut self, typ: S, converter: Box) { + self.converters.insert(typ.into(), converter); } + + pub fn get_converter(&self, typ: &str) -> Option<&traits::Converter> { + self.converters.get(typ).map(|c| c.as_ref()) + } + + pub fn get_converter_list(&self) -> Vec<(&String, &Box)> { + self.converters.iter().collect() + } + + // TODO(jwall): Support converter help descriptions. } diff --git a/src/convert/traits.rs b/src/convert/traits.rs index f873bfa..9a8bdbf 100644 --- a/src/convert/traits.rs +++ b/src/convert/traits.rs @@ -27,4 +27,5 @@ pub type Result = result::Result<(), Box>; pub trait Converter { fn convert(&self, vs: Rc, w: &mut Write) -> Result; fn file_ext(&self) -> String; + fn description(&self) -> String; } diff --git a/src/main.rs b/src/main.rs index 801325f..23ccd7c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,7 +27,7 @@ use ucglib::build; use ucglib::build::assets::{Cache, MemoryCache}; use ucglib::build::Val; use ucglib::convert::traits; -use ucglib::convert::ConverterRunner; +use ucglib::convert::ConverterRegistry; // TODO(jwall): List the target output types automatically. fn do_flags<'a>() -> clap::ArgMatches<'a> { @@ -54,22 +54,21 @@ fn do_flags<'a>() -> clap::ArgMatches<'a> { ) (@subcommand converters => (about: "list the available converters") - (@arg name: -c --converter-name +takes_value "Optionally print help for the provided converter") ) ).get_matches() } -fn run_converter(c: ConverterRunner, v: Rc, f: Option<&str>) -> traits::Result { - let file: Box = match f { +fn run_converter(c: &traits::Converter, v: Rc, f: Option<&str>) -> traits::Result { + let mut file: Box = match f { Some(f) => { let mut path_buf = PathBuf::from(f); - path_buf.set_extension(c.ext()); + path_buf.set_extension(c.file_ext()); let new_path = path_buf.to_str().unwrap(); Box::new(try!(File::create(&new_path))) } None => Box::new(io::stdout()), }; - c.convert(v, file) + c.convert(v, file.as_mut()) } fn build_file( @@ -101,7 +100,7 @@ fn do_validate(file: &str, cache: Rc>) -> bool { return true; } -fn do_compile(file: &str, cache: Rc>) -> bool { +fn do_compile(file: &str, cache: Rc>, registry: &ConverterRegistry) -> bool { println!("Building {}", file); let builder = match build_file(file, false, cache.clone()) { Ok(builder) => builder, @@ -117,14 +116,14 @@ fn do_compile(file: &str, cache: Rc>) -> bool { return false; } }; - match ConverterRunner::new(typ) { - Ok(converter) => { + match registry.get_converter(typ) { + Some(converter) => { run_converter(converter, val, Some(file)).unwrap(); eprintln!("Build successful"); process::exit(0); } - Err(msg) => { - eprintln!("{}", msg); + None => { + eprintln!("No such converter {}", typ); return false; } } @@ -135,6 +134,7 @@ fn visit_ucg_files( recurse: bool, validate: bool, cache: Rc>, + registry: &ConverterRegistry, ) -> Result> { let our_path = String::from(path.to_string_lossy()); let mut result = true; @@ -146,7 +146,9 @@ fn visit_ucg_files( let next_path = next_item.path(); let path_as_string = String::from(next_path.to_string_lossy()); if next_path.is_dir() && recurse { - if let Err(msg) = visit_ucg_files(&next_path, recurse, validate, cache.clone()) { + if let Err(msg) = + visit_ucg_files(&next_path, recurse, validate, cache.clone(), registry) + { eprintln!("Err 1: {}", msg); result = false; } @@ -159,7 +161,7 @@ fn visit_ucg_files( summary.push_str(format!("{} - PASS\n", path_as_string).as_str()) } } else if !validate { - if !do_compile(&path_as_string, cache.clone()) { + if !do_compile(&path_as_string, cache.clone(), registry) { result = false; } } @@ -173,7 +175,7 @@ fn visit_ucg_files( summary.push_str(format!("{} - PASS\n", &our_path).as_str()) } } else if !validate { - if !do_compile(&our_path, cache) { + if !do_compile(&our_path, cache, registry) { result = false; } } @@ -187,14 +189,15 @@ fn visit_ucg_files( fn main() { let app = do_flags(); let cache: Rc> = Rc::new(RefCell::new(MemoryCache::new())); + let registry = ConverterRegistry::make_registry(); if let Some(matches) = app.subcommand_matches("inspect") { let file = matches.value_of("INPUT").unwrap(); let sym = matches.value_of("sym"); let target = matches.value_of("target").unwrap(); let root = PathBuf::from(file); let mut builder = build::Builder::new(root.parent().unwrap(), cache); - match ConverterRunner::new(target) { - Ok(converter) => { + match registry.get_converter(target) { + Some(converter) => { // TODO(jwall): We should warn if this is a test file. let result = builder.build_file(file); if !result.is_ok() { @@ -218,8 +221,8 @@ fn main() { } } } - Err(msg) => { - eprintln!("{}", msg); + None => { + eprintln!("No such converter {}", target); process::exit(1); } } @@ -229,14 +232,14 @@ fn main() { let mut ok = true; if files.is_none() { let curr_dir = std::env::current_dir().unwrap(); - let ok = visit_ucg_files(curr_dir.as_path(), recurse, false, cache.clone()); + let ok = visit_ucg_files(curr_dir.as_path(), recurse, false, cache.clone(), ®istry); if let Ok(false) = ok { process::exit(1) } } for file in files.unwrap() { let pb = PathBuf::from(file); - if let Ok(false) = visit_ucg_files(&pb, recurse, false, cache.clone()) { + if let Ok(false) = visit_ucg_files(&pb, recurse, false, cache.clone(), ®istry) { ok = false; } } @@ -248,7 +251,7 @@ fn main() { let recurse = matches.is_present("recurse"); if files.is_none() { let curr_dir = std::env::current_dir().unwrap(); - let ok = visit_ucg_files(curr_dir.as_path(), recurse, true, cache.clone()); + let ok = visit_ucg_files(curr_dir.as_path(), recurse, true, cache.clone(), ®istry); if let Ok(false) = ok { process::exit(1) } @@ -257,7 +260,9 @@ fn main() { for file in files.unwrap() { let pb = PathBuf::from(file); if pb.is_dir() { - if let Ok(false) = visit_ucg_files(pb.as_path(), recurse, true, cache.clone()) { + if let Ok(false) = + visit_ucg_files(pb.as_path(), recurse, true, cache.clone(), ®istry) + { ok = false; } } else { @@ -284,6 +289,13 @@ fn main() { } process::exit(0); } else if let Some(_todo) = app.subcommand_matches("converters") { - // TODO(jwall): Flesh this command out. + println!("Available converters:"); + println!(""); + for (name, c) in registry.get_converter_list().iter() { + println!("- {}", name); + println!(" Description: {}", c.description()); + println!(" Output Extension: `.{}`", c.file_ext()); + println!(""); + } } }