Command-Runner
view release on metacpan or search on metacpan
lib/Command/Runner.pm view on Meta::CPAN
my $pid;
if (ref $command) {
my @cmd = map { Command::Runner::Quote::quote_win32($_) } $command->@*;
local %ENV = $self->{env}->%* if $self->{env};
my $guard = File::pushd::pushd($self->{cwd}) if $self->{cwd};
$pid = system { $command->[0] } 1, @cmd;
} else {
local %ENV = $self->{env}->%* if $self->{env};
my $guard = File::pushd::pushd($self->{cwd}) if $self->{cwd};
$pid = system 1, $command;
}
my $timeout = $self->{timeout} ? Command::Runner::Timeout->new($self->{timeout}, 1) : undef;
my $INT; local $SIG{INT} = sub (@) { $INT++ };
my $result;
while (1) {
if ($INT) {
kill INT => $pid;
$INT = 0;
}
my $res = waitpid $pid, POSIX::WNOHANG();
if ($res == -1) {
warn "waitpid($pid, POSIX::WNOHANG()) returns unexpectedly -1";
last;
} elsif ($res > 0) {
$result = $?;
last;
} else {
if ($timeout and my $signal = $timeout->signal) {
kill $signal => $pid;
}
Time::HiRes::sleep($TICK);
}
}
return { pid => $pid, result => $result, timeout => $timeout && $timeout->signaled };
}
sub _exec ($self, $command) {
pipe my $stdout_read, my $stdout_write;
$self->{_buffer}{stdout} = Command::Runner::LineBuffer->new(keep => $self->{keep});
my ($stderr_read, $stderr_write);
if (!$self->{redirect}) {
pipe $stderr_read, $stderr_write;
$self->{_buffer}{stderr} = Command::Runner::LineBuffer->new(keep => $self->{keep});
}
my $pid = fork;
die "fork: $!" unless defined $pid;
if ($pid == 0) {
close $_ for grep $_, $stdout_read, $stderr_read;
open STDOUT, ">&", $stdout_write;
if ($self->{redirect}) {
open STDERR, ">&", \*STDOUT;
} else {
open STDERR, ">&", $stderr_write;
}
if ($Config::Config{d_setpgrp}) {
POSIX::setpgid(0, 0) or die "setpgid: $!";
}
if ($self->{cwd}) {
chdir $self->{cwd} or die "chdir $self->{cwd}: $!";
}
if ($self->{env}) {
%ENV = $self->{env}->%*;
}
if (ref $command) {
exec { $command->[0] } $command->@*;
} else {
exec $command;
}
exit 127;
}
close $_ for grep $_, $stdout_write, $stderr_write;
my $signal_pid = $Config::Config{d_setpgrp} ? -$pid : $pid;
my $INT; local $SIG{INT} = sub (@) { $INT++ };
my $timeout = $self->{timeout} ? Command::Runner::Timeout->new($self->{timeout}, 1) : undef;
my $select = IO::Select->new(grep $_, $stdout_read, $stderr_read);
while ($select->count) {
if ($INT) {
kill INT => $signal_pid;
$INT = 0;
}
if ($timeout and my $signal = $timeout->signal) {
kill $signal => $signal_pid;
}
for my $ready ($select->can_read($TICK)) {
my $type = $ready == $stdout_read ? "stdout" : "stderr";
my $len = sysread $ready, my $buf, 64*1024;
if ($len) {
my $buffer = $self->{_buffer}{$type};
$buffer->add($buf);
next unless my @line = $buffer->get;
next unless my $sub = $self->{$type};
$sub->($_) for @line;
} else {
warn "sysread $type pipe failed: $!" unless defined $len;
$select->remove($ready);
close $ready;
}
}
}
for my $type (qw(stdout stderr)) {
next unless my $sub = $self->{$type};
my $buffer = $self->{_buffer}{$type} or next;
my @line = $buffer->get(1) or next;
$sub->($_) for @line;
}
close $_ for $select->handles;
waitpid $pid, 0;
my $res = {
pid => $pid,
result => $?,
timeout => $timeout && $timeout->signaled,
( run in 3.330 seconds using v1.01-cache-2.11-cpan-5735350b133 )