File Coverage

blib/lib/IPC/Run3/Shell.pm
Criterion Covered Total %
statement 182 186 97.8
branch 139 152 91.4
condition 43 45 95.5
subroutine 26 27 96.3
pod 2 5 40.0
total 392 415 94.4


line stmt bran cond sub pod time code
1             #!perl
2             package IPC::Run3::Shell;
3 17     17   1629920 use warnings;
  17         446  
  17         641  
4 17     17   108 use strict;
  17         37  
  17         699  
5              
6             # ##### This is the Perl module IPC::Run3::Shell #####
7             #
8             # Documentation can be found in the file Shell.pod (or via the perldoc command).
9             #
10             # Copyright (c) 2014 Hauke Daempfling (haukex@zero-g.net).
11             #
12             # This library is free software; you can redistribute it and/or modify
13             # it under the same terms as Perl 5 itself.
14             #
15             # For more information see the "Perl Artistic License",
16             # which should have been distributed with your copy of Perl.
17             # Try the command "perldoc perlartistic" or see
18             # http://perldoc.perl.org/perlartistic.html .
19              
20             our $VERSION = '0.56';
21              
22 17     17   105 use Carp;
  17         38  
  17         1071  
23 17     17   118 use warnings::register;
  17         45  
  17         2488  
24 17     17   117 use Scalar::Util qw/ blessed looks_like_number /;
  17         45  
  17         876  
25 17     17   7139 use Data::Dumper ();
  17         107112  
  17         483  
26 17     17   125 use overload ();
  17         39  
  17         685  
27              
28             # debugging stuff
29             # either set env var or set this var externally (may set to a fh / glob ref)
30             our $DEBUG;
31 17 50   17   2411 BEGIN { $DEBUG = ! ! $ENV{IPC_RUN3_SHELL_DEBUG} unless $DEBUG }
32             sub debug { ## no critic (RequireArgUnpacking)
33 1 50   1 0 3 return unless $DEBUG;
34 0 0       0 return print { ref $DEBUG eq 'GLOB' ? $DEBUG : \*STDERR } "# ", __PACKAGE__, " Debug: ", @_, "\n";
  0         0  
35             }
36              
37             my $dumper = Data::Dumper->new([])->Terse(1)->Purity(1)
38             ->Useqq(1)->Quotekeys(0)->Sortkeys(1)->Indent(0)->Pair('=>');
39 6     6 0 55 sub pp { return $dumper->Values(\@_)->Reset->Dump } ## no critic (RequireArgUnpacking)
40              
41 17     17   5385 use IPC::Run3 ();
  17         168056  
  17         1388  
42              
43             my @RUN3_OPTS = qw/ binmode_stdin binmode_stdout binmode_stderr append_stdout append_stderr return_if_system_error /;
44             my %KNOWN_OPTS = map { $_=>1 } @RUN3_OPTS,
45             qw/ show_cmd allow_exit irs chomp stdin stdout stderr fail_on_stderr both /;
46              
47             our $OBJECT_PACKAGE;
48             {
49             package ## no critic (ProhibitMultiplePackages)
50             IPC::Run3::Shell::Autoload; # hide from PAUSE by splitting onto two lines
51 17     17   1394 BEGIN { $IPC::Run3::Shell::OBJECT_PACKAGE = __PACKAGE__ }
52             our $AUTOLOAD;
53             sub AUTOLOAD { ## no critic (ProhibitAutoloading)
54 13     13   7662 my $cmd = $AUTOLOAD;
55 13 50       64 IPC::Run3::Shell::debug "Autoloading '$cmd'" if $IPC::Run3::Shell::DEBUG;
56 13         106 $cmd =~ s/^.*:://;
57 17     17   146 no strict 'refs'; ## no critic (ProhibitNoStrict)
  17         41  
  17         5903  
58 13         68 *$AUTOLOAD = IPC::Run3::Shell::make_cmd($cmd);
59 13         78 goto &$AUTOLOAD;
60             }
61       0     sub DESTROY {} # so AUTOLOAD isn't called on destruction
62             }
63              
64             sub new {
65 13     13 0 18502 my ($class, %opt) = @_;
66 13         85 return bless \%opt, $OBJECT_PACKAGE;
67             }
68              
69             my %EXPORTABLE = map {$_=>1} qw/ make_cmd /; # "run" gets special handling
70              
71             # this run() is for calling via IPC::Run3::Shell::run(), note that we don't export this below
72             *run = make_cmd();
73              
74             sub import {
75 27     27   6210 my ($class, @export) = @_;
76 27         103 my ($callpack) = caller;
77 27         100 return import_into($class, $callpack, @export);
78             }
79              
80             sub import_into {
81 28     28 1 303 my ($class, $callpack, @export) = @_;
82 28         57 my %opt;
83 28         193 %opt = ( %opt, %{shift @export} ) while ref $export[0] eq 'HASH';
  7         41  
84 28         82 for my $exp (@export) {
85 31 100 100     223 if (!defined $exp) {
    100 100        
86 2         306 warnings::warnif('uninitialized','Use of uninitialized value in import');
87 1         18 next;
88             }
89             elsif ( !ref($exp) && $exp && ( my ($sym) = $exp=~/^:(\w+)$/ ) ) {
90 10 100       49 if ($sym eq 'run') {
    100          
    100          
91             # instead of exporting 'run', we actually export a make_cmd closure (with default options but *no* arguments)
92 5 50       13 debug "Exporting '${callpack}::$sym' => make_cmd("._cmd2str(\%opt).")" if $DEBUG;
93 17     17   137 no strict 'refs'; ## no critic (ProhibitNoStrict)
  17         40  
  17         1544  
94 5         14 *{"${callpack}::$sym"} = make_cmd(\%opt);
  5         32  
95             }
96             elsif ($sym eq 'AUTOLOAD') {
97 1 50       3 debug "Exporting '${callpack}::$sym'" if $DEBUG;
98 17     17   409 no strict 'refs'; ## no critic (ProhibitNoStrict)
  17         45  
  17         2373  
99 1         1 *{"${callpack}::AUTOLOAD"} = \&{"${OBJECT_PACKAGE}::AUTOLOAD"};
  1         7  
  1         7  
100             }
101             elsif ($sym eq 'FATAL') {
102 1         6 debug "Enabling fatal warnings";
103 1         26 warnings->import(FATAL=>'IPC::Run3::Shell');
104             }
105             else {
106 3 100       117 croak "$class can't export \"$sym\"" unless $EXPORTABLE{$sym};
107 2         8 my $target = __PACKAGE__."::$sym";
108 2 50       6 debug "Exporting '${callpack}::$sym' => '$target'" if $DEBUG;
109 17     17   119 no strict 'refs'; ## no critic (ProhibitNoStrict)
  17         44  
  17         2194  
110 2         3 *{"${callpack}::$sym"} = \&{$target};
  2         11  
  2         8  
111             }
112             }
113             else {
114 19 100       83 my ($sym, @cmd) = ref $exp eq 'ARRAY' ? @$exp : ($exp, $exp);
115 19 100       262 croak "$class: no function name specified" unless $sym;
116 16         46 $sym = _strify($sym); # warn on refs
117 15 100       121 croak "$class: empty command for function \"$sym\"" unless @cmd;
118 14 50       37 debug "Exporting '${callpack}::$sym' => make_cmd("._cmd2str(\%opt, @cmd).")" if $DEBUG;
119 17     17   123 no strict 'refs'; ## no critic (ProhibitNoStrict)
  17         38  
  17         6912  
120 14         42 *{"${callpack}::$sym"} = make_cmd(\%opt, @cmd);
  14         112  
121             }
122             }
123 21         4357 return;
124             }
125              
126             sub make_cmd { ## no critic (ProhibitExcessComplexity)
127 55     55 1 1149 my @omcmd = @_;
128 55 100 100     439 warnings::warnif(__PACKAGE__."::make_cmd() may have been called as a method")
129             if $omcmd[0] && $omcmd[0] eq __PACKAGE__ ;
130             return sub {
131 190     190   130665 my @acmd = @_; # args to this function call
132 190         719 my @mcmd = @omcmd; # copy of args to make_cmd
133             # if we are a method, get default options from the object
134 190 100 100     1934 my %opt = blessed($acmd[0]) && $acmd[0]->isa($OBJECT_PACKAGE) ? %{shift @acmd} : ();
  116         464  
135             # hashrefs as the first argument of make_cmd and this method override current options
136 190         838 %opt = ( %opt, %{shift @mcmd} ) while ref $mcmd[0] eq 'HASH';
  69         284  
137 190         855 %opt = ( %opt, %{shift @acmd} ) while ref $acmd[0] eq 'HASH';
  123         709  
138             # now look at the back of @acmd
139 190         383 my @tmp_opts;
140 190         595 push @tmp_opts, pop @acmd while ref $acmd[-1] eq 'HASH';
141 190         618 %opt = ( %opt, %{pop @tmp_opts} ) while @tmp_opts;
  25         128  
142             # this is for the tests that test the option inheritance mechanism
143 190 100 100     1197 if (exists $opt{__TEST_OPT_A} || exists $opt{__TEST_OPT_B}) {
144             return join ',', (
145             exists $opt{__TEST_OPT_A} ? 'A='.(defined $opt{__TEST_OPT_A} ? $opt{__TEST_OPT_A} : 'undef') : (),
146 45 100       420 exists $opt{__TEST_OPT_B} ? 'B='.(defined $opt{__TEST_OPT_B} ? $opt{__TEST_OPT_B} : 'undef') : () );
    100          
    100          
    100          
147             }
148             # check options for validity
149 145         502 for (keys %opt) {
150             warnings::warnif(__PACKAGE__.": unknown option \"$_\"")
151 113 100       906 unless $KNOWN_OPTS{$_};
152             }
153 144 100       774 my $allow_exit = defined $opt{allow_exit} ? $opt{allow_exit} : [0];
154 144 100       640 if ($allow_exit ne 'ANY') {
155 140 100       506 $allow_exit = [$allow_exit] unless ref $allow_exit eq 'ARRAY';
156 140 100       1102 warnings::warnif(__PACKAGE__.": allow_exit is empty") unless @$allow_exit;
157 140         741 for (@$allow_exit) {
158             # We throw our own custom warning instead of Perl's regular warning because Perl's warning
159             # would be reported in this module instead of the calling code.
160 146 100 100     1886 warnings::warnif('numeric','Argument "'.(defined($_)?$_:"(undef)").'" isn\'t numeric in allow_exit')
    100          
161             unless defined && looks_like_number($_);
162 17     17   127 no warnings 'numeric', 'uninitialized'; ## no critic (ProhibitNoWarnings)
  17         35  
  17         19415  
163 144         769 $_ = 0+$_; # so later usage as a number isn't a warning
164             }
165             }
166             # Possible To-Do for Later: Define priorities for incompatible options so we can carp instead of croaking?
167             # Also maybe look at some other places where we croak at runtime to see if there is any way to carp there instead.
168             croak __PACKAGE__.": can't use options stderr and fail_on_stderr at the same time"
169 142 100 100     645 if exists $opt{stderr} && $opt{fail_on_stderr};
170             croak __PACKAGE__.": can't use options both and stdout at the same time"
171 141 100 100     615 if $opt{both} && exists $opt{stdout};
172             croak __PACKAGE__.": can't use options both and stderr at the same time"
173 140 100 100     486 if $opt{both} && exists $opt{stderr};
174             croak __PACKAGE__.": can't use options both and fail_on_stderr at the same time"
175 139 100 100     476 if $opt{both} && $opt{fail_on_stderr};
176             # assemble command (after having processed any option hashes etc.)
177 138         487 my @fcmd = (@mcmd, @acmd);
178 138 100       1398 croak __PACKAGE__.": empty command" unless @fcmd;
179             # stringify the stringifiable things, handle undef, and warn on refs
180 137         454 @fcmd = map {_strify($_)} @fcmd;
  434         1459  
181            
182             # prepare STDOUT redirection
183 129         401 my ($out, $stdout) = ('');
184 129 100       1443 if (exists $opt{stdout}) ## no critic (ProhibitCascadingIfElse)
    100          
    100          
    100          
185 18         63 { $stdout = $opt{stdout} }
186             elsif ($opt{both})
187 9 100       20 { $stdout = defined(wantarray) ? \$out : undef }
188             elsif (wantarray)
189 10         38 { $stdout = $out = [] }
190             elsif (defined(wantarray))
191 48         136 { $stdout = \$out }
192             else
193 44         122 { $stdout = undef }
194             # prepare STDERR redirection
195 129         356 my ($err, $stderr) = ('');
196 129 100       699 if (exists $opt{stderr})
    100          
    100          
197 6         23 { $stderr = $opt{stderr} }
198             elsif ($opt{fail_on_stderr})
199 9         21 { $stderr = \$err }
200             elsif ($opt{both})
201 9 100       22 { $stderr = wantarray ? \$err : ( defined(wantarray) ? \$out : undef ) }
    100          
202             else
203 105         221 { $stderr = undef }
204             # prepare options hash
205 129         483 my %r3o = ( return_if_system_error=>1 );
206 129 100       632 for (@RUN3_OPTS) { $r3o{$_} = $opt{$_} if exists $opt{$_} }
  774         2135  
207             # execute and process
208 129 50       365 debug "run3("._cmd2str(@fcmd).") ".pp(\%opt) if $DEBUG;
209 129 100       414 print { ref $opt{show_cmd} eq 'GLOB' ? $opt{show_cmd} : \*STDERR } '$ '._cmd2str(@fcmd)."\n" if $opt{show_cmd};
  5 100       33  
210 129 100       1412 local $/ = exists $opt{irs} ? $opt{irs} : $/;
211             # NOTE that we've documented that the user can rely on $?, so don't mess with it
212 129 100       826 IPC::Run3::run3( \@fcmd, $opt{stdin}, $stdout, $stderr, \%r3o )
213             or croak __PACKAGE__." (internal): run3 \"$fcmd[0]\" failed";
214 128         745286 my $exitcode = $?>>8;
215             croak "Command \"$fcmd[0]\" failed: process wrote to STDERR: \"$err\""
216 128 100 100     1839 if $opt{fail_on_stderr} && $err ne '' && $err ne $/;
      100        
217 123 100       939 if ($? == -1) {
    100          
218 3         1075 warnings::warnif("Command \"$fcmd[0]\" failed: $!");
219             return
220 2         246 }
221             elsif ($?&127) {
222 4 100       1397 warnings::warnif(sprintf("Command \"%s\" failed: signal %d, %s coredump",
223             $fcmd[0], ($?&127), ($?&128)?'with':'without' ))
224             }
225             else {
226             # allow_exit is checked for validity above
227             warnings::warnif("Command \"$fcmd[0]\" failed: exit status $exitcode")
228 116 100 100     2330 unless $allow_exit eq 'ANY' || grep {$_==$exitcode} @$allow_exit;
  118         5401  
229             }
230 108 100       1951 return unless defined wantarray;
231 76 100       480 if (exists $opt{stdout})
    100          
    100          
232 12         488 { return $exitcode }
233             elsif ($opt{both}) {
234 8 100       24 chomp($out,$err) if $opt{chomp};
235 8 100       240 return wantarray ? ($out, $err, $exitcode) : $out
236             }
237             elsif (wantarray) {
238 10 100       75 chomp(@$out) if $opt{chomp};
239 10         401 return @$out
240             }
241             else {
242 46 100       190 chomp($out) if $opt{chomp};
243 46         1773 return $out
244             }
245             }
246 54         576 }
247              
248             # This function attempts to behave like normal Perl stringification, but it adds two things:
249             # 1. Warnings on undef, in Perl's normal "uninitialized" category, the difference being that
250             # with "warnif", they will appear to originate in the calling code, and not in this function.
251             # 2. Warn if we are passed a reference that is not an object with overloaded stringification,
252             # since that is much more likely to be a mistake on the part of the user instead of intentional.
253             sub _strify {
254 464     464   23593 my ($x) = @_;
255 464 100 100     1912 if (!defined $x) {
    100          
256 4         758 warnings::warnif('uninitialized','Use of uninitialized value in argument list');
257 1         11 return "" }
258             elsif (blessed($x) && overload::Overloaded($x)) { # an object with overloading
259 9 100       274 if (overload::Method($x,'""')) # stringification explicitly defined, it'll work
    100          
    100          
260 4         236 { return "$x" }
261             # Else, stringification is not explicitly defined - stringification *may* work through autogeneration, but it may also die.
262             # There doesn't seem to be a way to ask Perl if stringification will die or not other than trying it out with eval.
263             # See also: http://www.perlmonks.org/?node_id=1121710
264             # Reminder to self: "$x" will always be defined; even if overloaded stringify returns undef;
265             # undef interpolated into the string will cause warning, but the resulting empty string is still defined.
266 5         252 elsif (defined(my $rv = eval { "$x" }))
267 2         21 { return $rv }
268             elsif ($@=~/\bno method found\b/) { # overloading failed, throw custom error
269             # Note: as far as I can tell the message "no method found"
270             # hasn't changed since its intoduction in Perl 5.000
271             # (e.g. git log -p -S 'no method found' gv.c )
272             # Perl bug #31793, which relates to overload::StrVal, apparently also caused problems with Carp
273 2 50 33     14 if (!$overload::VERSION || $overload::VERSION<1.04)
274 0         0 { die "Package ".ref($x)." doesn't overload stringification: $@" } ## no critic (RequireCarping)
275             else
276 2         177 { croak "Package ".ref($x)." doesn't overload stringification: $@" }
277             }
278             # something other than overloading failed, just re-throw
279 1         13 else { die $@ } ## no critic (RequireCarping)
280             # Remember that Perl's normal behavior should stringification not be
281             # available is to die; we're just propagating that behavior outward.
282             }
283             else {
284             # Note that objects without any overloading will stringify using Perl's default mechanism
285 451 100       2551 ref($x) and warnings::warnif(__PACKAGE__.": argument list contains references/objects");
286 445         1933 return "$x" }
287             }
288              
289             # function for sorta-pretty-printing commands
290             sub _cmd2str {
291 5     5   23 my @c = @_;
292 5         11 my $o = '';
293 5         13 for my $c (@c) {
294 18 100       43 $o .= ' ' if $o;
295 18 50       42 if (ref $c eq 'HASH') { # options
296             # note we don't pay attention to where in the argument list we are
297             # (I don't expect hashrefs to appear as arguments, the user is even warned about them)
298 0         0 $o .= pp($c);
299             }
300             else {
301 18 50       44 my $s = defined $c ? "$c" : '';
302 18 100       91 $s = pp($s) if $s=~/[^\w\-\=\/\.]/;
303 18         375 $o .= $s;
304             }
305             }
306 5         175 return $o;
307             }
308              
309              
310             1;