]> git.proxmox.com Git - pve-common.git/blobdiff - src/PVE/CLIHandler.pm
run_cli: skip environment init for PVE::Service::* classes
[pve-common.git] / src / PVE / CLIHandler.pm
index aee6bb2a4f8de2581a763b2520709b32bd5525bc..e6fd415b3ef4fd237c03db93eb038e835e7d1bed 100644 (file)
@@ -34,6 +34,19 @@ my $expand_command_name = sub {
     return $cmd;
 };
 
+my $complete_command_names = sub {
+    my $res = [];
+
+    return if ref($cmddef) ne 'HASH';
+
+    foreach my $cmd (keys %$cmddef) {
+       next if $cmd eq 'help';
+       push @$res, $cmd;
+    }
+
+    return $res;
+};
+
 __PACKAGE__->register_method ({
     name => 'help', 
     path => 'help',
@@ -46,6 +59,7 @@ __PACKAGE__->register_method ({
                description => "Command name",
                type => 'string',
                optional => 1,
+               completion => $complete_command_names,
            },
            verbose => {
                description => "Verbose output format.",
@@ -93,6 +107,20 @@ __PACKAGE__->register_method ({
 
     }});
 
+sub print_simple_pod_manpage {
+    my ($podfn, $class, $name, $arg_param, $uri_param) = @_;
+
+    my $synopsis = " $name help\n\n";
+    my $str = $class->usage_str($name, $name, $arg_param, $uri_param, 'long');
+    $str =~ s/^USAGE://;
+    $str =~ s/\n/\n /g;
+    $synopsis .= $str;
+
+    my $parser = PVE::PodParser->new();
+    $parser->{include}->{synopsis} = $synopsis;
+    $parser->parse_from_file($podfn);
+}
+
 sub print_pod_manpage {
     my ($podfn) = @_;
 
@@ -269,57 +297,103 @@ sub verify_api {
     PVE::RESTHandler::validate_method_schemas();
 }
 
-sub generate_pod_manpage {
-    my ($class, $podfn) = @_;
+sub generate_bash_completions {
+    my ($class) = @_;
 
-    no strict 'refs'; 
-    $cmddef = ${"${class}::cmddef"};
+    # generate bash completion config
 
     $exename = $class;
     $exename =~ s/^.*:://;
 
-    if (!defined($podfn)) {
-       my $cpath = "$class.pm";
-       $cpath =~ s/::/\//g;
-       foreach my $p (@INC) {
-           my $testfn = "$p/$cpath";
+    print <<__EOD__;
+# $exename bash completion
+
+# see http://tiswww.case.edu/php/chet/bash/FAQ
+# and __ltrim_colon_completions() in /usr/share/bash-completion/bash_completion
+# this modifies global var, but I found no better way
+COMP_WORDBREAKS=\${COMP_WORDBREAKS//:}
+
+complete -C '$exename bashcomplete' $exename
+__EOD__
+}
+
+sub find_cli_class_source {
+    my ($exename) = @_;
+
+    my $filename;
+
+    my $cpath = "PVE/CLI/${exename}.pm";
+    my $spath = "PVE/Service/${exename}.pm";
+    foreach my $p (@INC) {
+       foreach my $s (($cpath, $spath)) {
+           my $testfn = "$p/$s";
            if (-f $testfn) {
-               $podfn = $testfn;
+               $filename = $testfn;
                last;
            }
        }
+       last if defined($filename);
     }
 
+    return $filename;
+}
+
+sub generate_pod_manpage {
+    my ($class, $podfn) = @_;
+
+    $exename = $class;
+    $exename =~ s/^.*:://;
+
+    $podfn = find_cli_class_source($exename) if !defined($podfn);
+
     die "unable to find source for class '$class'" if !$podfn;
 
-    print_pod_manpage($podfn);
+    no strict 'refs';
+    my $def = ${"${class}::cmddef"};
+
+    if (ref($def) eq 'ARRAY') {
+       print_simple_pod_manpage($podfn, @$def);
+    } else {
+       $cmddef = $def;
+
+       $cmddef->{help} = [ __PACKAGE__, 'help', ['cmd'] ];
+
+       print_pod_manpage($podfn);
+    }
 }
 
-sub run {
-    my ($class, $pwcallback, $preparefunc) = @_;
+sub run_cli {
+    my ($class, $pwcallback, $podfn, $preparefunc) = @_;
 
     $ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
 
-    no strict 'refs';
-    $cmddef = ${"${class}::cmddef"};
-
     $exename = $class;
     $exename =~ s/^.*:://;
 
     initlog($exename);
 
-    die "please run as root\n" if $> != 0;
 
-    PVE::INotify::inotify_init();
+    if ($class !~ m/^PVE::Service::/) {
+       die "please run as root\n" if $> != 0;
 
-    my $rpcenv = PVE::RPCEnvironment->init('cli');
-    $rpcenv->init_request();
-    $rpcenv->set_language($ENV{LANG});
-    $rpcenv->set_user('root@pam');
+       PVE::INotify::inotify_init();
 
-    my $cmd = shift @ARGV;
+       my $rpcenv = PVE::RPCEnvironment->init('cli');
+       $rpcenv->init_request();
+       $rpcenv->set_language($ENV{LANG});
+       $rpcenv->set_user('root@pam');
+    }
 
-    handle_cmd($cmddef, $exename, $cmd, \@ARGV, $pwcallback, $0, $preparefunc);
+    no strict 'refs';
+    my $def = ${"${class}::cmddef"};
+
+    if (ref($def) eq 'ARRAY') {
+       handle_simple_cmd($def, \@ARGV, $pwcallback, $podfn, $preparefunc);
+    } else {
+       $cmddef = $def;
+       my $cmd = shift @ARGV;
+       handle_cmd($cmddef, $exename, $cmd, \@ARGV, $pwcallback, $podfn, $preparefunc);
+    }
 
     exit 0;
 }
@@ -339,6 +413,7 @@ sub handle_cmd {
        PVE::RESTHandler::validate_method_schemas();
        return;
     } elsif ($cmd eq 'printmanpod') {
+       $podfn = find_cli_class_source($exename) if !defined($podfn);
        print_pod_manpage($podfn);
        return;
     } elsif ($cmd eq 'bashcomplete') {
@@ -364,7 +439,7 @@ sub handle_cmd {
 }
 
 sub handle_simple_cmd {
-    my ($def, $args, $pwcallback, $podfn) = @_;
+    my ($def, $args, $pwcallback, $podfn, $preparefunc) = @_;
 
     my ($class, $name, $arg_param, $uri_param, $outsub) = @{$def};
     die "no class specified" if !$class;
@@ -383,19 +458,14 @@ sub handle_simple_cmd {
            PVE::RESTHandler::validate_method_schemas();
            return;
        } elsif ($args->[0] eq 'printmanpod') {
-           my $synopsis = " $name help\n\n";
-           my $str = $class->usage_str($name, $name, $arg_param, $uri_param, 'long');
-           $str =~ s/^USAGE://;
-           $str =~ s/\n/\n /g;
-           $synopsis .= $str;
-
-           my $parser = PVE::PodParser->new();
-           $parser->{include}->{synopsis} = $synopsis;
-           $parser->parse_from_file($podfn);
+           $podfn = find_cli_class_source($name) if !defined($podfn);
+           print_simple_pod_manpage($podfn, @$def);
            return;
        }
     }
 
+    &$preparefunc() if $preparefunc;
+
     my $res = $class->cli_handler($name, $name, \@ARGV, $arg_param, $uri_param, $pwcallback);
 
     &$outsub($res) if $outsub;