proxmox-backup/src/getopts.rs

204 lines
6.6 KiB
Rust
Raw Normal View History

2018-11-16 12:14:11 +00:00
use crate::api::schema::*;
use failure::*;
2018-11-20 15:54:29 +00:00
use serde_json::Value;
2018-11-16 12:14:11 +00:00
#[derive(Debug)]
enum RawArgument {
Separator,
Argument { value: String },
Option { name: String, value: Option<String> },
}
fn parse_argument(arg: &str) -> RawArgument {
let chars: Vec<char> = arg.chars().collect();
let length = chars.len();
if length >= 2 {
2018-11-16 12:14:11 +00:00
if chars[0] == '-' {
2018-11-18 08:34:43 +00:00
let mut first = 1;
if chars[1] == '-' {
if length == 2 { return RawArgument::Separator; }
first = 2;
}
2018-11-16 12:14:11 +00:00
for start in first..length {
if chars[start] == '=' {
let name: String = chars[first..start].iter().collect();
let value: String = chars[start+1..length].iter().collect();
return RawArgument::Option { name, value: Some(value) }
}
}
2018-11-16 12:14:11 +00:00
let name: String = chars[first..].iter().collect();
return RawArgument::Option { name: name, value: None }
}
2018-11-16 12:14:11 +00:00
}
RawArgument::Argument { value: arg.to_string() }
}
2018-11-17 08:57:26 +00:00
pub fn parse_arguments(
args: &Vec<String>,
2018-11-30 11:10:26 +00:00
arg_param: &Vec<&'static str>,
schema: &ObjectSchema,
2018-11-17 08:57:26 +00:00
) -> Result<(Value,Vec<String>), ParameterError> {
2018-11-16 12:14:11 +00:00
2018-11-17 08:57:26 +00:00
let mut errors = ParameterError::new();
2018-11-16 12:14:11 +00:00
let properties = &schema.properties;
2018-11-16 12:14:11 +00:00
let mut data: Vec<(String, String)> = vec![];
let mut rest: Vec<String> = vec![];
let mut pos = 0;
let mut skip = false;
while pos < args.len() {
2018-11-16 12:14:11 +00:00
if skip {
rest.push(args[pos].clone());
} else {
match parse_argument(&args[pos]) {
RawArgument::Separator => {
skip = true;
}
RawArgument::Option { name, value } => {
match value {
None => {
2018-11-20 15:54:29 +00:00
let mut want_bool = false;
let mut can_default = false;
if let Some((_optional, param_schema)) = properties.get::<str>(&name) {
2018-11-20 15:54:29 +00:00
if let Schema::Boolean(boolean_schema) = param_schema.as_ref() {
want_bool = true;
2018-11-17 10:28:26 +00:00
if let Some(default) = boolean_schema.default {
2018-11-20 15:54:29 +00:00
if default == false { can_default = true; }
} else {
can_default = true;
2018-11-17 10:28:26 +00:00
}
}
2018-11-20 15:54:29 +00:00
}
2018-11-17 10:28:26 +00:00
2018-11-18 07:55:21 +00:00
let mut next_is_argument = false;
let mut next_is_bool = false;
2018-11-17 10:28:26 +00:00
2018-11-18 07:55:21 +00:00
if (pos + 1) < args.len() {
let next = &args[pos+1];
2018-11-18 08:34:43 +00:00
if let RawArgument::Argument { value: _} = parse_argument(next) {
2018-11-18 07:55:21 +00:00
next_is_argument = true;
2018-11-17 10:28:26 +00:00
if let Ok(_) = parse_boolean(next) { next_is_bool = true; }
}
2018-11-18 07:55:21 +00:00
}
2018-11-17 10:28:26 +00:00
2018-11-18 07:55:21 +00:00
if want_bool {
2018-11-17 10:28:26 +00:00
if next_is_bool {
2018-11-16 12:14:11 +00:00
pos += 1;
2018-11-17 10:28:26 +00:00
data.push((name, args[pos].clone()));
} else if can_default {
data.push((name, "true".to_string()));
2018-11-16 12:14:11 +00:00
} else {
2018-11-17 10:28:26 +00:00
errors.push(format_err!("parameter '{}': {}", name,
"missing boolean value."));
}
} else {
2018-11-18 07:55:21 +00:00
if next_is_argument {
2018-11-17 10:28:26 +00:00
pos += 1;
data.push((name, args[pos].clone()));
} else {
errors.push(format_err!("parameter '{}': {}", name,
"missing parameter value."));
2018-11-16 12:14:11 +00:00
}
}
}
Some(v) => {
data.push((name, v));
}
}
}
RawArgument::Argument { value } => {
rest.push(value);
}
}
}
pos += 1;
}
2018-11-18 09:09:13 +00:00
for i in 0..arg_param.len() {
if rest.len() > i {
2018-11-30 11:10:26 +00:00
data.push((arg_param[i].to_string(), rest[i].clone()));
2018-11-18 09:09:13 +00:00
} else {
errors.push(format_err!("missing argument '{}'", arg_param[i]));
}
}
2018-11-17 08:57:26 +00:00
if errors.len() > 0 { return Err(errors); }
2018-11-16 12:14:11 +00:00
2018-11-18 09:09:13 +00:00
if arg_param.len() > 0 {
rest = rest[arg_param.len()..].to_vec();
}
2018-11-17 08:57:26 +00:00
let options = parse_parameter_strings(&data, schema, true)?;
Ok((options,rest))
2018-11-16 12:14:11 +00:00
}
2018-11-17 10:28:26 +00:00
#[test]
fn test_boolean_arg() {
let schema = ObjectSchema::new("Parameters:")
.required(
"enable", BooleanSchema::new("Enable")
);
2018-11-17 10:28:26 +00:00
2018-11-18 08:34:43 +00:00
let mut variants: Vec<(Vec<&str>, bool)> = vec![];
variants.push((vec!["-enable"], true));
variants.push((vec!["-enable=1"], true));
variants.push((vec!["-enable", "yes"], true));
variants.push((vec!["-enable", "Yes"], true));
variants.push((vec!["--enable", "1"], true));
variants.push((vec!["--enable", "ON"], true));
variants.push((vec!["--enable", "true"], true));
variants.push((vec!["--enable", "0"], false));
variants.push((vec!["--enable", "no"], false));
variants.push((vec!["--enable", "off"], false));
variants.push((vec!["--enable", "false"], false));
for (args, expect) in variants {
2018-11-17 10:28:26 +00:00
let string_args = args.iter().map(|s| s.to_string()).collect();
2018-11-18 09:09:13 +00:00
let res = parse_arguments(&string_args, &vec![], &schema);
2018-11-17 10:28:26 +00:00
assert!(res.is_ok());
if let Ok((options, rest)) = res {
2018-11-18 08:34:43 +00:00
assert!(options["enable"] == expect);
2018-11-17 10:28:26 +00:00
assert!(rest.len() == 0);
}
}
2018-11-18 09:09:13 +00:00
}
2018-11-17 10:28:26 +00:00
2018-11-18 09:09:13 +00:00
#[test]
fn test_argument_paramenter() {
let schema = ObjectSchema::new("Parameters:")
2018-11-23 12:18:41 +00:00
.required("enable", BooleanSchema::new("Enable."))
.required("storage", StringSchema::new("Storage."));
2018-11-18 09:09:13 +00:00
let args = vec!["-enable", "local"];
let string_args = args.iter().map(|s| s.to_string()).collect();
2018-12-07 08:02:24 +00:00
let res = parse_arguments(&string_args, &vec!["storage"], &schema);
2018-11-18 09:09:13 +00:00
assert!(res.is_ok());
if let Ok((options, rest)) = res {
assert!(options["enable"] == true);
assert!(options["storage"] == "local");
assert!(rest.len() == 0);
}
2018-11-17 10:28:26 +00:00
}