1 package TAP::Parser::Iterator::Process;
5 use TAP::Parser::Iterator ();
7 use vars qw($VERSION @ISA);
9 @ISA = 'TAP::Parser::Iterator';
14 my $IS_WIN32 = ( $^O =~ /^(MS)?Win32$/ );
18 TAP::Parser::Iterator::Process - Internal TAP::Parser Iterator
30 use TAP::Parser::Iterator;
31 my $it = TAP::Parser::Iterator::Process->new(@args);
35 Originally ripped off from L<Test::Harness>.
39 B<FOR INTERNAL USE ONLY!>
41 This is a simple iterator wrapper for processes.
49 =head2 Instance Methods
53 Iterate through it, of course.
57 Iterate raw input without applying any fixes for quirky input syntax.
61 Get the wait status for this iterator's process.
65 Get the exit status for this iterator's process.
69 eval { require POSIX; &POSIX::WEXITSTATUS(0) };
71 *_wait2exit = sub { $_[1] >> 8 };
74 *_wait2exit = sub { POSIX::WEXITSTATUS( $_[1] ) }
79 return unless $Config{d_fork} || $IS_WIN32;
80 for my $module (qw( IPC::Open3 IO::Select )) {
91 return $got_unicode if defined $got_unicode;
92 eval 'use Encode qw(decode_utf8);';
93 $got_unicode = $@ ? 0 : 1;
102 my @command = @{ delete $args->{command} || [] }
103 or die "Must supply a command to execute";
105 # Private. Used to frig with chunk size during testing.
106 my $chunk_size = delete $args->{_chunk_size} || 65536;
108 my $merge = delete $args->{merge};
109 my ( $pid, $err, $sel );
111 if ( my $setup = delete $args->{setup} ) {
115 my $out = IO::Handle->new;
117 if ( $class->_use_open3 ) {
120 my $xclose = \&IPC::Open3::xclose;
121 local $^W; # no warnings
122 local *IPC::Open3::xclose = sub {
125 return if ( fileno($fh) == fileno(STDIN) );
132 $err = $merge ? '' : '>&STDERR';
135 '<&STDIN', $out, $merge ? '' : $err,
139 die "Could not execute (@command): $@" if $@;
142 # Kludge to avoid warning under 5.5
143 eval 'binmode($out, ":crlf")';
147 $err = $merge ? '' : IO::Handle->new;
148 eval { $pid = open3( '<&STDIN', $out, $err, @command ); };
149 die "Could not execute (@command): $@" if $@;
150 $sel = $merge ? undef : IO::Select->new( $out, $err );
156 = join( ' ', map { $_ =~ /\s/ ? qq{"$_"} : $_ } @command );
157 open( $out, "$command|" )
158 or die "Could not execute ($command): $!";
167 chunk_size => $chunk_size,
170 if ( my $teardown = delete $args->{teardown} ) {
171 $self->{teardown} = sub {
172 $teardown->(@command);
179 =head3 C<handle_unicode>
181 Upgrade the input stream to handle UTF8.
188 if ( $self->{sel} ) {
189 if ( _get_unicode() ) {
191 # Make sure our iterator has been constructed and...
192 my $next = $self->{_next} ||= $self->_next;
194 # ...wrap it to do UTF8 casting
195 $self->{_next} = sub {
196 my $line = $next->();
197 return decode_utf8($line) if defined $line;
204 eval 'binmode($self->{out}, ":utf8")';
210 ##############################################################################
212 sub wait { shift->{wait} }
213 sub exit { shift->{exit} }
218 if ( my $out = $self->{out} ) {
219 if ( my $sel = $self->{sel} ) {
220 my $err = $self->{err};
222 my $partial = ''; # Partial line
223 my $chunk_size = $self->{chunk_size};
225 return shift @buf if @buf;
228 while ( my @ready = $sel->can_read ) {
229 for my $fh (@ready) {
230 my $got = sysread $fh, my ($chunk), $chunk_size;
235 elsif ( $fh == $err ) {
236 print STDERR $chunk; # echo STDERR
239 $chunk = $partial . $chunk;
242 # Make sure we have a complete line
243 unless ( substr( $chunk, -1, 1 ) eq "\n" ) {
244 my $nl = rindex $chunk, "\n";
250 $partial = substr( $chunk, $nl + 1 );
251 $chunk = substr( $chunk, 0, $nl );
255 push @buf, split /\n/, $chunk;
256 return shift @buf if @buf;
261 # Return partial last line
262 if ( length $partial ) {
274 if ( defined( my $line = <$out> ) ) {
293 return ( $self->{_next} ||= $self->_next )->();
301 # If we have a subprocess we need to wait for it to terminate
302 if ( defined $self->{pid} ) {
303 if ( $self->{pid} == waitpid( $self->{pid}, 0 ) ) {
308 ( delete $self->{out} )->close if $self->{out};
310 # If we have an IO::Select we also have an error handle to close.
311 if ( $self->{sel} ) {
312 ( delete $self->{err} )->close;
319 # Sometimes we get -1 on Windows. Presumably that means status not
321 $status = 0 if $IS_WIN32 && $status == -1;
323 $self->{wait} = $status;
324 $self->{exit} = $self->_wait2exit($status);
326 if ( my $teardown = $self->{teardown} ) {
333 =head3 C<get_select_handles>
335 Return a list of filehandles that may be used upstream in a select()
336 call to signal that this Iterator is ready. Iterators that are not
337 handle based should return an empty list.
341 sub get_select_handles {
343 return grep $_, ( $self->{out}, $self->{err} );