1 # Copyright © 2008 Frank Lichtenheld <frank@lichtenheld.de>
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program. If not, you can find it on the World Wide
15 # Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free
16 # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19 package Maemian::Command;
24 # Disabling IPC::Run::Debug saves tons of useless calls.
25 $ENV{'IPCRUNDEBUG'} = 'none';
28 use base qw(Exporter);
30 our @EXPORT_OK = qw(spawn reap kill);
32 use IPC::Run qw(run harness kill_kill);
36 Lintian::Command - Utilities to execute other commands from lintian code
40 use Lintian::Command qw(spawn);
42 # simplest possible call
43 my $success = spawn({}, ['command']);
47 $success = spawn($opts, ['command']);
49 print "STDOUT: $opts->{out}\n";
50 print "STDERR: $opts->{err}\n";
54 $opts = { in => 'infile.txt', out => 'outfile.txt' };
55 $success = spawn($opts, ['command']);
58 $success = spawn({}, ['command'], "|", ['othercommand']);
62 Lintian::Command is a thin wrapper around IPC::Run, that catches exception
63 and implements a useful default behaviour for input and output redirection.
65 Lintian::Command provides a function spawn() which is a wrapper
66 around IPC::Run::run() resp. IPC::Run::start() (depending on whether a
67 pipe is requested). To wait for finished child processes, it also
68 provides the reap() function as a wrapper around IPC::Run::finish().
70 =head2 C<spawn($opts, @cmds)>
72 The @cmds array is given to IPC::Run::run() (or ::start()) unaltered, but
73 should only be used for commands and piping symbols (i.e. all of the elements
74 should be either an array reference, a code reference, '|', or '&'). I/O
75 redirection is handled via the $opts hash reference. If you need more fine
76 grained control than that, you should just use IPC::Run directly.
78 $opts is a hash reference which can be used to set options and to retrieve
79 the status and output of the command executed.
81 The following hash keys can be set to alter the behaviour of spawn():
87 STDIN for the first forked child. Defaults to C<\undef>.
91 Use a pipe for STDIN and start the process in the background.
92 You will need to close the pipe after use and call $opts->{harness}->finish
93 in order for the started process to end properly.
97 STDOUT of the last forked child. Will be set to a newly created
98 scalar reference by default which can be used to retrieve the output
103 Use a pipe for STDOUT and start the process in the background.
104 You will need to call $opts->{harness}->finish in order for the started
105 process to end properly.
109 STDERR of all forked childs. Defaults to STDERR of the parent.
113 Use a pipe for STDERR and start the process in the background.
114 You will need to call $opts->{harness}->finish in order for the started
115 process to end properly.
119 Configures the behaviour in case of errors. The default is 'exception',
120 which will cause spawn() to die in case of exceptions thrown by IPC::Run.
121 If set to 'error' instead, it will also die if the command exits
122 with a non-zero error code. If exceptions should be handled by the caller,
123 setting it to 'never' will cause it to store the exception in the
124 C<exception> key instead.
128 The following additional keys will be set during the execution of spawn():
134 Will contain the IPC::Run object used for the call which can be used to
135 query the exit values of the forked programs (E.g. with results() and
136 full_results()) and to wait for processes started in the background.
140 If an exception is raised during the execution of the commands,
141 and if C<fail> is set to 'never', the exception will be caught and
142 stored under this key.
146 Will contain the return value of spawn().
153 my ($opts, @cmds) = @_;
155 if (ref($opts) ne 'HASH') {
158 $opts->{fail} ||= 'exception';
160 my ($out, $background);
161 my (@out, @in, @err);
162 if ($opts->{pipe_in}) {
163 @in = ('<pipe', $opts->{pipe_in});
166 $opts->{in} ||= \undef;
167 @in = ('<', $opts->{in});
169 if ($opts->{pipe_out}) {
170 @out = ('>pipe', $opts->{pipe_out});
173 $opts->{out} ||= \$out;
174 @out = ('>', $opts->{out});
176 if ($opts->{pipe_err}) {
177 @err = ('2>pipe', $opts->{pipe_err});
180 $opts->{err} ||= \*STDERR;
181 @err = ('2>', $opts->{err});
185 # print STDERR Dumper($opts, \@cmds);
189 my $last = pop @$cmd;
190 # Support shell-style "command &"
196 $opts->{harness} = harness($cmd, @in, @out, @err);
198 my ($first, $last) = (shift @cmds, pop @cmds);
199 # Support shell-style "command &"
205 $opts->{harness} = harness($first, @in, @cmds, @out, @err);
208 $opts->{success} = $opts->{harness}->start;
210 $opts->{success} = $opts->{harness}->run;
215 Util::fail($@) if $opts->{fail} ne 'never';
216 $opts->{success} = 0;
217 $opts->{exception} = $@;
218 } elsif ($opts->{fail} eq 'error'
219 and !$opts->{success}) {
221 if ($opts->{description}) {
222 Util::fail("$opts->{description} failed with error code ".
223 $opts->{harness}->result);
224 } elsif (@cmds == 1) {
225 Util::fail("$cmds[0][0] failed with error code ".
226 $opts->{harness}->result);
228 Util::fail("command failed with error code ".
229 $opts->{harness}->result);
232 # print STDERR Dumper($opts, \@cmds);
233 return $opts->{success};
236 =head2 C<reap($opts[, $opts[,...]])>
238 If you used one of the C<pipe_*> options to spawn() or used the shell-style "&"
239 operator to send the process to the background, you will need to wait for your
240 child processes to finish. For this you can use the reap() function,
241 which you can call with the $opts hash reference you gave to spawn() and which
242 will do the right thing. Multiple $opts can be passed.
244 Note however that this function will not close any of the pipes for you, so
245 you probably want to do that first before calling this function.
247 The following keys of the $opts hash have roughly the same function as
262 All other keys are probably just ignored.
268 while (my $opts = shift @_) {
269 next unless defined($opts->{harness});
272 $opts->{success} = $opts->{harness}->finish;
276 Util::fail($@) if $opts->{fail} ne 'never';
277 $opts->{success} = 0;
278 $opts->{exception} = $@;
279 } elsif ($opts->{fail} eq 'error'
280 and !$opts->{success}) {
282 if ($opts->{description}) {
283 Util::fail("$opts->{description} failed with error code ".
284 $opts->{harness}->result);
286 Util::fail("command failed with error code ".
287 $opts->{harness}->result);
290 $status &&= $opts->{success};
295 =head2 C<kill($opts[, $opts[, ...]])>
297 This is a simple wrapper around the kill_kill function. It doesn't allow
298 any customisation, but takes an $opts hash ref and SIGKILLs the process
299 two seconds after SIGTERM is sent. If multiple hash refs are passed it
300 executes kill_kill on each of them. The return status is the ORed value of
301 all the executions of kill_kill.
307 while (my $opts = shift @_) {
308 $status &&= kill_kill($opts->{'harness'}, grace => 2);
318 Lintian::Command exports nothing by default, but you can export the
319 spawn() and reap() functions.
323 Originally written by Frank Lichtenheld <djpig@debian.org> for Lintian.