router: cli: option to specify args explicitly

so CLI tools can pre-parse out non-api parameters before
passing the remaining stuff to the router

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2023-03-14 09:02:45 +01:00
parent 2bba40f604
commit 1c0edfb518

View File

@ -335,9 +335,10 @@ pub fn handle_command(
result result
} }
fn prepare_cli_command(def: &CommandLineInterface) -> (String, Vec<String>) { fn prepare_cli_command<A>(def: &CommandLineInterface, mut args: A) -> (String, Vec<String>)
let mut args = std::env::args(); where
A: Iterator<Item = String>,
{
let prefix = args.next().unwrap(); let prefix = args.next().unwrap();
let prefix = prefix.rsplit('/').next().unwrap().to_string(); // without path let prefix = prefix.rsplit('/').next().unwrap().to_string(); // without path
@ -379,12 +380,44 @@ fn prepare_cli_command(def: &CommandLineInterface) -> (String, Vec<String>) {
/// - ``printdoc``: Output ReST documentation. /// - ``printdoc``: Output ReST documentation.
/// ///
pub async fn run_async_cli_command<C: Into<CommandLineInterface>>(def: C, rpcenv: CliEnvironment) { pub async fn run_async_cli_command<C: Into<CommandLineInterface>>(def: C, rpcenv: CliEnvironment) {
run_async_cli_command_with_args(def, rpcenv, std::env::args()).await
}
/// Helper to get arguments and invoke the command.
///
/// This is the synchrounous version of run_async_cli_command. You can
/// pass an optional ``run`` function to execute async commands (else
/// async commands simply fail).
pub fn run_cli_command<C: Into<CommandLineInterface>>(
def: C,
rpcenv: CliEnvironment,
run: Option<fn(ApiFuture) -> Result<Value, Error>>,
) {
run_cli_command_with_args(def, rpcenv, run, std::env::args())
}
/// Helper to get arguments and invoke the command (async).
///
/// 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 async fn run_async_cli_command_with_args<A, C>(def: C, rpcenv: CliEnvironment, args: A)
where
C: Into<CommandLineInterface>,
A: IntoIterator<Item = String>,
{
let def = match def.into() { let def = match def.into() {
CommandLineInterface::Simple(cli_cmd) => CommandLineInterface::Simple(cli_cmd), CommandLineInterface::Simple(cli_cmd) => CommandLineInterface::Simple(cli_cmd),
CommandLineInterface::Nested(map) => CommandLineInterface::Nested(map.insert_help()), CommandLineInterface::Nested(map) => CommandLineInterface::Nested(map.insert_help()),
}; };
let (prefix, args) = prepare_cli_command(&def); let (prefix, args) = prepare_cli_command(&def, args.into_iter());
if handle_command_future(Arc::new(def), &prefix, args, rpcenv) if handle_command_future(Arc::new(def), &prefix, args, rpcenv)
.await .await
@ -399,17 +432,21 @@ pub async fn run_async_cli_command<C: Into<CommandLineInterface>>(def: C, rpcenv
/// This is the synchrounous version of run_async_cli_command. You can /// This is the synchrounous version of run_async_cli_command. You can
/// pass an optional ``run`` function to execute async commands (else /// pass an optional ``run`` function to execute async commands (else
/// async commands simply fail). /// async commands simply fail).
pub fn run_cli_command<C: Into<CommandLineInterface>>( pub fn run_cli_command_with_args<A, C>(
def: C, def: C,
rpcenv: CliEnvironment, rpcenv: CliEnvironment,
run: Option<fn(ApiFuture) -> Result<Value, Error>>, run: Option<fn(ApiFuture) -> Result<Value, Error>>,
) { args: A,
) where
C: Into<CommandLineInterface>,
A: IntoIterator<Item = String>,
{
let def = match def.into() { let def = match def.into() {
CommandLineInterface::Simple(cli_cmd) => CommandLineInterface::Simple(cli_cmd), CommandLineInterface::Simple(cli_cmd) => CommandLineInterface::Simple(cli_cmd),
CommandLineInterface::Nested(map) => CommandLineInterface::Nested(map.insert_help()), CommandLineInterface::Nested(map) => CommandLineInterface::Nested(map.insert_help()),
}; };
let (prefix, args) = prepare_cli_command(&def); let (prefix, args) = prepare_cli_command(&def, args.into_iter());
if handle_command(Arc::new(def), &prefix, args, rpcenv, run).is_err() { if handle_command(Arc::new(def), &prefix, args, rpcenv, run).is_err() {
std::process::exit(-1); std::process::exit(-1);