getopt parser fixes and cleanups

This commit is contained in:
Dietmar Maurer 2018-11-17 11:28:26 +01:00
parent 7556cab45e
commit 2770fbf3c3
2 changed files with 73 additions and 21 deletions

View File

@ -171,6 +171,14 @@ macro_rules! parameter {
}}; }};
} }
pub fn parse_boolean(value_str: &str) -> Result<bool, Error> {
match value_str.to_lowercase().as_str() {
"1" | "on" | "yes" | "true" => Ok(true),
"0" | "off" | "no" | "false" => Ok(false),
_ => bail!("Unable to parse boolean option."),
}
}
fn parse_simple_value(value_str: &str, schema: &Schema) -> Result<Value, Error> { fn parse_simple_value(value_str: &str, schema: &Schema) -> Result<Value, Error> {
let value = match schema { let value = match schema {
@ -178,11 +186,7 @@ fn parse_simple_value(value_str: &str, schema: &Schema) -> Result<Value, Error>
bail!("internal error - found Null schema."); bail!("internal error - found Null schema.");
} }
Schema::Boolean(_boolean_schema) => { Schema::Boolean(_boolean_schema) => {
let res = match value_str.to_lowercase().as_str() { let res = parse_boolean(value_str)?;
"1" | "on" | "yes" | "true" => true,
"0" | "off" | "no" | "false" => false,
_ => bail!("Unable to parse boolean option."),
};
Value::Bool(res) Value::Bool(res)
} }
Schema::Integer(integer_schema) => { Schema::Integer(integer_schema) => {

View File

@ -1,6 +1,7 @@
use crate::api::schema::*; use crate::api::schema::*;
use failure::*; use failure::*;
use std::collections::HashMap;
use serde_json::{json, Value}; use serde_json::{json, Value};
#[derive(Debug)] #[derive(Debug)]
@ -72,23 +73,43 @@ pub fn parse_arguments(
RawArgument::Option { name, value } => { RawArgument::Option { name, value } => {
match value { match value {
None => { None => {
if pos < args.len() { let param_schema = properties.get::<str>(&name);
if let RawArgument::Argument { value: next } = parse_argument(&args[pos+1]) { let (want_bool, can_default) = match param_schema {
pos += 1; Some(Schema::Boolean(boolean_schema)) => {
data.push((name, next)); if let Some(default) = boolean_schema.default {
} else { if default == true { (true, false); }
if let Some(Schema::Boolean(boolean_schema)) = properties.get::<str>(&name) {
if let Some(default) = boolean_schema.default {
if default == false {
data.push((name, "true".to_string()));
} else {
errors.push(format_err!("parameter '{}': {}", name,
"boolean requires argument."));
}
} else {
data.push((name, "true".to_string()));
}
} }
(true, true)
}
_ => (false, false),
};
if want_bool {
let mut next_is_bool = false;
if (pos + 1) < args.len() {
let next = &args[pos+1];
if let Ok(_) = parse_boolean(next) { next_is_bool = true; }
}
if next_is_bool {
pos += 1;
data.push((name, args[pos].clone()));
} else if can_default {
data.push((name, "true".to_string()));
} else {
errors.push(format_err!("parameter '{}': {}", name,
"missing boolean value."));
}
} else {
if (pos + 1) < args.len() {
pos += 1;
data.push((name, args[pos].clone()));
} else {
errors.push(format_err!("parameter '{}': {}", name,
"missing parameter value."));
} }
} }
} }
@ -113,3 +134,30 @@ pub fn parse_arguments(
Ok((options,rest)) Ok((options,rest))
} }
#[test]
fn test_boolean_arg() {
let schema = parameter!{enable => Boolean!{ optional => false }};
let mut variants: Vec<Vec<&str>> = vec![];
variants.push(vec!["-enable"]);
variants.push(vec!["-enable=1"]);
variants.push(vec!["-enable", "yes"]);
variants.push(vec!["--enable", "1"]);
for args in variants {
let string_args = args.iter().map(|s| s.to_string()).collect();
let res = parse_arguments(&string_args, &schema);
println!("RES: {:?}", res);
assert!(res.is_ok());
if let Ok((options, rest)) = res {
assert!(options["enable"] == true);
assert!(rest.len() == 0);
}
}
//Ok((options, rest)) => {
}