use std::collections::HashMap;
use std::collections::HashSet;
+use serde_json::Value;
+
use crate::api::schema::*;
use crate::api::router::*;
-use crate::api::config::*;
+//use crate::api::config::*;
use crate::getopts;
+struct CliEnvironment {
+ result_attributes: HashMap<String, Value>,
+}
+
+impl CliEnvironment {
+ fn new() -> Self {
+ Self { result_attributes: HashMap::new() }
+ }
+}
+
+impl RpcEnvironment for CliEnvironment {
+
+ fn set_result_attrib(&mut self, name: &str, value: Value) {
+ self.result_attributes.insert(name.into(), value);
+ }
+
+ fn get_result_attrib(&self, name: &str) -> Option<&Value> {
+ self.result_attributes.get(name)
+ }
+}
+
+
pub fn print_cli_usage() {
eprintln!("Usage: TODO");
}
-fn handle_simple_command(cli_cmd: &CliCommand, args: Vec<String>) -> Result<(), Error> {
+#[derive(Debug, Fail)]
+#[fail(display = "Usage error: {}", _0)]
+pub struct UsageError(Error);
+
+pub struct Invocation<'a>(&'a CliCommand, Value);
+
+fn handle_simple_command(cli_cmd: &CliCommand, args: Vec<String>) -> Result<Invocation, Error> {
let (params, rest) = getopts::parse_arguments(
&args, &cli_cmd.arg_param, &cli_cmd.info.parameters)?;
bail!("got additional arguments: {:?}", rest);
}
- let res = (cli_cmd.info.handler)(params, &cli_cmd.info)?;
-
- println!("Result: {}", serde_json::to_string_pretty(&res).unwrap());
-
- Ok(())
+ Ok(Invocation(cli_cmd, params))
}
fn find_command<'a>(def: &'a CliCommandMap, name: &str) -> Option<&'a CommandLineInterface> {
None
}
-fn handle_nested_command(def: &CliCommandMap, mut args: Vec<String>) -> Result<(), Error> {
+fn handle_nested_command(def: &CliCommandMap, mut args: Vec<String>) -> Result<Invocation, Error> {
if args.len() < 1 {
let mut cmds: Vec<&String> = def.commands.keys().collect();
match sub_cmd {
CommandLineInterface::Simple(cli_cmd) => {
- handle_simple_command(cli_cmd, args)?;
+ handle_simple_command(cli_cmd, args)
}
CommandLineInterface::Nested(map) => {
- handle_nested_command(map, args)?;
+ handle_nested_command(map, args)
}
}
-
- Ok(())
}
-fn print_property_completion(schema: &Schema, arg: &str) {
- // fixme: implement completion functions
+fn print_property_completion(
+ schema: &Schema,
+ name: &str,
+ completion_functions: &HashMap<String, CompletionFunction>,
+ arg: &str)
+{
+ if let Some(callback) = completion_functions.get(name) {
+ let list = (callback)(arg);
+ for value in list {
+ if value.starts_with(arg) {
+ println!("{}", value);
+ }
+ }
+ return;
+ }
+
if let Schema::String(StringSchema { format: Some(format), ..} ) = schema {
if let ApiStringFormat::Enum(list) = format.as_ref() {
for value in list {
args.remove(0);
print_simple_completion(cli_cmd, done, &arg_param[1..], args);
return;
- }
- if let Some((_, schema)) = cli_cmd.info.parameters.properties.get(prop_name) {
- if args.is_empty() {
- print_property_completion(schema, "");
- } else {
- print_property_completion(schema, &args[0]);
+ } else if args.len() == 1 {
+ if let Some((_, schema)) = cli_cmd.info.parameters.properties.get(prop_name) {
+ print_property_completion(schema, prop_name, &cli_cmd.completion_functions, &args[0]);
}
}
return;
if last.starts_with("--") && last.len() > 2 {
let prop_name = &last[2..];
if let Some((_, schema)) = cli_cmd.info.parameters.properties.get(prop_name) {
- print_property_completion(schema, &prefix);
+ print_property_completion(schema, prop_name, &cli_cmd.completion_functions, &prefix);
}
return;
}
}
- for (name, (optional, schema)) in &cli_cmd.info.parameters.properties {
+ for (name, (_optional, _schema)) in &cli_cmd.info.parameters.properties {
if done.contains(*name) { continue; }
let option = String::from("--") + name;
if option.starts_with(&prefix) {
Ok(val) => {
match usize::from_str_radix(&val, 10) {
Ok(i) => i,
- Err(e) => return,
+ Err(_) => return,
}
}
- Err(e) => return,
+ Err(_) => return,
};
let cmdline = match std::env::var("COMP_LINE") {
Ok(val) => val[0..comp_point].to_owned(),
- Err(e) => return,
+ Err(_) => return,
};
return Ok(());
}
- match def {
+ let invocation = match def {
CommandLineInterface::Simple(cli_cmd) => handle_simple_command(cli_cmd, args),
CommandLineInterface::Nested(map) => handle_nested_command(map, args),
- }
+ };
+
+ let mut rpcenv = CliEnvironment::new();
+
+ let res = match invocation {
+ Err(e) => return Err(UsageError(e).into()),
+ Ok(invocation) => (invocation.0.info.handler)(invocation.1, &invocation.0.info, &mut rpcenv)?,
+ };
+
+ println!("Result: {}", serde_json::to_string_pretty(&res).unwrap());
+
+ Ok(())
}
+pub type CompletionFunction = fn(&str) -> Vec<String>;
+
pub struct CliCommand {
pub info: ApiMethod,
pub arg_param: Vec<&'static str>,
pub fixed_param: Vec<&'static str>,
+ pub completion_functions: HashMap<String, CompletionFunction>,
}
impl CliCommand {
pub fn new(info: ApiMethod) -> Self {
- Self { info, arg_param: vec![], fixed_param: vec![] }
+ Self {
+ info, arg_param: vec![],
+ fixed_param: vec![],
+ completion_functions: HashMap::new(),
+ }
}
pub fn arg_param(mut self, names: Vec<&'static str>) -> Self {
self.fixed_param = args;
self
}
+
+ pub fn completion_cb(mut self, param_name: &str, cb: CompletionFunction) -> Self {
+ self.completion_functions.insert(param_name.into(), cb);
+ self
+ }
}
pub struct CliCommandMap {