From: Wolfgang Bumiller Date: Mon, 12 Mar 2018 12:04:15 +0000 (+0100) Subject: cli: more generic interactive parameter definition X-Git-Url: https://git.proxmox.com/?p=pve-common.git;a=commitdiff_plain;h=c7171ff272c9070958c8db1135b9305d6197f307 cli: more generic interactive parameter definition Instead of hardcoding 'password' as a special case in the JSONSchema's getopt handling, extend the new parameter mapping to allow defining a parameters as 'interactive'. They also take an optional argument on the command line directly. This effectively deprecates the password special case which should be replaced in pct/pveum/... and then dropped in pve-common. Signed-off-by: Wolfgang Bumiller --- diff --git a/src/PVE/JSONSchema.pm b/src/PVE/JSONSchema.pm index 9861a8f..0e722b8 100644 --- a/src/PVE/JSONSchema.pm +++ b/src/PVE/JSONSchema.pm @@ -1333,7 +1333,7 @@ sub method_get_child_link { # a way to parse command line parameters, using a # schema to configure Getopt::Long sub get_options { - my ($schema, $args, $arg_param, $fixed_param, $pwcallback) = @_; + my ($schema, $args, $arg_param, $fixed_param, $pwcallback, $param_mapping_hash) = @_; if (!$schema || !$schema->{properties}) { raise("too many arguments\n", code => HTTP_BAD_REQUEST) @@ -1349,13 +1349,20 @@ sub get_options { $list_param = $arg_param; } + my @interactive = (); my @getopt = (); foreach my $prop (keys %{$schema->{properties}}) { my $pd = $schema->{properties}->{$prop}; next if $list_param && $prop eq $list_param; next if defined($fixed_param->{$prop}); - if ($prop eq 'password' && $pwcallback) { + my $mapping = $param_mapping_hash->{$prop}; + if ($mapping && $mapping->{interactive}) { + # interactive parameters such as passwords: make the argument + # optional and call the mapping function afterwards. + push @getopt, "$prop:s"; + push @interactive, [$prop, $mapping->{func}]; + } elsif ($prop eq 'password' && $pwcallback) { # we do not accept plain password on input line, instead # we turn this into a boolean option and ask for password below # using $pwcallback() (for security reasons). @@ -1409,6 +1416,15 @@ sub get_options { } } + foreach my $entry (@interactive) { + my ($opt, $func) = @$entry; + my $pd = $schema->{properties}->{$opt}; + my $value = $opts->{$opt}; + if (defined($value) || !$pd->{optional}) { + $opts->{$opt} = $func->($value); + } + } + # decode after Getopt as we are not sure how well it handles unicode foreach my $p (keys %$opts) { if (!ref($opts->{$p})) { diff --git a/src/PVE/RESTHandler.pm b/src/PVE/RESTHandler.pm index 0a64158..3f5c732 100644 --- a/src/PVE/RESTHandler.pm +++ b/src/PVE/RESTHandler.pm @@ -514,15 +514,15 @@ my $compute_param_mapping_hash = sub { return $res if !defined($mapping_array); foreach my $item (@$mapping_array) { - my ($name, $func, $desc); + my ($name, $func, $desc, $interactive); if (ref($item) eq 'ARRAY') { - ($name, $func, $desc) = @$item; + ($name, $func, $desc, $interactive) = @$item; } else { $name = $item; $func = sub { return PVE::Tools::file_get_contents($_[0]) }; } $desc //= ''; - $res->{$name} = { desc => $desc, func => $func }; + $res->{$name} = { desc => $desc, func => $func, interactive => $interactive }; } return $res; @@ -691,6 +691,7 @@ my $replace_file_names_with_contents = sub { my ($param, $param_mapping_hash) = @_; while (my ($k, $d) = each %$param_mapping_hash) { + next if $d->{interactive}; # handled by the JSONSchema's get_options code $param->{$k} = $d->{func}->($param->{$k}) if defined($param->{$k}); } @@ -705,10 +706,10 @@ sub cli_handler { my $res; eval { - my $param = PVE::JSONSchema::get_options($info->{parameters}, $args, $arg_param, $fixed_param, $read_password_func); + my $param_mapping_hash = $compute_param_mapping_hash->($param_mapping_func->($name)) if $param_mapping_func; + my $param = PVE::JSONSchema::get_options($info->{parameters}, $args, $arg_param, $fixed_param, $read_password_func, $param_mapping_hash); - if (defined($param_mapping_func)) { - my $param_mapping_hash = $compute_param_mapping_hash->(&$param_mapping_func($name)); + if (defined($param_mapping_hash)) { &$replace_file_names_with_contents($param, $param_mapping_hash); }