view release on metacpan or search on metacpan
0.74 2013-09-12 06:10:50 -0400
- skip raw support testing on all platforms
0.73 2013-09-10 14:08:24 -0400
- perl 5.8 support fixes
0.72 2013-09-09 08:20:35 -0400
- marking raw support as experiemental
https://github.com/plicease/AnyEvent-Open3-Simple/issues/6
- undocumented (and experimental): on_stderr and on_stdout can be list ref
0.71 2013-09-03 15:19:59 -0400
- fixed raw support
0.70 2013-09-03 12:39:38 -0400
- promote to production
0.69_02 2013-09-01 14:25:50 -0400
- add prereq EV on MSWin32
my $proc = shift; # isa AnyEvent::Open3::Simple::Process
my $program = shift; # string
my @args = @_; # list of arguments
say 'child PID: ', $proc->pid;
},
on_stdout => sub {
my $proc = shift; # isa AnyEvent::Open3::Simple::Process
my $line = shift; # string
say 'out: ', $string;
},
on_stderr => sub {
my $proc = shift; # isa AnyEvent::Open3::Simple::Process
my $line = shift; # string
say 'err: ', $line;
},
on_exit => sub {
my $proc = shift; # isa AnyEvent::Open3::Simple::Process
my $exit_value = shift; # integer
my $signal = shift; # integer
say 'exit value: ', $exit_value;
say 'signal: ', $signal;
$done->send;
},
);
$ipc->run('echo', 'hello there');
$done->recv;
DESCRIPTION
This module provides an interface to open3 while running under AnyEvent
that delivers data from stdout and stderr as lines are written by the
subprocess. The interface is reminiscent of IPC::Open3::Simple,
although this module does provides a somewhat different API, so it
cannot be used a drop in replacement for that module.
There are already a number of interfaces for interacting with
subprocesses in the context of AnyEvent, but this one is the most
convenient for my usage. Note the modules listed in the SEE ALSO
section below for other interfaces that may be more or less
appropriate.
will raise an on_error event, on MSWin32 it will not trigger a
on_error and instead cause a normal exit with a exit value of 1.
In versions 0.77 and better, this event also gets the program name
and arguments passed into the run method.
* on_stdout ($proc, $line)
Called on every line printed to stdout by the child process.
* on_stderr ($proc, $line)
Called on every line printed to stderr by the child process.
* on_exit ($proc, $exit_value, $signal)
Called when the processes completes, either because it called exit,
or if it was killed by a signal.
* on_success ($proc)
Called when the process returns zero exit value and is not terminated
by a signal.
---
pod_spelling_system:
stopwords:
- AnyEvent
- stderr
- API
- MSWin32
- MSWin
- Scaffidi
- prereq
- OpenBSD
- Wiersdorf
- open3
- suboptimal
- mojo
lib/AnyEvent/Open3/Simple.pm view on Meta::CPAN
sub new
{
my $default_handler = sub { };
my $class = shift;
my $args = (reftype($_[0]) || '') eq 'HASH' ? shift : { @_ };
my %self;
croak "stdin passed into AnyEvent::Open3::Simple->new no longer supported" if $args->{stdin};
croak "raw passed into AnyEvent::Open::Simple->new no longer supported" if $args->{raw};
$self{$_} = $args->{$_} || $default_handler for qw( on_stdout on_stderr on_start on_exit on_signal on_fail on_error on_success );
$self{impl} = $args->{implementation}
|| $ENV{ANYEVENT_OPEN3_SIMPLE}
|| _detect();
croak "unknown implementation $self{impl}" unless $self{impl} =~ /^(idle|child|mojo)$/;
$self{impl} = _detect()
if $self{impl} eq 'mojo' && do { require Mojo::Reactor; Mojo::Reactor->detect eq 'Mojo::Reactor::EV' };
bless \%self, $class;
}
lib/AnyEvent/Open3/Simple.pm view on Meta::CPAN
croak "run method requires at least one argument"
unless @_ >= 2;
my $proc_user = (ref $_[-1] eq 'CODE' ? pop : sub {});
my $stdin;
$stdin = pop if ref $_[-1];
my($self, $program, @arguments) = @_;
my($child_stdin, $child_stdout, $child_stderr);
$child_stderr = gensym;
local *TEMP;
if(defined $stdin)
{
my $file = File::Temp->new;
$file->autoflush(1);
$file->print(
ref($stdin) eq 'ARRAY'
? join("\n", @{ $stdin })
: $$stdin
lib/AnyEvent/Open3/Simple.pm view on Meta::CPAN
AnyEvent::detect();
require AnyEvent::Open3::Simple::Idle if $self->{impl} eq 'idle';
}
elsif($self->{impl} eq 'mojo')
{
require Mojo::Reactor;
require Mojo::IOLoop;
require AnyEvent::Open3::Simple::Mojo;
}
my $pid = eval { open3 $child_stdin, $child_stdout, $child_stderr, $program, @arguments };
if(my $error = $@)
{
$self->{on_error}->($error, $program, @arguments);
return;
}
my $proc = AnyEvent::Open3::Simple::Process->new($pid, $child_stdin);
$proc_user->($proc);
$self->{on_start}->($proc, $program, @arguments);
my $watcher_stdout;
my $watcher_stderr;
my $stdout_callback = sub {
my $input = <$child_stdout>;
return unless defined $input;
$input =~ s/(\015?\012|\015)$//;
my $ref = $self->{on_stdout};
ref($ref) eq 'ARRAY' ? push @$ref, $input : $ref->($proc, $input);
};
my $stderr_callback = sub {
my $input = <$child_stderr>;
return unless defined $input;
$input =~ s/(\015?\012|\015)$//;
my $ref = $self->{on_stderr};
ref($ref) eq 'ARRAY' ? push @$ref, $input : $ref->($proc, $input);
};
if(!_is_native_win32() && $self->{impl} =~ /^(idle|child)$/)
{
$watcher_stdout = AnyEvent->io(
fh => $child_stdout,
poll => 'r',
cb => $stdout_callback,
) unless _is_native_win32();
$watcher_stderr = AnyEvent->io(
fh => $child_stderr,
poll => 'r',
cb => $stderr_callback,
) unless _is_native_win32();
}
my $watcher_child;
my $end_cb = sub {
#my($pid, $status) = @_;
my $status = $_[1];
my($exit_value, $signal) = ($status >> 8, $status & 127);
$proc->close;
# make sure we consume any stdout and stderr which hasn't
# been consumed yet. This seems to make on_out.t work on
# cygwin
if($self->{raw})
{
local $/;
$self->{on_stdout}->($proc, scalar <$child_stdout>);
$self->{on_stderr}->($proc, scalar <$child_stderr>);
}
else
{
while(!eof $child_stdout)
{
my $input = <$child_stdout>;
last unless defined $input;
$input =~ s/(\015?\012|\015)$//;
my $ref = $self->{on_stdout};
ref($ref) eq 'ARRAY' ? push @$ref, $input : $ref->($proc, $input);
}
while(!eof $child_stderr)
{
my $input = <$child_stderr>;
last unless defined $input;
$input =~ s/(\015?\012|\015)$//;
my $ref = $self->{on_stderr};
ref($ref) eq 'ARRAY' ? push @$ref, $input : $ref->($proc, $input);
}
}
$self->{on_exit}->($proc, $exit_value, $signal);
$self->{on_signal}->($proc, $signal) if $signal > 0;
$self->{on_fail}->($proc, $exit_value) if $exit_value > 0;
$self->{on_success}->($proc) if $signal == 0 && $exit_value == 0;
undef $watcher_stdout;
undef $watcher_stderr;
undef $watcher_child;
undef $proc;
};
if($self->{impl} eq 'mojo')
{
my($selout, $selerr);
if(_is_native_win32())
{
require IO::Select;
$selout = IO::Select->new($child_stdout);
$selerr = IO::Select->new($child_stderr);
}
my $reactor = Mojo::IOLoop->singleton->reactor;
my $id;
$id = Mojo::IOLoop->recurring(0.25 => sub {
AnyEvent::Open3::Simple::Mojo::_watcher($pid, sub {
$end_cb->(@_);
Mojo::IOLoop->remove($id);
if(_is_native_win32())
{
$stdout_callback->() if $selout->can_read(0);
$stderr_callback->() if $selerr->can_read(0);
}
else
{
$reactor->remove($child_stdout);
$reactor->remove($child_stderr);
}
});
});
}
elsif($self->{impl} eq 'idle')
{
my($selout, $selerr);
if(_is_native_win32())
{
require IO::Select;
$selout = IO::Select->new($child_stdout);
$selerr = IO::Select->new($child_stderr);
}
$watcher_child = AnyEvent->idle(cb => sub {
if(_is_native_win32())
{
$stdout_callback->() if $selout->can_read(0);
$stderr_callback->() if $selerr->can_read(0);
}
AnyEvent::Open3::Simple::Idle::_watcher($pid, $end_cb);
});
}
else
{
$watcher_child = AnyEvent->child(
pid => $pid,
cb => $end_cb,
);
lib/AnyEvent/Open3/Simple.pm view on Meta::CPAN
my $proc = shift; # isa AnyEvent::Open3::Simple::Process
my $program = shift; # string
my @args = @_; # list of arguments
say 'child PID: ', $proc->pid;
},
on_stdout => sub {
my $proc = shift; # isa AnyEvent::Open3::Simple::Process
my $line = shift; # string
say 'out: ', $string;
},
on_stderr => sub {
my $proc = shift; # isa AnyEvent::Open3::Simple::Process
my $line = shift; # string
say 'err: ', $line;
},
on_exit => sub {
my $proc = shift; # isa AnyEvent::Open3::Simple::Process
my $exit_value = shift; # integer
my $signal = shift; # integer
say 'exit value: ', $exit_value;
say 'signal: ', $signal;
lib/AnyEvent/Open3/Simple.pm view on Meta::CPAN
$done->send;
},
);
$ipc->run('echo', 'hello there');
$done->recv;
=head1 DESCRIPTION
This module provides an interface to open3 while running under AnyEvent
that delivers data from stdout and stderr as lines are written by the
subprocess. The interface is reminiscent of L<IPC::Open3::Simple>,
although this module does provides a somewhat different API, so it
cannot be used a drop in replacement for that module.
There are already a number of interfaces for interacting with subprocesses
in the context of L<AnyEvent>, but this one is the most convenient for my
usage. Note the modules listed in the SEE ALSO section below for other
interfaces that may be more or less appropriate.
=head1 CONSTRUCTOR
lib/AnyEvent/Open3/Simple.pm view on Meta::CPAN
with a exit value of 1.
In versions 0.77 and better, this event also gets the program name
and arguments passed into the L<run|AnyEvent::Open3::Simple#run>
method.
=item * C<on_stdout> ($proc, $line)
Called on every line printed to stdout by the child process.
=item * C<on_stderr> ($proc, $line)
Called on every line printed to stderr by the child process.
=item * C<on_exit> ($proc, $exit_value, $signal)
Called when the processes completes, either because it called exit,
or if it was killed by a signal.
=item * C<on_success> ($proc)
Called when the process returns zero exit value and is not terminated by a signal.
t/anyevent_open3_simple__mojo.t view on Meta::CPAN
on_exit => sub {
(undef, $exit_value, undef) = @_;
Mojo::IOLoop->stop;
pass 'called on_exit';
},
on_stdout => sub {
my $line = pop;
push @out, $line;
note "[out] $line";
},
on_stderr => sub {
my $line = pop;
push @err, $line;
note "[err] $line";
},
);
my $program = do {
my $fn = File::Spec->catfile( tempdir( CLEANUP => 1 ), 'mojo_test.pl' );
open my $fh, '>', $fn;
print $fh 'print "dragon\n"; print STDERR "lime\n"; exit 22';
t/anyevent_open3_simple__mojo.t view on Meta::CPAN
$fn;
};
$ipc->run($^X, $program);
Mojo::IOLoop->start;
ok $called_on_start, 'called on start';
is $exit_value, 22, 'exit = 22';
is_deeply \@out, ['dragon'], 'stdout';
is_deeply \@err, ['lime'], 'stderr';
is $ipc->{impl}, 'mojo', 'used mojo implementation';
ok !$INC{'AnyEvent.pm'}, 'did not load AnyEvent';
diag "AnyEvent.pm = $INC{'AnyEvent.pm'}" if $INC{'AnyEvent.pm'};
t/anyevent_open3_simple__on_out.t view on Meta::CPAN
my $done = AnyEvent->condvar;
my @out;
my @err;
my $exit_value;
my $signal;
my $proc;
my $ipc = AnyEvent::Open3::Simple->new(
on_stdout => sub { push @out, pop },
on_stderr => sub { push @err, pop },
on_exit => sub {
($proc, $exit_value, $signal) = @_;
$done->send;
},
);
my $timeout = AnyEvent->timer (
after => 5,
cb => sub { diag 'timeout!'; exit 2; },
);
t/anyevent_open3_simple__on_out_array.t view on Meta::CPAN
my $done = AnyEvent->condvar;
my @out;
my @err;
my $exit_value;
my $signal;
my $proc;
my $ipc = AnyEvent::Open3::Simple->new(
on_stdout => \@out,
on_stderr => \@err,
on_exit => sub {
($proc, $exit_value, $signal) = @_;
$done->send;
},
);
my $timeout = AnyEvent->timer (
after => 5,
cb => sub { diag 'timeout!'; exit 2; },
);
xt/author/pod_spelling_system.t view on Meta::CPAN
if -r $config_filename;
plan skip_all => 'disabled' if $config->{pod_spelling_system}->{skip};
chdir(File::Spec->catdir($FindBin::Bin, File::Spec->updir, File::Spec->updir));
add_stopwords($config->{pod_spelling_system}->{stopwords}->@*);
add_stopwords(qw(
Plicease
stdout
stderr
stdin
subref
loopback
username
os
Ollis
Mojolicious
plicease
CPAN
reinstall