From 6adb40eefcdcb71b5afff0d173f44a034b1ff7b7 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Fri, 22 Feb 2019 11:14:01 +0100 Subject: [PATCH] src/cli/command.rs: start implementing generate_usage_str() --- src/cli/command.rs | 141 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 131 insertions(+), 10 deletions(-) diff --git a/src/cli/command.rs b/src/cli/command.rs index b99c2588..35e173d1 100644 --- a/src/cli/command.rs +++ b/src/cli/command.rs @@ -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: {} ", prefix); +fn get_schema_type_text(schema: Arc, _style: ParameterDisplayStyle) -> String { + + let type_text = match *schema { + Schema::Null => String::from(""), // should not happen + Schema::String(_) => String::from(""), + Schema::Boolean(_) => String::from(""), + Schema::Integer(_) => String::from(""), + Schema::Object(_) => String::from(""), + Schema::Array(_) => String::from(""), + }; + + type_text +} + +fn get_property_description( + name: &str, + schema: Arc, + 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) { @@ -23,14 +123,14 @@ fn handle_simple_command(prefix: &str, cli_cmd: &CliCommand, args: Vec) &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: {} ", 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 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); } };