pve-common/data/PVE/CLIHandler.pm
2011-08-23 07:31:48 +02:00

196 lines
4.3 KiB
Perl

package PVE::CLIHandler;
use strict;
use warnings;
use PVE::Exception qw(raise raise_param_exc);
use PVE::RESTHandler;
use PVE::PodParser;
use base qw(PVE::RESTHandler);
my $cmddef;
my $exename;
my $expand_command_name = sub {
my ($def, $cmd) = @_;
if (!$def->{$cmd}) {
my $expanded;
for my $k (keys(%$def)) {
if ($k =~ m/^$cmd/) {
if ($expanded) {
$expanded = undef; # more than one match
last;
} else {
$expanded = $k;
}
}
}
$cmd = $expanded if $expanded;
}
return $cmd;
};
__PACKAGE__->register_method ({
name => 'help',
path => 'help',
method => 'GET',
description => "Get help about specified command.",
parameters => {
additionalProperties => 0,
properties => {
cmd => {
description => "Command name",
type => 'string',
optional => 1,
},
verbose => {
description => "Verbose output format.",
type => 'boolean',
optional => 1,
},
},
},
returns => { type => 'null' },
code => sub {
my ($param) = @_;
die "not initialized" if !($cmddef && $exename);
my $cmd = $param->{cmd};
my $verbose = defined($cmd) && $cmd;
$verbose = $param->{verbose} if defined($param->{verbose});
if (!$cmd) {
if ($verbose) {
print_usage_verbose();
} else {
print_usage_short(\*STDOUT);
}
return undef;
}
$cmd = &$expand_command_name($cmddef, $cmd);
my ($class, $name, $arg_param, $uri_param) = @{$cmddef->{$cmd} || []};
raise_param_exc({ cmd => "no such command '$cmd'"}) if !$class;
my $str = $class->usage_str($name, "$exename $cmd", $arg_param, $uri_param, $verbose ? 'full' : 'short');
if ($verbose) {
print "$str\n";
} else {
print "USAGE: $str\n";
}
return undef;
}});
sub print_pod_manpage {
my ($podfn) = @_;
die "not initialized" if !($cmddef && $exename);
die "no pod file specified" if !$podfn;
my $synopsis = "";
$synopsis .= " $exename <COMMAND> [ARGS] [OPTIONS]\n\n";
my $style = 'full'; # or should we use 'short'?
my $oldclass;
foreach my $cmd (sorted_commands()) {
my ($class, $name, $arg_param, $uri_param) = @{$cmddef->{$cmd}};
my $str = $class->usage_str($name, "$exename $cmd", $arg_param,
$uri_param, $style);
$str =~ s/^USAGE: //;
$synopsis .= "\n" if $oldclass && $oldclass ne $class;
$str =~ s/\n/\n /g;
$synopsis .= " $str\n\n";
$oldclass = $class;
}
$synopsis .= "\n";
my $parser = PVE::PodParser->new();
$parser->{include}->{synopsis} = $synopsis;
$parser->parse_from_file($podfn);
}
sub print_usage_verbose {
die "not initialized" if !($cmddef && $exename);
print "USAGE: $exename <COMMAND> [ARGS] [OPTIONS]\n\n";
foreach my $cmd (sort keys %$cmddef) {
my ($class, $name, $arg_param, $uri_param) = @{$cmddef->{$cmd}};
my $str = $class->usage_str($name, "$exename $cmd", $arg_param, $uri_param, 'full');
print "$str\n\n";
}
}
sub sorted_commands {
return sort { ($cmddef->{$a}->[0] cmp $cmddef->{$b}->[0]) || ($a cmp $b)} keys %$cmddef;
}
sub print_usage_short {
my ($fd, $msg) = @_;
die "not initialized" if !($cmddef && $exename);
print $fd "ERROR: $msg\n" if $msg;
print $fd "USAGE: $exename <COMMAND> [ARGS] [OPTIONS]\n";
my $oldclass;
foreach my $cmd (sorted_commands()) {
my ($class, $name, $arg_param, $uri_param) = @{$cmddef->{$cmd}};
my $str = $class->usage_str($name, "$exename $cmd", $arg_param, $uri_param, 'short');
print $fd "\n" if $oldclass && $oldclass ne $class;
print $fd " $str";
$oldclass = $class;
}
}
sub handle_cmd {
my ($def, $cmdname, $cmd, $args, $pwcallback, $podfn) = @_;
$cmddef = $def;
$exename = $cmdname;
$cmddef->{help} = [ __PACKAGE__, 'help', ['cmd'] ];
if (!$cmd) {
print_usage_short (\*STDERR, "no command specified");
exit (-1);
} elsif ($cmd eq 'verifyapi') {
PVE::RESTHandler::validate_method_schemas();
return;
} elsif ($cmd eq 'printmanpod') {
print_pod_manpage($podfn);
return;
}
$cmd = &$expand_command_name($cmddef, $cmd);
my ($class, $name, $arg_param, $uri_param, $outsub) = @{$cmddef->{$cmd} || []};
if (!$class) {
print_usage_short (\*STDERR, "unknown command '$cmd'");
exit (-1);
}
my $prefix = "$exename $cmd";
my $res = $class->cli_handler($prefix, $name, \@ARGV, $arg_param, $uri_param, $pwcallback);
if ($outsub) {
&$outsub($res);
}
}
1;