forked from Proxmox/proxmox
cli: deal with commands without positional args
When reaching the final command we relied on the positional parameters "ending" the global option parsing. This means we did not get global options at the end, and failed with "unknown option" instead. Fix this by simply retaining unknown options in that case and not stopping at positional parameters. Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
fee00addab
commit
5eb7cbd250
@ -263,6 +263,7 @@ pub(crate) struct ParseOptions<'t, 'o> {
|
||||
stop_at_positional: bool,
|
||||
stop_at_unknown: bool,
|
||||
deny_unknown: bool,
|
||||
retain_unknown: bool,
|
||||
retain_separator: bool,
|
||||
}
|
||||
|
||||
@ -278,6 +279,7 @@ impl<'t, 'o> ParseOptions<'t, 'o> {
|
||||
stop_at_positional: false,
|
||||
stop_at_unknown: false,
|
||||
deny_unknown: false,
|
||||
retain_unknown: false,
|
||||
retain_separator: false,
|
||||
}
|
||||
}
|
||||
@ -288,6 +290,12 @@ impl<'t, 'o> ParseOptions<'t, 'o> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Builder style option to retain unknown parameters in the returned argument array.
|
||||
pub fn retain_unknown(mut self, deny: bool) -> Self {
|
||||
self.retain_unknown = deny;
|
||||
self
|
||||
}
|
||||
|
||||
/// Builder style option to stop parsing on unknown parameters.
|
||||
/// This implies deny_unknown`.
|
||||
/// Useful for bash completion.
|
||||
@ -351,12 +359,19 @@ impl<'t, 'o> ParseOptions<'t, 'o> {
|
||||
|
||||
let opt_schema = self.option_schemas.get(option).copied();
|
||||
|
||||
if self.deny_unknown && opt_schema.is_none() {
|
||||
if self.stop_at_unknown {
|
||||
if opt_schema.is_none() {
|
||||
if self.retain_unknown {
|
||||
positional.push(orig_arg);
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
if self.deny_unknown {
|
||||
if self.stop_at_unknown {
|
||||
positional.push(orig_arg);
|
||||
break;
|
||||
}
|
||||
errors.push(option.to_string(), format_err!("unknown option {option:?}"));
|
||||
}
|
||||
errors.push(option.to_string(), format_err!("unknown option {option:?}"));
|
||||
}
|
||||
|
||||
if let Some(value) = value {
|
||||
|
@ -464,11 +464,16 @@ impl<'cli> CommandLineParseState<'cli> {
|
||||
}
|
||||
|
||||
/// Parse out the current global options and return the remaining `args`.
|
||||
fn handle_current_global_options(&mut self, args: Vec<String>) -> Result<Vec<String>, Error> {
|
||||
fn handle_current_global_options(
|
||||
&mut self,
|
||||
args: Vec<String>,
|
||||
needs_subcommand: bool,
|
||||
) -> Result<Vec<String>, Error> {
|
||||
let mut global_args = Vec::new();
|
||||
let args = getopts::ParseOptions::new(&mut global_args, &self.global_option_schemas)
|
||||
.stop_at_positional(true)
|
||||
.deny_unknown(true)
|
||||
.deny_unknown(needs_subcommand)
|
||||
.stop_at_positional(needs_subcommand)
|
||||
.retain_unknown(!needs_subcommand)
|
||||
.parse(args)?;
|
||||
// and merge them into the hash map
|
||||
for (option, argument) in global_args {
|
||||
@ -505,7 +510,7 @@ impl<'cli> CommandLineParseState<'cli> {
|
||||
|
||||
self.enable_global_options(cli);
|
||||
|
||||
let mut args = self.handle_current_global_options(args)?;
|
||||
let mut args = self.handle_current_global_options(args, true)?;
|
||||
|
||||
// now deal with the actual subcommand list
|
||||
if args.is_empty() {
|
||||
@ -538,7 +543,7 @@ impl<'cli> CommandLineParseState<'cli> {
|
||||
rpcenv: &mut CliEnvironment,
|
||||
args: Vec<String>,
|
||||
) -> Result<Invocation<'cli>, Error> {
|
||||
let args = self.handle_current_global_options(args)?;
|
||||
let args = self.handle_current_global_options(args, false)?;
|
||||
self.build_global_options(&mut *rpcenv)?;
|
||||
let interface = Arc::clone(&self.interface);
|
||||
Ok(Invocation {
|
||||
|
Loading…
Reference in New Issue
Block a user