src/cli/command.rs: start implementing generate_usage_str()

This commit is contained in:
Dietmar Maurer 2019-02-22 11:14:01 +01:00
parent 33256db6dd
commit 6adb40eefc
1 changed files with 131 additions and 10 deletions

View File

@ -1,6 +1,7 @@
use failure::*;
use std::collections::HashMap;
use std::collections::HashSet;
use std::sync::Arc;
//use serde_json::Value;
@ -11,10 +12,109 @@ use super::environment::CliEnvironment;
use super::getopts;
fn print_simple_usage(prefix: &str, _cli_cmd: &CliCommand, err: Error) {
#[derive(Copy, Clone)]
enum ParameterDisplayStyle {
//Config,
//SonfigSub,
Arg,
Fixed,
}
eprintln!("Error: {}", err);
eprintln!("\nUsage: {} <TODO>", prefix);
fn get_schema_type_text(schema: Arc<Schema>, _style: ParameterDisplayStyle) -> String {
let type_text = match *schema {
Schema::Null => String::from("<null>"), // should not happen
Schema::String(_) => String::from("<string>"),
Schema::Boolean(_) => String::from("<boolean>"),
Schema::Integer(_) => String::from("<integer>"),
Schema::Object(_) => String::from("<object>"),
Schema::Array(_) => String::from("<array>"),
};
type_text
}
fn get_property_description(
name: &str,
schema: Arc<Schema>,
style: ParameterDisplayStyle
) -> String {
let type_text = get_schema_type_text(schema, style);
let display_name = match style {
ParameterDisplayStyle::Arg => {
format!("--{}", name)
}
ParameterDisplayStyle::Fixed => {
format!("<{}>", name)
}
};
format!(" {:-10} {}", display_name, type_text)
}
fn generate_usage_str(prefix: &str, cli_cmd: &CliCommand, indent: &str) -> String {
let arg_param = &cli_cmd.arg_param;
let fixed_param = &cli_cmd.fixed_param;
let properties = &cli_cmd.info.parameters.properties;
let mut done_hash = HashSet::<&str>::new();
let mut args = String::new();
for positional_arg in arg_param {
let (optional, _schema) = properties.get(positional_arg).unwrap();
args.push(' ');
if *optional { args.push('['); }
args.push('<'); args.push_str(positional_arg); args.push('>');
if *optional { args.push(']'); }
//arg_descr.push_str(&get_property_description(positional_arg, schema.clone(), ParameterDisplayStyle::Fixed));
done_hash.insert(positional_arg);
}
let mut options = String::new();
let mut prop_names: Vec<&str> = properties.keys().map(|v| *v).collect();
prop_names.sort();
for prop in prop_names {
let (optional, schema) = properties.get(prop).unwrap();
if done_hash.contains(prop) { continue; }
if fixed_param.contains(&prop) { continue; }
let type_text = get_schema_type_text(schema.clone(), ParameterDisplayStyle::Arg);
if *optional {
options.push(' ');
options.push_str(&get_property_description(prop, schema.clone(), ParameterDisplayStyle::Arg));
} else {
args.push_str("--"); args.push_str(prop);
args.push(' ');
args.push_str(&type_text);
}
done_hash.insert(prop);
}
format!("{}{}{}", indent, prefix, args)
}
fn print_simple_usage_error(prefix: &str, cli_cmd: &CliCommand, err: Error) {
eprint!("Error: {}\nUsage: ", err);
print_simple_usage(prefix, cli_cmd);
}
fn print_simple_usage(prefix: &str, cli_cmd: &CliCommand) {
let usage = generate_usage_str(prefix, cli_cmd, "");
eprintln!("{}", usage);
}
fn handle_simple_command(prefix: &str, cli_cmd: &CliCommand, args: Vec<String>) {
@ -23,14 +123,14 @@ fn handle_simple_command(prefix: &str, cli_cmd: &CliCommand, args: Vec<String>)
&args, &cli_cmd.arg_param, &cli_cmd.info.parameters) {
Ok((p, r)) => (p, r),
Err(err) => {
print_simple_usage(prefix, cli_cmd, err.into());
print_simple_usage_error(prefix, cli_cmd, err.into());
std::process::exit(-1);
}
};
if !rest.is_empty() {
let err = format_err!("got additional arguments: {:?}", rest);
print_simple_usage(prefix, cli_cmd, err);
print_simple_usage_error(prefix, cli_cmd, err);
std::process::exit(-1);
}
@ -68,10 +168,31 @@ fn find_command<'a>(def: &'a CliCommandMap, name: &str) -> Option<&'a CommandLin
None
}
fn print_nested_usage(prefix: &str, _def: &CliCommandMap, err: Error) {
fn print_nested_usage_error(prefix: &str, def: &CliCommandMap, err: Error) {
eprintln!("Error: {}", err);
eprintln!("\nUsage: {} <TODO>", prefix);
eprintln!("Error: {}\n\nUsage:\n", err);
print_nested_usage(prefix, def);
}
fn print_nested_usage(prefix: &str, def: &CliCommandMap) {
let mut cmds: Vec<&String> = def.commands.keys().collect();
cmds.sort();
for cmd in cmds {
let new_prefix = format!("{} {}", prefix, cmd);
match def.commands.get(cmd).unwrap() {
CommandLineInterface::Simple(cli_cmd) => {
let usage = generate_usage_str(&new_prefix, cli_cmd, "");
eprintln!("{}", usage);
}
CommandLineInterface::Nested(map) => {
print_nested_usage(&new_prefix, map);
}
}
}
}
@ -88,7 +209,7 @@ fn handle_nested_command(prefix: &str, def: &CliCommandMap, mut args: Vec<String
});
let err = format_err!("no command specified.\nPossible commands: {}", list);
print_nested_usage(prefix, def, err);
print_nested_usage_error(prefix, def, err);
std::process::exit(-1);
}
@ -98,7 +219,7 @@ fn handle_nested_command(prefix: &str, def: &CliCommandMap, mut args: Vec<String
Some(cmd) => cmd,
None => {
let err = format_err!("no such command '{}'", command);
print_nested_usage(prefix, def, err);
print_nested_usage_error(prefix, def, err);
std::process::exit(-1);
}
};