mirror of
https://git.proxmox.com/git/proxmox
synced 2025-08-08 11:19:07 +00:00
router: cli: improve doc-gen global options handling
Passing the &GlobalOptions through is more telling than an opaque Iterator<&str>... Also: actually generate the property descriptions in non-ReST mode for global options as well, so the `help` output for a specific command includes the property documentation instead of only showing the name. Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
d872eb9d7e
commit
95c0614ccd
@ -10,7 +10,7 @@ use super::environment::CliEnvironment;
|
|||||||
use super::getopts;
|
use super::getopts;
|
||||||
use super::{
|
use super::{
|
||||||
generate_nested_usage, generate_usage_str_do, print_help, print_nested_usage_error,
|
generate_nested_usage, generate_usage_str_do, print_help, print_nested_usage_error,
|
||||||
print_simple_usage_error_do, CliCommand, CliCommandMap, CommandLineInterface,
|
print_simple_usage_error_do, CliCommand, CliCommandMap, CommandLineInterface, GlobalOptions,
|
||||||
};
|
};
|
||||||
use crate::{ApiFuture, ApiHandler, ApiMethod, RpcEnvironment};
|
use crate::{ApiFuture, ApiHandler, ApiMethod, RpcEnvironment};
|
||||||
|
|
||||||
@ -28,11 +28,11 @@ pub const OUTPUT_FORMAT: Schema = StringSchema::new("Output format.")
|
|||||||
]))
|
]))
|
||||||
.schema();
|
.schema();
|
||||||
|
|
||||||
fn parse_arguments(
|
fn parse_arguments<'cli>(
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
cli_cmd: &CliCommand,
|
cli_cmd: &CliCommand,
|
||||||
args: Vec<String>,
|
args: Vec<String>,
|
||||||
global_options_iter: impl Iterator<Item = &'static str>,
|
global_options_iter: impl Iterator<Item = &'cli GlobalOptions>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
let (params, remaining) = match getopts::parse_arguments(
|
let (params, remaining) = match getopts::parse_arguments(
|
||||||
&args,
|
&args,
|
||||||
@ -94,13 +94,13 @@ async fn handle_simple_command_future(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn handle_simple_command(
|
pub(crate) fn handle_simple_command<'cli>(
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
cli_cmd: &CliCommand,
|
cli_cmd: &CliCommand,
|
||||||
args: Vec<String>,
|
args: Vec<String>,
|
||||||
rpcenv: &mut CliEnvironment,
|
rpcenv: &mut CliEnvironment,
|
||||||
run: Option<fn(ApiFuture) -> Result<Value, Error>>,
|
run: Option<fn(ApiFuture) -> Result<Value, Error>>,
|
||||||
global_options_iter: impl Iterator<Item = &'static str>,
|
global_options_iter: impl Iterator<Item = &'cli GlobalOptions>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let params = parse_arguments(prefix, cli_cmd, args, global_options_iter)?;
|
let params = parse_arguments(prefix, cli_cmd, args, global_options_iter)?;
|
||||||
|
|
||||||
|
@ -76,13 +76,13 @@ pub fn generate_usage_str(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn generate_usage_str_do(
|
pub(crate) fn generate_usage_str_do<'cli>(
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
cli_cmd: &CliCommand,
|
cli_cmd: &CliCommand,
|
||||||
format: DocumentationFormat,
|
format: DocumentationFormat,
|
||||||
indent: &str,
|
indent: &str,
|
||||||
skip_options: &[&str],
|
skip_options: &[&str],
|
||||||
global_options_iter: impl Iterator<Item = &'static str>,
|
global_options_iter: impl Iterator<Item = &'cli GlobalOptions>,
|
||||||
) -> String {
|
) -> String {
|
||||||
let arg_param = cli_cmd.arg_param;
|
let arg_param = cli_cmd.arg_param;
|
||||||
let fixed_param = &cli_cmd.fixed_param;
|
let fixed_param = &cli_cmd.fixed_param;
|
||||||
@ -212,23 +212,44 @@ pub(crate) fn generate_usage_str_do(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut global_options = String::new();
|
let mut global_options = String::new();
|
||||||
for opt in global_options_iter {
|
|
||||||
use std::fmt::Write as _;
|
|
||||||
|
|
||||||
if done_hash.contains(opt) {
|
for (name, _optional, param_schema) in
|
||||||
|
global_options_iter.flat_map(|o| o.schema.any_object().unwrap().properties())
|
||||||
|
{
|
||||||
|
if done_hash.contains(name) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if !global_options.is_empty() {
|
if format == DocumentationFormat::ReST {
|
||||||
if matches!(format, DocumentationFormat::ReST) {
|
use std::fmt::Write as _;
|
||||||
|
|
||||||
|
// In the ReST outputs we don't include the documentation for global options each time
|
||||||
|
// as this is mostly used for the man page and we have a separate section before
|
||||||
|
// labeled
|
||||||
|
// "Options available for command group <stuff>:"
|
||||||
|
// which documents them fully.
|
||||||
|
//
|
||||||
|
// FIXME: Ideally we'd instead be able to tell the difference between generating the
|
||||||
|
// entire tree or just a single command's documentation to know whether to print all of
|
||||||
|
// them?
|
||||||
|
|
||||||
|
if !global_options.is_empty() {
|
||||||
global_options.push_str("\n\n");
|
global_options.push_str("\n\n");
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
let _ = write!(global_options, "``--{name}``");
|
||||||
|
} else {
|
||||||
|
// For the other ones we use the same generation method as for any other option:
|
||||||
|
|
||||||
|
if !global_options.is_empty() {
|
||||||
global_options.push('\n');
|
global_options.push('\n');
|
||||||
}
|
}
|
||||||
|
global_options.push_str(&get_property_description(
|
||||||
|
name,
|
||||||
|
param_schema,
|
||||||
|
ParameterDisplayStyle::Arg,
|
||||||
|
format,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
let _ = match format {
|
|
||||||
DocumentationFormat::ReST => write!(global_options, "``--{opt}``"),
|
|
||||||
_ => write!(global_options, "--{opt}"),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !global_options.is_empty() {
|
if !global_options.is_empty() {
|
||||||
@ -246,11 +267,11 @@ pub fn print_simple_usage_error(prefix: &str, cli_cmd: &CliCommand, err_msg: &st
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Print command usage for simple commands to ``stderr``.
|
/// Print command usage for simple commands to ``stderr``.
|
||||||
pub(crate) fn print_simple_usage_error_do(
|
pub(crate) fn print_simple_usage_error_do<'cli>(
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
cli_cmd: &CliCommand,
|
cli_cmd: &CliCommand,
|
||||||
err_msg: &str,
|
err_msg: &str,
|
||||||
global_options_iter: impl Iterator<Item = &'static str>,
|
global_options_iter: impl Iterator<Item = &'cli GlobalOptions>,
|
||||||
) {
|
) {
|
||||||
let usage = generate_usage_str_do(
|
let usage = generate_usage_str_do(
|
||||||
prefix,
|
prefix,
|
||||||
@ -271,14 +292,13 @@ pub fn print_nested_usage_error(prefix: &str, def: &CliCommandMap, err_msg: &str
|
|||||||
|
|
||||||
/// While going through nested commands, this keeps track of the available global options.
|
/// While going through nested commands, this keeps track of the available global options.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct UsageState {
|
struct UsageState<'cli> {
|
||||||
global_options: Vec<Vec<&'static Schema>>,
|
global_options: Vec<Vec<&'cli GlobalOptions>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsageState {
|
impl<'cli> UsageState<'cli> {
|
||||||
fn push_global_options(&mut self, options: &HashMap<std::any::TypeId, GlobalOptions>) {
|
fn push_global_options(&mut self, options: &'cli HashMap<std::any::TypeId, GlobalOptions>) {
|
||||||
self.global_options
|
self.global_options.push(options.values().collect());
|
||||||
.push(options.values().map(|o| o.schema).collect());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_global_options(&mut self) {
|
fn pop_global_options(&mut self) {
|
||||||
@ -307,6 +327,7 @@ impl UsageState {
|
|||||||
let _ = write!(out, "Options available for command group ``{prefix}``:");
|
let _ = write!(out, "Options available for command group ``{prefix}``:");
|
||||||
for opt in opts {
|
for opt in opts {
|
||||||
for (name, _optional, schema) in opt
|
for (name, _optional, schema) in opt
|
||||||
|
.schema
|
||||||
.any_object()
|
.any_object()
|
||||||
.expect("non-object schema in global optiosn")
|
.expect("non-object schema in global optiosn")
|
||||||
.properties()
|
.properties()
|
||||||
@ -322,12 +343,10 @@ impl UsageState {
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
fn global_options_iter(&self) -> impl Iterator<Item = &'static str> + '_ {
|
fn global_options_iter(&self) -> impl Iterator<Item = &'cli GlobalOptions> + '_ {
|
||||||
self.global_options
|
self.global_options
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|list| list.iter().copied())
|
.flat_map(|list| list.iter().copied())
|
||||||
.flat_map(|o| o.any_object().unwrap().properties())
|
|
||||||
.map(|(name, _optional, _schema)| *name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,10 +359,10 @@ pub fn generate_nested_usage(
|
|||||||
generate_nested_usage_do(&mut UsageState::default(), prefix, def, format)
|
generate_nested_usage_do(&mut UsageState::default(), prefix, def, format)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_nested_usage_do(
|
fn generate_nested_usage_do<'cli>(
|
||||||
state: &mut UsageState,
|
state: &mut UsageState<'cli>,
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
def: &CliCommandMap,
|
def: &'cli CliCommandMap,
|
||||||
format: DocumentationFormat,
|
format: DocumentationFormat,
|
||||||
) -> String {
|
) -> String {
|
||||||
state.push_global_options(&def.global_options);
|
state.push_global_options(&def.global_options);
|
||||||
|
@ -550,7 +550,7 @@ impl<'cli> CommandLineParseState<'cli> {
|
|||||||
args,
|
args,
|
||||||
rpcenv,
|
rpcenv,
|
||||||
self.async_run,
|
self.async_run,
|
||||||
self.global_option_schemas.keys().copied(),
|
self.global_option_types.values().copied(),
|
||||||
);
|
);
|
||||||
command::set_help_context(None);
|
command::set_help_context(None);
|
||||||
out
|
out
|
||||||
|
@ -136,8 +136,10 @@ Optional parameters:
|
|||||||
|
|
||||||
Inherited group parameters:
|
Inherited group parameters:
|
||||||
|
|
||||||
--global1
|
--global1 one|two
|
||||||
--global2
|
A global option.
|
||||||
|
--global2 <string>
|
||||||
|
A second global option.
|
||||||
"##
|
"##
|
||||||
.trim_start()
|
.trim_start()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user