Rafael Garcia-Suarez wrote:
>Jos I. Boumans wrote:
>
>
>>Basically, if we can either get:
>>a) pipes to work 'somehow' on win32 (that being ipc::run or a fix on
>>ipc::open3 or teaching IPC::Cmd to use IPC::Run3).
>>
>>
>
>I don't know whether we can hope to get a reliable version of this in
>the near future, so give me hints, windows hackers :) If we don't, then
>I'll remove IPC::Run and began integrating Archive::Tar and its
>dependencies (notably Compress::Zlib).
>
Both Nicholas and I have now asked exactly what the problem with
IPC::Open3 on Win32 is, but have not yet received an answer. Presumably
nobody is quite sure what, if anything, the problem is, so I thought I'd
try and find out.
The attached program contains what I believe is the relevant code,
lifted from CPANPLUS::Tools::Cmd, to try open IPC::Open3 vs IPC::Run.
Running "perl test.pl run" runs "$^X -v" via IPC::Run and produces this
output:
=====
C:\Temp>perl test.pl run
err=[0]
buffer=[
This is perl, v5.8.6 built for MSWin32-x86-perlio
Copyright 1987-2004, Larry Wall
Perl may be copied only under the terms of either the Artistic License
or the
GNU General Public License, which may be found in the Perl 5 source kit.
Complete documentation for Perl, including FAQ lists, should be found on
this system using `man perl' or `perldoc perl'. If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.
]
buferr=[]
bufout=[
This is perl, v5.8.6 built for MSWin32-x86-perlio
Copyright 1987-2004, Larry Wall
Perl may be copied only under the terms of either the Artistic License
or the
GNU General Public License, which may be found in the Perl 5 source kit.
Complete documentation for Perl, including FAQ lists, should be found on
this system using `man perl' or `perldoc perl'. If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.
]
=====
Running "perl test.pl open" runs the same $cmd via IPC::Open3 but
produces just this:
=====
C:\Temp>perl test.pl open
err=[0]
buffer=[]
buferr=[]
bufout=[]
=====
And that's a $cmd that doesn't even involve pipes.
Changing the $cmd to qq[$^X -e "open FH, '>C:/Temp/testout'"] reveals
that the $cmd definitely is being executed; we're just losing all its
output.
But IPC::Open3 passes all its tests OK (and the tests include gathering
output from the child), so perhaps the _open3_run() subroutine is doing
something wrong or non-portable?
Adding some debug, I find that $sel->can_read() is returning an empty
list. If I change
while (my @ready = $sel->can_read) {
foreach my $fh (@ready) { # loop through buffered handles
...
}
}
to
foreach my $fh ($outfh, $errfh) {
...
}
then the output is now as expected.
Presumably IO::Select->can_read() doesn't work on Win32 because it uses
a 4-arg select(), which is only implemented for sockets on Win32. Is
the above change safe, or did we need to call can_read() for some
reason? Would the proposed "selectable pipes" change have any impact on
this?
What do I need to do to test out whether IPC::Open3 is working with
pipes or not? (Open3.t doesn't seem to include any such tests.)
- Steve
------------------------------------------------
This email has been scanned for viruses and content by the Radan Computational
Webshield Appliances.
use strict;
use warnings;
use IPC::Open3;
use IPC::Run;
use IO::Select;
use Symbol;
MAIN: {
my (@buffer,@buferr,@bufout);
my $verbose = 0;
### STDOUT message handler
my $_out_handler = sub {
my $buf = shift;
return unless defined $buf;
print STDOUT $buf if $verbose;
push @buffer, $buf;
push @bufout, $buf;
};
### STDERR message handler
my $_err_handler = sub {
my $buf = shift;
return unless defined $buf;
print STDERR $buf if $verbose;
push @buffer, $buf;
push @buferr, $buf;
};
my $cmd = "$^X -v";
my @cmd = ref ($cmd) ? grep(length, @{$cmd}) : $cmd;
printf "Running [%s]...\n", join(' ', @cmd) if $verbose;
my $err;
if (@ARGV and $ARGV[0] =~ /run/) {
STDOUT->autoflush(1); STDERR->autoflush(1);
@cmd = ref($cmd) ? ( [ @cmd ] )
: map { /[<>|&]/
? $_
: [ split / +/ ]
} split( /\s*([<>|&])\s*/, $cmd );
IPC::Run::run(@cmd, \*STDIN, $_out_handler, $_err_handler) or $err++;
}
elsif (@ARGV and $ARGV[0] =~ /open/) {
my $rv;
($rv,$err) = _open3_run([EMAIL PROTECTED], $_out_handler, $_err_handler, $verbose);
}
else {
die "Usage: $0 {run|open}\n";
}
$err ||= $?;
print "err=[$err]\n";
print "[EMAIL PROTECTED]";
print "[EMAIL PROTECTED]";
print "[EMAIL PROTECTED]";
}
sub _open3_run {
my ($cmdref, $_out_handler, $_err_handler, $verbose) = @_;
my @cmd = @$cmdref;
my ($infh, $outfh, $errfh); # open3 handles
my $pid = eval {
IPC::Open3::open3(
$infh = Symbol::gensym(),
$outfh = Symbol::gensym(),
$errfh = Symbol::gensym(),
@cmd,
)
};
return (undef, $@) if $@;
my $sel = IO::Select->new; # create a select object
$sel->add($outfh, $errfh); # and add the fhs
STDOUT->autoflush(1); STDERR->autoflush(1);
$outfh->autoflush(1) if UNIVERSAL::can($outfh, 'autoflush');
$errfh->autoflush(1) if UNIVERSAL::can($errfh, 'autoflush');
while (my @ready = $sel->can_read) {
foreach my $fh (@ready) { # loop through buffered handles
# read up to 4096 bytes from this fh.
my $len = sysread $fh, my($buf), 4096;
if (not defined $len){
# There was an error reading
warn "Error from child: $!";
return(undef, $!);
}
elsif ($len == 0){
$sel->remove($fh); # finished reading
next;
}
elsif ($fh == $outfh) {
$_out_handler->($buf);
} elsif ($fh == $errfh) {
$_err_handler->($buf);
} else {
warn "IO::Select error";
return(undef, $!);
}
}
}
waitpid $pid, 0; # wait for it to die
return 1;
}