]> git.proxmox.com Git - pve-common.git/blame - data/PVE/CLIHandler.pm
correctly copy bridge config
[pve-common.git] / data / PVE / CLIHandler.pm
CommitLineData
e143e9d8
DM
1package PVE::CLIHandler;
2
3use strict;
4use warnings;
5
6use PVE::Exception qw(raise raise_param_exc);
7use PVE::RESTHandler;
8use PVE::PodParser;
9
10use base qw(PVE::RESTHandler);
11
12my $cmddef;
13my $exename;
14
15my $expand_command_name = sub {
16 my ($def, $cmd) = @_;
17
18 if (!$def->{$cmd}) {
19 my $expanded;
20 for my $k (keys(%$def)) {
21 if ($k =~ m/^$cmd/) {
22 if ($expanded) {
23 $expanded = undef; # more than one match
24 last;
25 } else {
26 $expanded = $k;
27 }
28 }
29 }
30 $cmd = $expanded if $expanded;
31 }
32 return $cmd;
33};
34
35__PACKAGE__->register_method ({
36 name => 'help',
37 path => 'help',
38 method => 'GET',
39 description => "Get help about specified command.",
40 parameters => {
41 additionalProperties => 0,
42 properties => {
43 cmd => {
44 description => "Command name",
45 type => 'string',
46 optional => 1,
47 },
48 verbose => {
49 description => "Verbose output format.",
50 type => 'boolean',
51 optional => 1,
52 },
53 },
54 },
55 returns => { type => 'null' },
56
57 code => sub {
58 my ($param) = @_;
59
60 die "not initialized" if !($cmddef && $exename);
61
62 my $cmd = $param->{cmd};
63
64 my $verbose = defined($cmd) && $cmd;
65 $verbose = $param->{verbose} if defined($param->{verbose});
66
67 if (!$cmd) {
68 if ($verbose) {
69 print_usage_verbose();
70 } else {
71 print_usage_short(\*STDOUT);
72 }
73 return undef;
74 }
75
76 $cmd = &$expand_command_name($cmddef, $cmd);
77
78 my ($class, $name, $arg_param, $uri_param) = @{$cmddef->{$cmd} || []};
79
80 raise_param_exc({ cmd => "no such command '$cmd'"}) if !$class;
81
82
83 my $str = $class->usage_str($name, "$exename $cmd", $arg_param, $uri_param, $verbose ? 'full' : 'short');
84 if ($verbose) {
85 print "$str\n";
86 } else {
87 print "USAGE: $str\n";
88 }
89
90 return undef;
91
92 }});
93
94sub print_pod_manpage {
95 my ($podfn) = @_;
96
97 die "not initialized" if !($cmddef && $exename);
98 die "no pod file specified" if !$podfn;
99
100 my $synopsis = "";
101
102 $synopsis .= " $exename <COMMAND> [ARGS] [OPTIONS]\n\n";
103
104 my $style = 'full'; # or should we use 'short'?
105 my $oldclass;
106 foreach my $cmd (sorted_commands()) {
107 my ($class, $name, $arg_param, $uri_param) = @{$cmddef->{$cmd}};
108 my $str = $class->usage_str($name, "$exename $cmd", $arg_param,
109 $uri_param, $style);
110 $str =~ s/^USAGE: //;
111
112 $synopsis .= "\n" if $oldclass && $oldclass ne $class;
113 $str =~ s/\n/\n /g;
114 $synopsis .= " $str\n\n";
115 $oldclass = $class;
116 }
117
118 $synopsis .= "\n";
119
120 my $parser = PVE::PodParser->new();
121 $parser->{include}->{synopsis} = $synopsis;
122 $parser->parse_from_file($podfn);
123}
124
125sub print_usage_verbose {
126
127 die "not initialized" if !($cmddef && $exename);
128
129 print "USAGE: $exename <COMMAND> [ARGS] [OPTIONS]\n\n";
130
131 foreach my $cmd (sort keys %$cmddef) {
132 my ($class, $name, $arg_param, $uri_param) = @{$cmddef->{$cmd}};
133 my $str = $class->usage_str($name, "$exename $cmd", $arg_param, $uri_param, 'full');
134 print "$str\n\n";
135 }
136}
137
138sub sorted_commands {
139 return sort { ($cmddef->{$a}->[0] cmp $cmddef->{$b}->[0]) || ($a cmp $b)} keys %$cmddef;
140}
141
142sub print_usage_short {
143 my ($fd, $msg) = @_;
144
145 die "not initialized" if !($cmddef && $exename);
146
147 print $fd "ERROR: $msg\n" if $msg;
148 print $fd "USAGE: $exename <COMMAND> [ARGS] [OPTIONS]\n";
149
150 my $oldclass;
151 foreach my $cmd (sorted_commands()) {
152 my ($class, $name, $arg_param, $uri_param) = @{$cmddef->{$cmd}};
153 my $str = $class->usage_str($name, "$exename $cmd", $arg_param, $uri_param, 'short');
154 print $fd "\n" if $oldclass && $oldclass ne $class;
155 print $fd " $str";
156 $oldclass = $class;
157 }
158}
159
160sub handle_cmd {
161 my ($def, $cmdname, $cmd, $args, $pwcallback, $podfn) = @_;
162
163 $cmddef = $def;
164 $exename = $cmdname;
165
166 $cmddef->{help} = [ __PACKAGE__, 'help', ['cmd'] ];
167
168 if (!$cmd) {
169 print_usage_short (\*STDERR, "no command specified");
170 exit (-1);
171 } elsif ($cmd eq 'verifyapi') {
172 PVE::RESTHandler::validate_method_schemas();
173 return;
174 } elsif ($cmd eq 'printmanpod') {
175 print_pod_manpage($podfn);
176 return;
177 }
178
179 $cmd = &$expand_command_name($cmddef, $cmd);
180
181 my ($class, $name, $arg_param, $uri_param, $outsub) = @{$cmddef->{$cmd} || []};
182
183 if (!$class) {
184 print_usage_short (\*STDERR, "unknown command '$cmd'");
185 exit (-1);
186 }
187
188 my $prefix = "$exename $cmd";
189 my $res = $class->cli_handler($prefix, $name, \@ARGV, $arg_param, $uri_param, $pwcallback);
2026f4b5
DM
190
191 &$outsub($res) if $outsub;
192}
193
194sub handle_simple_cmd {
195 my ($def, $args, $pwcallback, $podfn) = @_;
196
197 my ($class, $name, $arg_param, $uri_param, $outsub) = @{$def};
198 die "no class specified" if !$class;
199
200 if (scalar(@$args) == 1) {
201 if ($args->[0] eq 'help') {
202 my $str = "USAGE: $name help\n";
203 $str .= $class->usage_str($name, $name, $arg_param, $uri_param, 'long');
204 print STDERR "$str\n\n";
205 return;
206 } elsif ($args->[0] eq 'verifyapi') {
207 PVE::RESTHandler::validate_method_schemas();
208 return;
209 } elsif ($args->[0] eq 'printmanpod') {
210 my $synopsis = " $name help\n\n";
211 my $str = $class->usage_str($name, $name, $arg_param, $uri_param, 'long');
212 $str =~ s/^USAGE://;
213 $str =~ s/\n/\n /g;
214 $synopsis .= $str;
215
216 my $parser = PVE::PodParser->new();
217 $parser->{include}->{synopsis} = $synopsis;
218 $parser->parse_from_file($podfn);
219 return;
220 }
e143e9d8 221 }
2026f4b5
DM
222
223 my $res = $class->cli_handler($name, $name, \@ARGV, $arg_param, $uri_param, $pwcallback);
224
225 &$outsub($res) if $outsub;
e143e9d8
DM
226}
227
2281;