src/cli: improve docs
This commit is contained in:
parent
3bf920527c
commit
28c855c0a2
39
src/cli.rs
39
src/cli.rs
@ -1,8 +1,16 @@
|
||||
//! Tools to create command line parsers
|
||||
//!
|
||||
//! We can use Schema deinititions to create command line parsers.
|
||||
//! This crate provides convenient helpers to create command line
|
||||
//! parsers using Schema definitions.
|
||||
//!
|
||||
//!
|
||||
//! ## Features
|
||||
//!
|
||||
//! - Use declarative API schema to define the CLI
|
||||
//! - Automatic parameter verification
|
||||
//! - Automatically generate documentation and manual pages
|
||||
//! - Automatically generate bash completion helpers
|
||||
//! - Ability to create interactive commands (using ``rustyline``)
|
||||
//! - Supports complex/nested commands
|
||||
|
||||
mod environment;
|
||||
pub use environment::*;
|
||||
@ -29,17 +37,34 @@ use std::collections::HashMap;
|
||||
|
||||
use proxmox::api::ApiMethod;
|
||||
|
||||
/// Completion function for single parameters.
|
||||
///
|
||||
/// Completion functions gets the current parameter value, and should
|
||||
/// return a list of all possible values.
|
||||
pub type CompletionFunction = fn(&str, &HashMap<String, String>) -> Vec<String>;
|
||||
|
||||
/// Define a simple CLI command.
|
||||
pub struct CliCommand {
|
||||
/// The Schema definition.
|
||||
pub info: &'static ApiMethod,
|
||||
/// Argument parameter list.
|
||||
///
|
||||
/// Those parameters are expected to be passed as command line
|
||||
/// arguments in the specified order. All other parameters needs
|
||||
/// to be specified as ``--option <value>`` pairs.
|
||||
pub arg_param: &'static [&'static str],
|
||||
/// Predefined parameters.
|
||||
pub fixed_param: HashMap<&'static str, String>,
|
||||
/// Completion functions.
|
||||
///
|
||||
/// Each parameter may have an associated completion function,
|
||||
/// which is called by the shell completion handler.
|
||||
pub completion_functions: HashMap<String, CompletionFunction>,
|
||||
}
|
||||
|
||||
impl CliCommand {
|
||||
|
||||
/// Create a new instance.
|
||||
pub fn new(info: &'static ApiMethod) -> Self {
|
||||
Self {
|
||||
info, arg_param: &[],
|
||||
@ -48,37 +73,46 @@ impl CliCommand {
|
||||
}
|
||||
}
|
||||
|
||||
/// Set argument parameter list.
|
||||
pub fn arg_param(mut self, names: &'static [&'static str]) -> Self {
|
||||
self.arg_param = names;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set fixed parameters.
|
||||
pub fn fixed_param(mut self, key: &'static str, value: String) -> Self {
|
||||
self.fixed_param.insert(key, value);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set completion functions.
|
||||
pub fn completion_cb(mut self, param_name: &str, cb: CompletionFunction) -> Self {
|
||||
self.completion_functions.insert(param_name.into(), cb);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Define nested CLI commands.
|
||||
pub struct CliCommandMap {
|
||||
/// Each command has an unique name. The map associates names with
|
||||
/// command definitions.
|
||||
pub commands: HashMap<String, CommandLineInterface>,
|
||||
}
|
||||
|
||||
impl CliCommandMap {
|
||||
|
||||
/// Create a new instance.
|
||||
pub fn new() -> Self {
|
||||
Self { commands: HashMap:: new() }
|
||||
}
|
||||
|
||||
/// Insert another command.
|
||||
pub fn insert<S: Into<String>>(mut self, name: S, cli: CommandLineInterface) -> Self {
|
||||
self.commands.insert(name.into(), cli);
|
||||
self
|
||||
}
|
||||
|
||||
/// Insert the help command.
|
||||
pub fn insert_help(mut self) -> Self {
|
||||
self.commands.insert(String::from("help"), help_command_def().into());
|
||||
self
|
||||
@ -107,6 +141,7 @@ impl CliCommandMap {
|
||||
}
|
||||
}
|
||||
|
||||
/// Define Complex command line interfaces.
|
||||
pub enum CommandLineInterface {
|
||||
Simple(CliCommand),
|
||||
Nested(CliCommandMap),
|
||||
|
@ -14,12 +14,18 @@ use super::getopts;
|
||||
use super::{CommandLineInterface, CliCommand, CliCommandMap, completion::*};
|
||||
use super::format::*;
|
||||
|
||||
/// Schema definition for ``--output-format`` parameter.
|
||||
///
|
||||
/// - ``text``: command specific text format.
|
||||
/// - ``json``: JSON, single line.
|
||||
/// - ``json-pretty``: JSON, human readable.
|
||||
///
|
||||
pub const OUTPUT_FORMAT: Schema =
|
||||
StringSchema::new("Output format.")
|
||||
.format(&ApiStringFormat::Enum(&["text", "json", "json-pretty"]))
|
||||
.schema();
|
||||
|
||||
pub fn handle_simple_command(
|
||||
fn handle_simple_command(
|
||||
_top_def: &CommandLineInterface,
|
||||
prefix: &str,
|
||||
cli_cmd: &CliCommand,
|
||||
@ -69,7 +75,7 @@ pub fn handle_simple_command(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn handle_nested_command(
|
||||
fn handle_nested_command(
|
||||
top_def: &CommandLineInterface,
|
||||
prefix: &str,
|
||||
def: &CliCommandMap,
|
||||
@ -172,11 +178,15 @@ fn set_help_context(def: Option<Arc<CommandLineInterface>>) {
|
||||
HELP_CONTEXT.with(|ctx| { *ctx.borrow_mut() = def; });
|
||||
}
|
||||
|
||||
pub fn help_command_def() -> CliCommand {
|
||||
pub(crate) fn help_command_def() -> CliCommand {
|
||||
CliCommand::new(&API_METHOD_COMMAND_HELP)
|
||||
.arg_param(&["command"])
|
||||
}
|
||||
|
||||
/// Handle command invocation.
|
||||
///
|
||||
/// This command gets the command line ``args`` and tries to invoke
|
||||
/// the corresponding API handler.
|
||||
pub fn handle_command(
|
||||
def: Arc<CommandLineInterface>,
|
||||
prefix: &str,
|
||||
@ -199,6 +209,18 @@ pub fn handle_command(
|
||||
result
|
||||
}
|
||||
|
||||
/// Helper to get arguments and invoke the command.
|
||||
///
|
||||
/// This helper reads arguments with ``std::env::args()``. The first
|
||||
/// argument is assumed to be the program name, and is passed as ``prefix`` to
|
||||
/// ``handle_command()``.
|
||||
///
|
||||
/// This helper automatically add the help command, and two special
|
||||
/// sub-command:
|
||||
///
|
||||
/// - ``bashcomplete``: Output bash completions instead of running the command.
|
||||
/// - ``printdoc``: Output ReST documentation.
|
||||
///
|
||||
pub fn run_cli_command(def: CommandLineInterface) {
|
||||
|
||||
let def = match def {
|
||||
|
@ -189,6 +189,12 @@ fn get_nested_completion(
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper to generate bash completions.
|
||||
///
|
||||
/// This helper extracts the command line from environment variable
|
||||
/// set by ``bash``, namely ``COMP_LINE`` and ``COMP_POINT``. This is
|
||||
/// passed to ``get_completions()``. Returned values are printed to
|
||||
/// ``stdout``.
|
||||
pub fn print_bash_completion(def: &CommandLineInterface) {
|
||||
|
||||
let comp_point: usize = match std::env::var("COMP_POINT") {
|
||||
@ -213,6 +219,7 @@ pub fn print_bash_completion(def: &CommandLineInterface) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute possible completions for a partial command
|
||||
pub fn get_completions(
|
||||
cmd_def: &CommandLineInterface,
|
||||
line: &str,
|
||||
|
@ -7,7 +7,7 @@ use proxmox::api::format::*;
|
||||
|
||||
use super::{CommandLineInterface, CliCommand, CliCommandMap};
|
||||
|
||||
/// Helper function to format and print result
|
||||
/// Helper function to format and print result.
|
||||
///
|
||||
/// This is implemented for machine generatable formats 'json' and
|
||||
/// 'json-pretty'. The 'text' format needs to be handled somewhere
|
||||
@ -26,6 +26,7 @@ pub fn format_and_print_result(
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper to generate command usage text for simple commands.
|
||||
pub fn generate_usage_str(
|
||||
prefix: &str,
|
||||
cli_cmd: &CliCommand,
|
||||
@ -115,6 +116,7 @@ pub fn generate_usage_str(
|
||||
text
|
||||
}
|
||||
|
||||
/// Print command usage for simple commands to ``stderr``.
|
||||
pub fn print_simple_usage_error(
|
||||
prefix: &str,
|
||||
cli_cmd: &CliCommand,
|
||||
@ -124,6 +126,7 @@ pub fn print_simple_usage_error(
|
||||
eprint!("Error: {}\nUsage: {}", err_msg, usage);
|
||||
}
|
||||
|
||||
/// Print command usage for nested commands to ``stderr``.
|
||||
pub fn print_nested_usage_error(
|
||||
prefix: &str,
|
||||
def: &CliCommandMap,
|
||||
@ -133,6 +136,7 @@ pub fn print_nested_usage_error(
|
||||
eprintln!("Error: {}\n\nUsage:\n\n{}", err_msg, usage);
|
||||
}
|
||||
|
||||
/// Helper to generate command usage text for nested commands.
|
||||
pub fn generate_nested_usage(
|
||||
prefix: &str,
|
||||
def: &CliCommandMap,
|
||||
@ -163,6 +167,7 @@ pub fn generate_nested_usage(
|
||||
usage
|
||||
}
|
||||
|
||||
/// Print help text to ``stderr``.
|
||||
pub fn print_help(
|
||||
top_def: &CommandLineInterface,
|
||||
mut prefix: String,
|
||||
|
@ -2,6 +2,11 @@ use std::sync::Arc;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Helper trait implementation for ``rustyline``.
|
||||
///
|
||||
/// This can be used to generate interactive commands using
|
||||
/// ``rustyline`` (readline implementation).
|
||||
///
|
||||
pub struct CliHelper {
|
||||
cmd_def: Arc<CommandLineInterface>,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user