AnyEvent-Subprocess
view release on metacpan or search on metacpan
lib/AnyEvent/Subprocess.pm view on Meta::CPAN
This registers short names for each delegate and will cause
C<AnyEvent::Subprocess::Job> to build the actual instances
automatically. This means you can say C<'StandardHandles'> to get a
delegate for each of STDIN, STDOUT, and STDERR. If you want to know
how all the sugary names work, just open C<DefaultDelegates.pm> and
take a look. (The documentation for that module also covers that, as
well as how to define your own delegate builders.)
If you are too lazy to look -- there are delegates for giving the
child arbitrary sockets or pipes opened to arbitrary file descriptors
(so you can deal with more than stdin/stdout/stderr and communicate
bidirectionally between the parent and child), there is a delegate for
giving the child a pseudo-tty (which can run complicatged programs,
like emacs!), there is a delegate for capturing any input
automatically, and passing it back to the parent via the C<Done>
object, and there is a delegate for calling functions in the parent
when certain events are received.
Once you have decided what delegates your job needs, you need to
create a job object:
lib/AnyEvent/Subprocess.pm view on Meta::CPAN
on.
What makes this more interesting is the ability to add delegates to
any of these classes. These delegates are called into at various
points and allow you to add more features. By default, you just get a
callback when the process exits. You can also kill the running
process. That's it. From there, you can add delegates to add more
features. You can add a pipe to share between the parent and the
child. Instead of sharing a pipe, you can have an fd opened to an
arbitrary file descriptor number in the child. You have an infinite
number of these, so you can capture the child's stdout and stderr,
write to its stdin, and also share a socket for out-of-band
communication. You can also open a pipe to the child's fd #5 and
write to it. (This is nice if you are invoking something like C<gpg>
that wants the password written on an arbitrary fd other than 1.)
(This is all done with the included C<Handle> delegate. See
L<AnyEvent::Subprocess::Job::Delegate::Handle>.)
You can then build upon this; instead of writing your own code to
reading the handles when they become readable and accumulate input,
lib/AnyEvent/Subprocess/DefaultDelegates.pm view on Meta::CPAN
name => "${prefix}stdin",
direction => 'w',
replace => \*STDIN,
),
$class->new(
name => "${prefix}stdout",
direction => 'r',
replace => \*STDOUT,
),
$class->new(
name => "${prefix}stderr",
direction => 'r',
replace => \*STDERR,
),
);
});
register_delegate( 'CommHandle' => sub {
my $args = shift || {};
my $name = $args->{name} || 'comm';
lib/AnyEvent/Subprocess/DefaultDelegates.pm view on Meta::CPAN
name => $name,
direction => 'rw',
pass_to_child => 1,
);
});
register_delegate( 'Pty' => sub {
my $args = shift || {};
$args->{name} ||= 'pty';
if(delete $args->{stderr}){
$args->{redirect_handles} = [
\*STDIN,
\*STDOUT,
\*STDERR,
];
}
return AnyEvent::Subprocess::Job::Delegate::Pty->new(%$args);
});
lib/AnyEvent/Subprocess/DefaultDelegates.pm view on Meta::CPAN
=head2 Handle
Provides connections to an arbitrary filehandle / fd / pipe / socket /
etc.
See L<AnyEvent::Subprocess::Job::Delegate::Handle>
=head2 StandardHandles
Provides connections to the child's STDIN/STDOUT/STDERR handles.
Delegates are named stdin/stdout/stderr. Optional arg prefix adds a
prefix string to the delegates' names.
=head2 CommHandle
Provides a (bidirectional) socket to be shared between the child and
parent. Optional arg name provides delegate name (so you can have
more than one, if desired).
Optional arg name controls name; defaults to 'comm.
=head2 Pty
Provides the child with stdin and stdout attached to a pseudo-tty, and
provides the parent with a delegate to control this. Optional arg
stderr controls whether or not the child's stderr will also go to the
pty; defaults to no.
Optional arg name controls name; defaults to 'pty'.
=head2 CompletionCondvar
Supplies a delegate that is a L<AnyEvent::Condvar> that is sent the
child exit information ("Done class") when the child process exits.
=head2 Callback
lib/AnyEvent/Subprocess/Job/Delegate/Pty.pm view on Meta::CPAN
=head1 DESCRIPTION
You can have more than one of these, but the last one will become the
controlling tty.
=head1 INITARGS
=head2 redirect_handles
A list of filehandles that will be connected to this Pty in the child.
Defaults to stdout and stderr.
=head1 METHODS
=head2 pty
Returns the L<IO::Pty|IO::Pty> object. You can use this object to set
the child's window size, etc.
=head2 handle
my $done = $condvar->recv;
isa_ok $done, 'AnyEvent::Subprocess::Done';
is $done->exit_value, 0, 'got exit status 0';
is $done->exit_signal, 0, 'no signal';
ok $done->exited, 'exited normally';
ok !$done->dumped_core, 'no dump';
ok $done->is_success, 'success';
like $run->delegate('stderr')->handle->{rbuf},
qr/^starting child foo.*^child is done/ms,
'captured stderr';
is $run->delegate('stdout')->handle->{rbuf},
"got line: {$line}",
'copied STDIN to STDOUT ok';
t/capture-basic.t view on Meta::CPAN
my $s = AnyEvent::Subprocess->new(
delegates => [
'StandardHandles',
'CompletionCondvar',
{ 'Capture' => {
name => 'stdout_capture',
handle => 'stdout',
}},
{ 'Capture' => {
name => 'stderr_capture',
handle => 'stderr',
}},
],
code => sub {
print "Hello, world. This is stdout.";
print {*STDERR} "OH HAI, THIS IS STDERR.";
},
);
my $run = $s->run;
my $done = $run->delegate('completion_condvar')->recv;
is $done->delegate('stdout_capture')->output,
'Hello, world. This is stdout.', 'got out';
is $done->delegate('stderr_capture')->output,
'OH HAI, THIS IS STDERR.', 'got err';
ok $done->is_success, 'exit success';
t/external-process.t view on Meta::CPAN
sub tests {
my $proc = shift;
ok $proc;
my $run = $proc->run;
my $condvar = $run->delegate('completion_condvar');
my $got_error = 0;
$run->delegate('stderr')->handle->on_read( sub { warn @_; warn $_[0]->rbuf; $got_error++ } );
$run->delegate('stdout')->handle->push_read( line => sub {
my ($h, $data) = @_;
ok length $data > 9, 'got some value from `date`';
ok looks_like_number $data, 'data looks like number';
});
my $done = $condvar->recv;
is $done->exit_value, 0, 'exited with value 0';
is $got_error, 0, 'no errors/warning/noise on stderr';
}
# test code => ArrayRef
my $proc = AnyEvent::Subprocess->new(
delegates => [ 'StandardHandles', 'CompletionCondvar' ],
code => ['date', '+%s'],
);
tests($proc);
t/open-to-fd.t view on Meta::CPAN
name => 'extra_in',
direction => 'w',
replace => 3,
}},
{ Handle => {
name => 'extra_out',
direction => 'r',
replace => 4,
}},
{ Capture => { handle => 'stdout' }},
{ Capture => { handle => 'stderr' }},
{ Capture => {
name => 'extra_capture',
handle => 'extra_out',
}},
],
code => sub {
open my $extra_in, '<&=3' or die "Failed to open fd 3: $!";
open my $extra_out, '>&=4' or die "Failed to open fd 4: $!";
my $stdin = <STDIN>;
t/open-to-fd.t view on Meta::CPAN
my $condvar = $run->delegate('completion_condvar');
$run->delegate('stdin')->handle->push_write("stdin\n");
$run->delegate('extra_in')->handle->push_write("extra_in\n");
my $done = $condvar->recv;
ok $done->is_success, 'exited ok';
is $done->delegate('stdout_capture')->output, "Got: stdin\n", 'got stdin';
is $done->delegate('extra_capture')->output, "Got: extra_in\n", 'got extra_in';
is $done->delegate('stderr_capture')->output, "No errors\n", 'no errors on stderr';
( run in 1.230 second using v1.01-cache-2.11-cpan-49f99fa48dc )