mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-25 18:49:50 -04:00
FEATURE: Support limited help for the available converters.
This commit is contained in:
parent
f9cdd4f3f6
commit
398fbc7e1b
@ -91,4 +91,8 @@ impl Converter for EnvConverter {
|
|||||||
fn file_ext(&self) -> String {
|
fn file_ext(&self) -> String {
|
||||||
String::from("env")
|
String::from("env")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn description(&self) -> String {
|
||||||
|
"Convert ucg Vals into environment variables.".to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,6 +186,10 @@ impl Converter for ExecConverter {
|
|||||||
fn file_ext(&self) -> String {
|
fn file_ext(&self) -> String {
|
||||||
String::from("sh")
|
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)]
|
#[cfg(test)]
|
||||||
|
@ -111,6 +111,10 @@ impl Converter for FlagConverter {
|
|||||||
fn file_ext(&self) -> String {
|
fn file_ext(&self) -> String {
|
||||||
String::from("txt")
|
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
|
// We need some unit tests for this now :D
|
||||||
|
@ -92,4 +92,8 @@ impl Converter for JsonConverter {
|
|||||||
fn file_ext(&self) -> String {
|
fn file_ext(&self) -> String {
|
||||||
String::from("json")
|
String::from("json")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn description(&self) -> String {
|
||||||
|
"Convert ucg Vals into valid json.".to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,54 +19,46 @@ pub mod flags;
|
|||||||
pub mod json;
|
pub mod json;
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
|
|
||||||
use std::io::Write;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use build::Val;
|
|
||||||
|
|
||||||
/// ConverterRunner knows how to run a given converter on a Val.
|
/// ConverterRunner knows how to run a given converter on a Val.
|
||||||
pub struct ConverterRunner {
|
pub struct ConverterRegistry {
|
||||||
converter: Box<traits::Converter>,
|
converters: HashMap<String, Box<traits::Converter>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConverterRunner {
|
impl ConverterRegistry {
|
||||||
/// new creates a new ConverterRunner with a converter for the provided output target.
|
/// new creates a new ConverterRunner with a converter for the provided output target.
|
||||||
///
|
///
|
||||||
/// * flags
|
/// * flags
|
||||||
/// * json
|
/// * json
|
||||||
/// * env
|
/// * env
|
||||||
/// * exec
|
/// * exec
|
||||||
pub fn new(typ: &str) -> Result<Self, String> {
|
fn new() -> Self {
|
||||||
if typ == "flags" {
|
ConverterRegistry {
|
||||||
return Ok(ConverterRunner {
|
converters: HashMap::new(),
|
||||||
converter: Box::new(flags::FlagConverter::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 make_registry() -> Self {
|
||||||
pub fn convert(&self, v: Rc<Val>, mut w: Box<Write>) -> traits::Result {
|
let mut registry = Self::new();
|
||||||
self.converter.convert(v, &mut w)
|
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 register<S: Into<String>>(&mut self, typ: S, converter: Box<traits::Converter>) {
|
||||||
pub fn ext(&self) -> String {
|
self.converters.insert(typ.into(), converter);
|
||||||
self.converter.file_ext()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<traits::Converter>)> {
|
||||||
|
self.converters.iter().collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jwall): Support converter help descriptions.
|
||||||
}
|
}
|
||||||
|
@ -27,4 +27,5 @@ pub type Result = result::Result<(), Box<Error>>;
|
|||||||
pub trait Converter {
|
pub trait Converter {
|
||||||
fn convert(&self, vs: Rc<Val>, w: &mut Write) -> Result;
|
fn convert(&self, vs: Rc<Val>, w: &mut Write) -> Result;
|
||||||
fn file_ext(&self) -> String;
|
fn file_ext(&self) -> String;
|
||||||
|
fn description(&self) -> String;
|
||||||
}
|
}
|
||||||
|
58
src/main.rs
58
src/main.rs
@ -27,7 +27,7 @@ use ucglib::build;
|
|||||||
use ucglib::build::assets::{Cache, MemoryCache};
|
use ucglib::build::assets::{Cache, MemoryCache};
|
||||||
use ucglib::build::Val;
|
use ucglib::build::Val;
|
||||||
use ucglib::convert::traits;
|
use ucglib::convert::traits;
|
||||||
use ucglib::convert::ConverterRunner;
|
use ucglib::convert::ConverterRegistry;
|
||||||
|
|
||||||
// TODO(jwall): List the target output types automatically.
|
// TODO(jwall): List the target output types automatically.
|
||||||
fn do_flags<'a>() -> clap::ArgMatches<'a> {
|
fn do_flags<'a>() -> clap::ArgMatches<'a> {
|
||||||
@ -54,22 +54,21 @@ fn do_flags<'a>() -> clap::ArgMatches<'a> {
|
|||||||
)
|
)
|
||||||
(@subcommand converters =>
|
(@subcommand converters =>
|
||||||
(about: "list the available converters")
|
(about: "list the available converters")
|
||||||
(@arg name: -c --converter-name +takes_value "Optionally print help for the provided converter")
|
|
||||||
)
|
)
|
||||||
).get_matches()
|
).get_matches()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_converter(c: ConverterRunner, v: Rc<Val>, f: Option<&str>) -> traits::Result {
|
fn run_converter(c: &traits::Converter, v: Rc<Val>, f: Option<&str>) -> traits::Result {
|
||||||
let file: Box<std::io::Write> = match f {
|
let mut file: Box<std::io::Write> = match f {
|
||||||
Some(f) => {
|
Some(f) => {
|
||||||
let mut path_buf = PathBuf::from(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();
|
let new_path = path_buf.to_str().unwrap();
|
||||||
Box::new(try!(File::create(&new_path)))
|
Box::new(try!(File::create(&new_path)))
|
||||||
}
|
}
|
||||||
None => Box::new(io::stdout()),
|
None => Box::new(io::stdout()),
|
||||||
};
|
};
|
||||||
c.convert(v, file)
|
c.convert(v, file.as_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_file(
|
fn build_file(
|
||||||
@ -101,7 +100,7 @@ fn do_validate(file: &str, cache: Rc<RefCell<Cache>>) -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_compile(file: &str, cache: Rc<RefCell<Cache>>) -> bool {
|
fn do_compile(file: &str, cache: Rc<RefCell<Cache>>, registry: &ConverterRegistry) -> bool {
|
||||||
println!("Building {}", file);
|
println!("Building {}", file);
|
||||||
let builder = match build_file(file, false, cache.clone()) {
|
let builder = match build_file(file, false, cache.clone()) {
|
||||||
Ok(builder) => builder,
|
Ok(builder) => builder,
|
||||||
@ -117,14 +116,14 @@ fn do_compile(file: &str, cache: Rc<RefCell<Cache>>) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match ConverterRunner::new(typ) {
|
match registry.get_converter(typ) {
|
||||||
Ok(converter) => {
|
Some(converter) => {
|
||||||
run_converter(converter, val, Some(file)).unwrap();
|
run_converter(converter, val, Some(file)).unwrap();
|
||||||
eprintln!("Build successful");
|
eprintln!("Build successful");
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
}
|
}
|
||||||
Err(msg) => {
|
None => {
|
||||||
eprintln!("{}", msg);
|
eprintln!("No such converter {}", typ);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,6 +134,7 @@ fn visit_ucg_files(
|
|||||||
recurse: bool,
|
recurse: bool,
|
||||||
validate: bool,
|
validate: bool,
|
||||||
cache: Rc<RefCell<Cache>>,
|
cache: Rc<RefCell<Cache>>,
|
||||||
|
registry: &ConverterRegistry,
|
||||||
) -> Result<bool, Box<Error>> {
|
) -> Result<bool, Box<Error>> {
|
||||||
let our_path = String::from(path.to_string_lossy());
|
let our_path = String::from(path.to_string_lossy());
|
||||||
let mut result = true;
|
let mut result = true;
|
||||||
@ -146,7 +146,9 @@ fn visit_ucg_files(
|
|||||||
let next_path = next_item.path();
|
let next_path = next_item.path();
|
||||||
let path_as_string = String::from(next_path.to_string_lossy());
|
let path_as_string = String::from(next_path.to_string_lossy());
|
||||||
if next_path.is_dir() && recurse {
|
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);
|
eprintln!("Err 1: {}", msg);
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
@ -159,7 +161,7 @@ fn visit_ucg_files(
|
|||||||
summary.push_str(format!("{} - PASS\n", path_as_string).as_str())
|
summary.push_str(format!("{} - PASS\n", path_as_string).as_str())
|
||||||
}
|
}
|
||||||
} else if !validate {
|
} else if !validate {
|
||||||
if !do_compile(&path_as_string, cache.clone()) {
|
if !do_compile(&path_as_string, cache.clone(), registry) {
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,7 +175,7 @@ fn visit_ucg_files(
|
|||||||
summary.push_str(format!("{} - PASS\n", &our_path).as_str())
|
summary.push_str(format!("{} - PASS\n", &our_path).as_str())
|
||||||
}
|
}
|
||||||
} else if !validate {
|
} else if !validate {
|
||||||
if !do_compile(&our_path, cache) {
|
if !do_compile(&our_path, cache, registry) {
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,14 +189,15 @@ fn visit_ucg_files(
|
|||||||
fn main() {
|
fn main() {
|
||||||
let app = do_flags();
|
let app = do_flags();
|
||||||
let cache: Rc<RefCell<Cache>> = Rc::new(RefCell::new(MemoryCache::new()));
|
let cache: Rc<RefCell<Cache>> = Rc::new(RefCell::new(MemoryCache::new()));
|
||||||
|
let registry = ConverterRegistry::make_registry();
|
||||||
if let Some(matches) = app.subcommand_matches("inspect") {
|
if let Some(matches) = app.subcommand_matches("inspect") {
|
||||||
let file = matches.value_of("INPUT").unwrap();
|
let file = matches.value_of("INPUT").unwrap();
|
||||||
let sym = matches.value_of("sym");
|
let sym = matches.value_of("sym");
|
||||||
let target = matches.value_of("target").unwrap();
|
let target = matches.value_of("target").unwrap();
|
||||||
let root = PathBuf::from(file);
|
let root = PathBuf::from(file);
|
||||||
let mut builder = build::Builder::new(root.parent().unwrap(), cache);
|
let mut builder = build::Builder::new(root.parent().unwrap(), cache);
|
||||||
match ConverterRunner::new(target) {
|
match registry.get_converter(target) {
|
||||||
Ok(converter) => {
|
Some(converter) => {
|
||||||
// TODO(jwall): We should warn if this is a test file.
|
// TODO(jwall): We should warn if this is a test file.
|
||||||
let result = builder.build_file(file);
|
let result = builder.build_file(file);
|
||||||
if !result.is_ok() {
|
if !result.is_ok() {
|
||||||
@ -218,8 +221,8 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(msg) => {
|
None => {
|
||||||
eprintln!("{}", msg);
|
eprintln!("No such converter {}", target);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,14 +232,14 @@ fn main() {
|
|||||||
let mut ok = true;
|
let mut ok = true;
|
||||||
if files.is_none() {
|
if files.is_none() {
|
||||||
let curr_dir = std::env::current_dir().unwrap();
|
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 {
|
if let Ok(false) = ok {
|
||||||
process::exit(1)
|
process::exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for file in files.unwrap() {
|
for file in files.unwrap() {
|
||||||
let pb = PathBuf::from(file);
|
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;
|
ok = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,7 +251,7 @@ fn main() {
|
|||||||
let recurse = matches.is_present("recurse");
|
let recurse = matches.is_present("recurse");
|
||||||
if files.is_none() {
|
if files.is_none() {
|
||||||
let curr_dir = std::env::current_dir().unwrap();
|
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 {
|
if let Ok(false) = ok {
|
||||||
process::exit(1)
|
process::exit(1)
|
||||||
}
|
}
|
||||||
@ -257,7 +260,9 @@ fn main() {
|
|||||||
for file in files.unwrap() {
|
for file in files.unwrap() {
|
||||||
let pb = PathBuf::from(file);
|
let pb = PathBuf::from(file);
|
||||||
if pb.is_dir() {
|
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;
|
ok = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -284,6 +289,13 @@ fn main() {
|
|||||||
}
|
}
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
} else if let Some(_todo) = app.subcommand_matches("converters") {
|
} 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!("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user