package App::Beam::Command; use strict; use Carp; require Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw(CHAN_STDOUT CHAN_STDERR); our %EXPORT_TAGS = ( channels => [ qw(CHAN_STDOUT CHAN_STDERR) ] ); use IPC::Open3; use Symbol 'gensym'; sub new { my $class = shift; return bless { argv => \@_ }, $class; } sub add { my $self = shift; push @{$self->{argv}}, @_; } use constant { CHAN_STDOUT => 0, CHAN_STDERR => 1 }; sub run { my $self = shift; my $out = gensym; my $err = gensym; return $self->{status} if exists($self->{status}); my $pid = open3(\*STDIN, $out, $err, @{$self->{argv}}); waitpid($pid, 0); $self->{status} = $?; local $/ = undef; $self->{channel}[CHAN_STDOUT] = <$out>; $self->{channel}[CHAN_STDERR] = <$err>; return $self->{status}; } sub restart { my $self = shift; delete $self->{status}; delete $self->{channel}; return $self->run; } sub status { my $self = shift; return undef unless exists $self->{status}; return $self->{status}; } sub channel { my ($self, $chan) = @_; return undef if !exists($self->{channel}) || $chan > $#{$self->{channel}}; open(my $fd, '<', \$self->{channel}[$chan]) or croak "can't dup: $!"; return $fd; } sub argv { my ($self) = @_; return @{$self->{argv}}; } sub command_line { my ($self) = @_; return join(' ', $self->argv); } sub command_name { my ($self) = @_; return $self->{argv}[0]; } sub exit_code { my ($self) = @_; my $code = $self->status; return -1 if (!defined($code) || $code == -1 || ($code & 127)); return $code >> 8; } 1;