diff options
Diffstat (limited to 'lib/App/Beam/Command.pm')
-rw-r--r-- | lib/App/Beam/Command.pm | 44 |
1 files changed, 39 insertions, 5 deletions
diff --git a/lib/App/Beam/Command.pm b/lib/App/Beam/Command.pm index 79b8b06..4f92cdf 100644 --- a/lib/App/Beam/Command.pm +++ b/lib/App/Beam/Command.pm @@ -12,6 +12,7 @@ our %EXPORT_TAGS = ( use IPC::Open3; use Symbol 'gensym'; +use POSIX qw(:sys_wait_h); sub new { my $class = shift; @@ -28,6 +29,24 @@ use constant { CHAN_STDERR => 1 }; +sub start_log { + my ($self, $chan, $rfd) = @_; + + if (exists($self->{log}) && defined($self->{log}[$chan])) { + local $^F = fileno($rfd); + my $pid = fork(); + if ($pid == 0) { + local $_ = $rfd; + &{$self->{log}[CHAN_STDERR]}; + exit(0); + } else { + push @{$self->{pids}}, $pid; + return undef; + } + } + return $rfd; +} + sub run { my $self = shift; my $out = gensym; @@ -36,25 +55,39 @@ sub run { return $self->{status} if exists($self->{status}); eval { - my $pid = open3(\*STDIN, $out, $err, @{$self->{argv}}); - waitpid($pid, 0); + push @{$self->{pids}}, + open3(\*STDIN, $out, $err, @{$self->{argv}}); + $out = $self->start_log(CHAN_STDOUT, $out); + $err = $self->start_log(CHAN_STDERR, $err); + do { + my $pid = waitpid(-1, 0); + if ($pid > 0) { + @{$self->{pids}} = grep { $pid != $_ } @{$self->{pids}}; + } + } while ($#{$self->{pids}} >= 0); }; if ($@) { $self->{status} = $@; } else { $self->{status} = $?; local $/ = undef; - $self->{channel}[CHAN_STDOUT] = <$out>; - $self->{channel}[CHAN_STDERR] = <$err>; + $self->{channel}[CHAN_STDOUT] = defined($out) ? <$out> : undef; + $self->{channel}[CHAN_STDERR] = defined($err) ? <$err> : undef; } return $self->{status}; } +sub set_logger { + my ($self, $chan, $fun) = @_; + $self->{log}[$chan] = $fun; +} + sub restart { my $self = shift; delete $self->{status}; delete $self->{channel}; + delete $self->{pids}; return $self->run; } @@ -66,7 +99,8 @@ sub status { sub channel { my ($self, $chan) = @_; - return undef if !exists($self->{channel}) || $chan > $#{$self->{channel}}; + return undef + unless (exists($self->{channel}) && defined($self->{channel}[$chan])); open(my $fd, '<', \$self->{channel}[$chan]) or croak "can't dup: $!"; return $fd; } |