Alien-ROOT
view release on metacpan or search on metacpan
inc/inc_IPC-Cmd/IPC/Cmd.pm view on Meta::CPAN
else {
$cmd = [ grep { defined && length } @$cmd ] if ref $cmd;
}
my $pp_cmd = (ref $cmd ? "@$cmd" : $cmd);
print loc("Running [%1]...\n", $pp_cmd ) if $verbose;
### did the user pass us a buffer to fill or not? if so, set this
### flag so we know what is expected of us
### XXX this is now being ignored. in the future, we could add diagnostic
### messages based on this logic
#my $user_provided_buffer = $buffer == \$def_buf ? 0 : 1;
### buffers that are to be captured
my( @buffer, @buff_err, @buff_out );
### capture STDOUT
my $_out_handler = sub {
my $buf = shift;
return unless defined $buf;
print STDOUT $buf if $verbose;
push @buffer, $buf;
push @buff_out, $buf;
};
### capture STDERR
my $_err_handler = sub {
my $buf = shift;
return unless defined $buf;
print STDERR $buf if $verbose;
push @buffer, $buf;
push @buff_err, $buf;
};
### flag to indicate we have a buffer captured
my $have_buffer = $self->can_capture_buffer ? 1 : 0;
### flag indicating if the subcall went ok
my $ok;
### dont look at previous errors:
local $?;
local $@;
local $!;
### we might be having a timeout set
eval {
local $SIG{ALRM} = sub { die bless sub {
ALARM_CLASS .
qq[: Command '$pp_cmd' aborted by alarm after $timeout seconds]
}, ALARM_CLASS } if $timeout;
alarm $timeout || 0;
### IPC::Run is first choice if $USE_IPC_RUN is set.
if( !IS_WIN32 and $USE_IPC_RUN and $self->can_use_ipc_run( 1 ) ) {
### ipc::run handlers needs the command as a string or an array ref
$self->_debug( "# Using IPC::Run. Have buffer: $have_buffer" )
if $DEBUG;
$ok = $self->_ipc_run( $cmd, $_out_handler, $_err_handler );
### since IPC::Open3 works on all platforms, and just fails on
### win32 for capturing buffers, do that ideally
} elsif ( $USE_IPC_OPEN3 and $self->can_use_ipc_open3( 1 ) ) {
$self->_debug("# Using IPC::Open3. Have buffer: $have_buffer")
if $DEBUG;
### in case there are pipes in there;
### IPC::Open3 will call exec and exec will do the right thing
my $method = IS_WIN32 ? '_open3_run_win32' : '_open3_run';
$ok = $self->$method(
$cmd, $_out_handler, $_err_handler, $verbose
);
### if we are allowed to run verbose, just dispatch the system command
} else {
$self->_debug( "# Using system(). Have buffer: $have_buffer" )
if $DEBUG;
$ok = $self->_system_run( $cmd, $verbose );
}
alarm 0;
};
### restore STDIN after duping, or STDIN will be closed for
### this current perl process!
$self->__reopen_fds( @{ $self->_fds} ) if $self->_fds;
my $err;
unless( $ok ) {
### alarm happened
if ( $@ and ref $@ and $@->isa( ALARM_CLASS ) ) {
$err = $@->(); # the error code is an expired alarm
### another error happened, set by the dispatchub
} else {
$err = $self->error;
}
}
### fill the buffer;
$$buffer = join '', @buffer if @buffer;
### return a list of flags and buffers (if available) in list
### context, or just a simple 'ok' in scalar
return wantarray
? $have_buffer
? ($ok, $err, \@buffer, \@buff_out, \@buff_err)
: ($ok, $err )
: $ok
}
sub _open3_run_win32 {
my $self = shift;
my $cmd = shift;
my $outhand = shift;
my $errhand = shift;
my $pipe = sub {
socketpair($_[0], $_[1], AF_UNIX, SOCK_STREAM, PF_UNSPEC)
or return undef;
shutdown($_[0], 1); # No more writing for reader
shutdown($_[1], 0); # No more reading for writer
return 1;
};
my $open3 = sub {
local (*TO_CHLD_R, *TO_CHLD_W);
local (*FR_CHLD_R, *FR_CHLD_W);
local (*FR_CHLD_ERR_R, *FR_CHLD_ERR_W);
$pipe->(*TO_CHLD_R, *TO_CHLD_W ) or die $^E;
$pipe->(*FR_CHLD_R, *FR_CHLD_W ) or die $^E;
$pipe->(*FR_CHLD_ERR_R, *FR_CHLD_ERR_W) or die $^E;
inc/inc_IPC-Cmd/IPC/Cmd.pm view on Meta::CPAN
### unless it's an alarm
if( $@ and not UNIVERSAL::isa( $@, ALARM_CLASS ) ) {
$self->error( $@ );
### if it *is* an alarm, propagate
} elsif( $@ ) {
die $@;
### some error in the sub command
} else {
$self->error( $self->_pp_child_error( $cmd, $? ) );
}
return;
}
}
}
sub _system_run {
my $self = shift;
my $cmd = shift;
my $verbose = shift || 0;
### pipes have to come in a quoted string, and that clashes with
### whitespace. This sub fixes up such commands so they run properly
$cmd = $self->__fix_cmd_whitespace_and_special_chars( $cmd );
my @fds_to_dup = $verbose ? () : qw[STDOUT STDERR];
$self->_fds( \@fds_to_dup );
$self->__dup_fds( @fds_to_dup );
### system returns 'true' on failure -- the exit code of the cmd
$self->ok( 1 );
system( ref $cmd ? @$cmd : $cmd ) == 0 or do {
$self->error( $self->_pp_child_error( $cmd, $? ) );
$self->ok( 0 );
};
### done in the parent call now
#$self->__reopen_fds( @fds_to_dup );
return unless $self->ok;
return $self->ok;
}
{ my %sc_lookup = map { $_ => $_ } SPECIAL_CHARS;
sub __fix_cmd_whitespace_and_special_chars {
my $self = shift;
my $cmd = shift;
### command has a special char in it
if( ref $cmd and grep { $sc_lookup{$_} } @$cmd ) {
### since we have special chars, we have to quote white space
### this *may* conflict with the parsing :(
my $fixed;
my @cmd = map { / / ? do { $fixed++; QUOTE.$_.QUOTE } : $_ } @$cmd;
$self->_debug( "# Quoted $fixed arguments containing whitespace" )
if $DEBUG && $fixed;
### stringify it, so the special char isn't escaped as argument
### to the program
$cmd = join ' ', @cmd;
}
return $cmd;
}
}
### Command-line arguments (but not the command itself) must be quoted
### to ensure case preservation. Borrowed from Module::Build with adaptations.
### Patch for this supplied by Craig Berry, see RT #46288: [PATCH] Add argument
### quoting for run() on VMS
sub _quote_args_vms {
### Returns a command string with proper quoting so that the subprocess
### sees this same list of args, or if we get a single arg that is an
### array reference, quote the elements of it (except for the first)
### and return the reference.
my @args = @_;
my $got_arrayref = (scalar(@args) == 1
&& UNIVERSAL::isa($args[0], 'ARRAY'))
? 1
: 0;
@args = split(/\s+/, $args[0]) unless $got_arrayref || scalar(@args) > 1;
my $cmd = $got_arrayref ? shift @{$args[0]} : shift @args;
### Do not quote qualifiers that begin with '/' or previously quoted args.
map { if (/^[^\/\"]/) {
$_ =~ s/\"/""/g; # escape C<"> by doubling
$_ = q(").$_.q(");
}
}
($got_arrayref ? @{$args[0]}
: @args
);
$got_arrayref ? unshift(@{$args[0]}, $cmd) : unshift(@args, $cmd);
return $got_arrayref ? $args[0]
: join(' ', @args);
}
### XXX this is cribbed STRAIGHT from M::B 0.30 here:
### http://search.cpan.org/src/KWILLIAMS/Module-Build-0.30/lib/Module/Build/Platform/Windows.pm:split_like_shell
### XXX this *should* be integrated into text::parsewords
sub _split_like_shell_win32 {
# As it turns out, Windows command-parsing is very different from
# Unix command-parsing. Double-quotes mean different things,
# backslashes don't necessarily mean escapes, and so on. So we
# can't use Text::ParseWords::shellwords() to break a command string
# into words. The algorithm below was bashed out by Randy and Ken
# (mostly Randy), and there are a lot of regression tests, so we
# should feel free to adjust if desired.
local $_ = shift;
inc/inc_IPC-Cmd/IPC/Cmd.pm view on Meta::CPAN
return @argv unless defined() && length();
my $arg = '';
my( $i, $quote_mode ) = ( 0, 0 );
while ( $i < length() ) {
my $ch = substr( $_, $i , 1 );
my $next_ch = substr( $_, $i+1, 1 );
if ( $ch eq '\\' && $next_ch eq '"' ) {
$arg .= '"';
$i++;
} elsif ( $ch eq '\\' && $next_ch eq '\\' ) {
$arg .= '\\';
$i++;
} elsif ( $ch eq '"' && $next_ch eq '"' && $quote_mode ) {
$quote_mode = !$quote_mode;
$arg .= '"';
$i++;
} elsif ( $ch eq '"' && $next_ch eq '"' && !$quote_mode &&
( $i + 2 == length() ||
substr( $_, $i + 2, 1 ) eq ' ' )
) { # for cases like: a"" => [ 'a' ]
push( @argv, $arg );
$arg = '';
$i += 2;
} elsif ( $ch eq '"' ) {
$quote_mode = !$quote_mode;
} elsif ( $ch eq ' ' && !$quote_mode ) {
push( @argv, $arg ) if defined( $arg ) && length( $arg );
$arg = '';
++$i while substr( $_, $i + 1, 1 ) eq ' ';
} else {
$arg .= $ch;
}
$i++;
}
push( @argv, $arg ) if defined( $arg ) && length( $arg );
return @argv;
}
{ use File::Spec;
use Symbol;
my %Map = (
STDOUT => [qw|>&|, \*STDOUT, Symbol::gensym() ],
STDERR => [qw|>&|, \*STDERR, Symbol::gensym() ],
STDIN => [qw|<&|, \*STDIN, Symbol::gensym() ],
);
### dups FDs and stores them in a cache
sub __dup_fds {
my $self = shift;
my @fds = @_;
__PACKAGE__->_debug( "# Closing the following fds: @fds" ) if $DEBUG;
for my $name ( @fds ) {
my($redir, $fh, $glob) = @{$Map{$name}} or (
Carp::carp(loc("No such FD: '%1'", $name)), next );
### MUST use the 2-arg version of open for dup'ing for
### 5.6.x compatibility. 5.8.x can use 3-arg open
### see perldoc5.6.2 -f open for details
open $glob, $redir . fileno($fh) or (
Carp::carp(loc("Could not dup '$name': %1", $!)),
return
);
### we should re-open this filehandle right now, not
### just dup it
### Use 2-arg version of open, as 5.5.x doesn't support
### 3-arg version =/
if( $redir eq '>&' ) {
open( $fh, '>' . File::Spec->devnull ) or (
Carp::carp(loc("Could not reopen '$name': %1", $!)),
return
);
}
}
return 1;
}
### reopens FDs from the cache
sub __reopen_fds {
my $self = shift;
my @fds = @_;
__PACKAGE__->_debug( "# Reopening the following fds: @fds" ) if $DEBUG;
for my $name ( @fds ) {
my($redir, $fh, $glob) = @{$Map{$name}} or (
Carp::carp(loc("No such FD: '%1'", $name)), next );
### MUST use the 2-arg version of open for dup'ing for
### 5.6.x compatibility. 5.8.x can use 3-arg open
### see perldoc5.6.2 -f open for details
open( $fh, $redir . fileno($glob) ) or (
Carp::carp(loc("Could not restore '$name': %1", $!)),
return
);
### close this FD, we're not using it anymore
close $glob;
}
return 1;
}
}
sub _debug {
my $self = shift;
my $msg = shift or return;
my $level = shift || 0;
local $Carp::CarpLevel += $level;
Carp::carp($msg);
return 1;
}
sub _pp_child_error {
my $self = shift;
my $cmd = shift or return;
my $ce = shift or return;
my $pp_cmd = ref $cmd ? "@$cmd" : $cmd;
my $str;
if( $ce == -1 ) {
### Include $! in the error message, so that the user can
### see 'No such file or directory' versus 'Permission denied'
### versus 'Cannot fork' or whatever the cause was.
$str = "Failed to execute '$pp_cmd': $!";
} elsif ( $ce & 127 ) {
### some signal
$str = loc( "'%1' died with signal %d, %s coredump\n",
$pp_cmd, ($ce & 127), ($ce & 128) ? 'with' : 'without');
} else {
### Otherwise, the command run but gave error status.
$str = "'$pp_cmd' exited with value " . ($ce >> 8);
}
$self->_debug( "# Child error '$ce' translated to: $str" ) if $DEBUG;
return $str;
}
1;
=head2 $q = QUOTE
Returns the character used for quoting strings on this platform. This is
usually a C<'> (single quote) on most systems, but some systems use different
quotes. For example, C<Win32> uses C<"> (double quote).
You can use it as follows:
use IPC::Cmd qw[run QUOTE];
my $cmd = q[echo ] . QUOTE . q[foo bar] . QUOTE;
This makes sure that C<foo bar> is treated as a string, rather than two
separate arguments to the C<echo> function.
__END__
=head1 HOW IT WORKS
C<run> will try to execute your command using the following logic:
=over 4
=item *
If you have C<IPC::Run> installed, and the variable C<$IPC::Cmd::USE_IPC_RUN>
is set to true (See the L<"Global Variables"> section) use that to execute
the command. You will have the full output available in buffers, interactive commands
are sure to work and you are guaranteed to have your verbosity
settings honored cleanly.
=item *
Otherwise, if the variable C<$IPC::Cmd::USE_IPC_OPEN3> is set to true
(See the L<"Global Variables"> section), try to execute the command using
L<IPC::Open3>. Buffers will be available on all platforms,
interactive commands will still execute cleanly, and also your verbosity
settings will be adhered to nicely;
=item *
Otherwise, if you have the C<verbose> argument set to true, we fall back
to a simple C<system()> call. We cannot capture any buffers, but
interactive commands will still work.
=item *
Otherwise we will try and temporarily redirect STDERR and STDOUT, do a
C<system()> call with your command and then re-open STDERR and STDOUT.
This is the method of last resort and will still allow you to execute
your commands cleanly. However, no buffers will be available.
=back
=head1 Global Variables
( run in 0.321 second using v1.01-cache-2.11-cpan-d0baa829c65 )