Acme-Sort-Sleep
view release on metacpan or search on metacpan
local/lib/perl5/IO/Async/Process.pm view on Meta::CPAN
=head1 SYNOPSIS
use IO::Async::Process;
use IO::Async::Loop;
my $loop = IO::Async::Loop->new;
my $process = IO::Async::Process->new(
command => [ "tr", "a-z", "n-za-m" ],
stdin => {
from => "hello world\n",
},
stdout => {
on_read => sub {
my ( $stream, $buffref ) = @_;
while( $$buffref =~ s/^(.*)\n// ) {
print "Rot13 of 'hello world' is '$1'\n";
}
return 0;
},
},
on_finish => sub {
$loop->stop;
},
);
$loop->add( $process );
$loop->run;
=head1 DESCRIPTION
This subclass of L<IO::Async::Notifier> starts a child process, and invokes a
callback when it exits. The child process can either execute a given block of
code (via C<fork(2)>), or a command.
=cut
=head1 EVENTS
The following events are invoked, either using subclass methods or CODE
references in parameters:
=head2 on_finish $exitcode
Invoked after the process has exited by normal means (i.e. an C<exit(2)>
syscall from a process, or C<return>ing from the code block), and has closed
all its file descriptors.
=head2 on_exception $exception, $errno, $exitcode
Invoked when the process exits by an exception from C<code>, or by failing to
C<exec(2)> the given command. C<$errno> will be a dualvar, containing both
number and string values. After a successful C<exec()> call, this condition
can no longer happen.
Note that this has a different name and a different argument order from
C<< Loop->open_child >>'s C<on_error>.
If this is not provided and the process exits with an exception, then
C<on_finish> is invoked instead, being passed just the exit code.
Since this is just the results of the underlying C<< $loop->spawn_child >>
C<on_exit> handler in a different order it is possible that the C<$exception>
field will be an empty string. It will however always be defined. This can be
used to distinguish the two cases:
on_exception => sub {
my ( $self, $exception, $errno, $exitcode ) = @_;
if( length $exception ) {
print STDERR "The process died with the exception $exception " .
"(errno was $errno)\n";
}
elsif( ( my $status = W_EXITSTATUS($exitcode) ) == 255 ) {
print STDERR "The process failed to exec() - $errno\n";
}
else {
print STDERR "The process exited with exit status $status\n";
}
}
=cut
=head1 CONSTRUCTOR
=cut
=head2 new
$process = IO::Async::Process->new( %args )
Constructs a new C<IO::Async::Process> object and returns it.
Once constructed, the C<Process> will need to be added to the C<Loop> before
the child process is started.
=cut
sub _init
{
my $self = shift;
$self->SUPER::_init( @_ );
$self->{to_close} = {};
$self->{finish_futures} = [];
}
=head1 PARAMETERS
The following named parameters may be passed to C<new> or C<configure>:
=head2 on_finish => CODE
=head2 on_exception => CODE
CODE reference for the event handlers.
local/lib/perl5/IO/Async/Process.pm view on Meta::CPAN
=cut
sub fd
{
my $self = shift;
my ( $fd ) = @_;
return $self->{fd_handle}{$fd} ||= do {
my $opts = $self->{fd_opts}{$fd} or
croak "$self does not have an fd Stream for $fd";
my $handle_class;
if( defined $opts->{socktype} && IO::Async::OS->getsocktypebyname( $opts->{socktype} ) != SOCK_STREAM ) {
require IO::Async::Socket;
$handle_class = "IO::Async::Socket";
}
else {
require IO::Async::Stream;
$handle_class = "IO::Async::Stream";
}
my $handle = $handle_class->new(
notifier_name => $fd eq "0" ? "stdin" :
$fd eq "1" ? "stdout" :
$fd eq "2" ? "stderr" :
$fd eq "io" ? "stdio" : "fd$fd",
%{ $opts->{handle} },
);
if( defined $opts->{from} ) {
$handle->write( $opts->{from},
on_flush => sub {
my ( $handle ) = @_;
$handle->close_write;
},
);
}
$handle
};
}
=head2 stdin
=head2 stdout
=head2 stderr
=head2 stdio
$stream = $process->stdin
$stream = $process->stdout
$stream = $process->stderr
$stream = $process->stdio
Shortcuts for calling C<fd> with 0, 1, 2 or C<io> respectively, to obtain the
L<IO::Async::Stream> representing the standard input, output, error, or
combined input/output streams of the child process.
=cut
sub stdin { shift->fd( 0 ) }
sub stdout { shift->fd( 1 ) }
sub stderr { shift->fd( 2 ) }
sub stdio { shift->fd( 'io' ) }
=head1 EXAMPLES
=head2 Capturing the STDOUT stream of a process
By configuring the C<stdout> filehandle of the process using the C<into> key,
data written by the process can be captured.
my $stdout;
my $process = IO::Async::Process->new(
command => [ "writing-program", "arguments" ],
stdout => { into => \$stdout },
on_finish => sub {
print "The process has finished, and wrote:\n";
print $stdout;
}
);
$loop->add( $process );
Note that until C<on_finish> is invoked, no guarantees are made about how much
of the data actually written by the process is yet in the C<$stdout> scalar.
See also the C<run_child> method of L<IO::Async::Loop>.
To handle data more interactively as it arrives, the C<on_read> key can
instead be used, to provide a callback function to invoke whenever more data
is available from the process.
my $process = IO::Async::Process->new(
command => [ "writing-program", "arguments" ],
stdout => {
on_read => sub {
my ( $stream, $buffref ) = @_;
while( $$buffref =~ s/^(.*)\n// ) {
print "The process wrote a line: $1\n";
}
return 0;
},
},
on_finish => sub {
print "The process has finished\n";
}
);
$loop->add( $process );
If the code to handle data read from the process isn't available yet when
the object is constructed, it can be supplied later by using the C<configure>
method on the C<stdout> filestream at some point before it gets added to the
Loop. In this case, C<stdin> should be configured using C<pipe_read> in the
( run in 0.779 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )