File Coverage

blib/lib/IPC/Run3/Shell.pm
Criterion Covered Total %
statement 199 204 97.5
branch 153 168 91.0
condition 43 45 95.5
subroutine 27 28 96.4
pod 2 5 40.0
total 424 450 94.2


line stmt bran cond sub pod time code
1             #!perl
2             package IPC::Run3::Shell;
3 19     19   1952607 use warnings;
  19         205  
  19         676  
4 19     19   106 use strict;
  19         41  
  19         801  
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-2020 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.58';
21              
22 19     19   106 use Carp;
  19         54  
  19         1098  
23 19     19   124 use warnings::register;
  19         36  
  19         2300  
24 19     19   128 use Scalar::Util qw/ blessed looks_like_number /;
  19         47  
  19         1119  
25 19     19   12481 use Data::Dumper ();
  19         135282  
  19         518  
26 19     19   133 use overload ();
  19         45  
  19         761  
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 19 50   19   4417 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             sub _dcopy { # slightly kludgy hack because Dumper with Purity issues warnings about code references (e.g. stdout_filter option)
40 12     12   26 my $v = shift;
41 12 100       36 return [ map { _dcopy($_) } @$v ] if ref $v eq 'ARRAY';
  6         23  
42 6 50       13 return { map { $_ => _dcopy($$v{$_}) } keys %$v } if ref $v eq 'HASH';
  0         0  
43 6 50       12 return 'CODE' if ref $v eq 'CODE';
44 6         84 return $v;
45             }
46 6     6 0 58 sub pp { return $dumper->Values(_dcopy(\@_))->Reset->Dump } ## no critic (RequireArgUnpacking)
47              
48 19     19   9846 use IPC::Run3 ();
  19         215782  
  19         1482  
49              
50             my @RUN3_OPTS = qw/ binmode_stdin binmode_stdout binmode_stderr append_stdout append_stderr return_if_system_error /;
51             my %KNOWN_OPTS = map { $_=>1 } @RUN3_OPTS,
52             qw/ show_cmd allow_exit irs chomp stdin stdout stderr fail_on_stderr both stdout_filter /;
53              
54             our $OBJECT_PACKAGE;
55             {
56             package ## no critic (ProhibitMultiplePackages)
57             IPC::Run3::Shell::Autoload; # hide from PAUSE by splitting onto two lines
58 19     19   1565 BEGIN { $IPC::Run3::Shell::OBJECT_PACKAGE = __PACKAGE__ }
59             our $AUTOLOAD;
60             sub AUTOLOAD { ## no critic (ProhibitAutoloading)
61 14     14   9882 my $cmd = $AUTOLOAD;
62 14 50       66 IPC::Run3::Shell::debug "Autoloading '$cmd'" if $IPC::Run3::Shell::DEBUG;
63 14         150 $cmd =~ s/^.*:://;
64 19     19   177 no strict 'refs'; ## no critic (ProhibitNoStrict)
  19         46  
  19         7296  
65 14         103 *$AUTOLOAD = IPC::Run3::Shell::make_cmd($cmd);
66 14         111 goto &$AUTOLOAD;
67             }
68       0     sub DESTROY {} # so AUTOLOAD isn't called on destruction
69             }
70              
71             sub new {
72 14     14 0 24003 my ($class, %opt) = @_;
73 14         134 return bless \%opt, $OBJECT_PACKAGE;
74             }
75              
76             my %EXPORTABLE = map {$_=>1} qw/ make_cmd /; # "run" gets special handling
77              
78             # this run() is for calling via IPC::Run3::Shell::run(), note that we don't export this below
79             *run = make_cmd();
80              
81             sub import {
82 28     28   7547 my ($class, @export) = @_;
83 28         110 my ($callpack) = caller;
84 28         110 return import_into($class, $callpack, @export);
85             }
86              
87             sub import_into {
88 29     29 1 352 my ($class, $callpack, @export) = @_;
89 29         56 my %opt;
90 29         222 %opt = ( %opt, %{shift @export} ) while ref $export[0] eq 'HASH';
  7         32  
91 29         93 for my $exp (@export) {
92 31 100 100     298 if (!defined $exp) {
    100 100        
93 2         307 warnings::warnif('uninitialized','Use of uninitialized value in import');
94 1         25 next;
95             }
96             elsif ( !ref($exp) && $exp && ( my ($sym) = $exp=~/^:(\w+)$/ ) ) {
97 10 100       39 if ($sym eq 'run') {
    100          
    100          
98             # instead of exporting 'run', we actually export a make_cmd closure (with default options but *no* arguments)
99 5 50       28 debug "Exporting '${callpack}::$sym' => make_cmd("._cmd2str(\%opt).")" if $DEBUG;
100 19     19   169 no strict 'refs'; ## no critic (ProhibitNoStrict)
  19         67  
  19         1998  
101 5         21 *{"${callpack}::$sym"} = make_cmd(\%opt);
  5         41  
102             }
103             elsif ($sym eq 'AUTOLOAD') {
104 1 50       2 debug "Exporting '${callpack}::$sym'" if $DEBUG;
105 19     19   139 no strict 'refs'; ## no critic (ProhibitNoStrict)
  19         44  
  19         3066  
106 1         2 *{"${callpack}::AUTOLOAD"} = \&{"${OBJECT_PACKAGE}::AUTOLOAD"};
  1         5  
  1         6  
107             }
108             elsif ($sym eq 'FATAL') {
109 1         6 debug "Enabling fatal warnings";
110 1         29 warnings->import(FATAL=>'IPC::Run3::Shell');
111             }
112             else {
113 3 100       106 croak "$class can't export \"$sym\"" unless $EXPORTABLE{$sym};
114 2         7 my $target = __PACKAGE__."::$sym";
115 2 50       6 debug "Exporting '${callpack}::$sym' => '$target'" if $DEBUG;
116 19     19   168 no strict 'refs'; ## no critic (ProhibitNoStrict)
  19         38  
  19         2644  
117 2         4 *{"${callpack}::$sym"} = \&{$target};
  2         11  
  2         6  
118             }
119             }
120             else {
121 19 100       89 my ($sym, @cmd) = ref $exp eq 'ARRAY' ? @$exp : ($exp, $exp);
122 19 100       317 croak "$class: no function name specified" unless $sym;
123 16         68 $sym = _strify($sym); # warn on refs
124 15 100       142 croak "$class: empty command for function \"$sym\"" unless @cmd;
125 14 50       34 debug "Exporting '${callpack}::$sym' => make_cmd("._cmd2str(\%opt, @cmd).")" if $DEBUG;
126 19     19   141 no strict 'refs'; ## no critic (ProhibitNoStrict)
  19         42  
  19         9553  
127 14         41 *{"${callpack}::$sym"} = make_cmd(\%opt, @cmd);
  14         119  
128             }
129             }
130 22         4231 return;
131             }
132              
133             sub make_cmd { ## no critic (ProhibitExcessComplexity)
134 64     64 1 1554 my @omcmd = @_;
135 64 100 100     786 warnings::warnif(__PACKAGE__."::make_cmd() may have been called as a method")
136             if $omcmd[0] && $omcmd[0] eq __PACKAGE__ ;
137             return sub {
138 218     218   153423 my @acmd = @_; # args to this function call
139 218         823 my @mcmd = @omcmd; # copy of args to make_cmd
140             # if we are a method, get default options from the object
141 218 100 100     3008 my %opt = blessed($acmd[0]) && $acmd[0]->isa($OBJECT_PACKAGE) ? %{shift @acmd} : ();
  134         822  
142             # hashrefs as the first argument of make_cmd and this method override current options
143 218         938 %opt = ( %opt, %{shift @mcmd} ) while ref $mcmd[0] eq 'HASH';
  79         400  
144 218         945 %opt = ( %opt, %{shift @acmd} ) while ref $acmd[0] eq 'HASH';
  141         753  
145             # now look at the back of @acmd
146 218         443 my @tmp_opts;
147 218         666 push @tmp_opts, pop @acmd while ref $acmd[-1] eq 'HASH';
148 218         659 %opt = ( %opt, %{pop @tmp_opts} ) while @tmp_opts;
  28         155  
149             # this is for the tests that test the option inheritance mechanism
150 218 100 100     1876 if (exists $opt{__TEST_OPT_A} || exists $opt{__TEST_OPT_B}) {
151             return join ',', (
152             exists $opt{__TEST_OPT_A} ? 'A='.(defined $opt{__TEST_OPT_A} ? $opt{__TEST_OPT_A} : 'undef') : (),
153 45 100       536 exists $opt{__TEST_OPT_B} ? 'B='.(defined $opt{__TEST_OPT_B} ? $opt{__TEST_OPT_B} : 'undef') : () );
    100          
    100          
    100          
154             }
155             # check options for validity
156 173         661 for (keys %opt) {
157             warnings::warnif(__PACKAGE__.": unknown option \"$_\"")
158 141 100       1024 unless $KNOWN_OPTS{$_};
159             }
160 172 100       994 if (defined $opt{stdout_filter}) {
161             croak __PACKAGE__.": option stdout_filter must be a coderef"
162 16 100       541 unless ref $opt{stdout_filter} eq 'CODE'}
163 170 100       755 my $allow_exit = defined $opt{allow_exit} ? $opt{allow_exit} : [0];
164 170 100       726 if ($allow_exit ne 'ANY') {
165 166 100       652 $allow_exit = [$allow_exit] unless ref $allow_exit eq 'ARRAY';
166 166 100       967 warnings::warnif(__PACKAGE__.": allow_exit is empty") unless @$allow_exit;
167 166         514 for (@$allow_exit) {
168             # We throw our own custom warning instead of Perl's regular warning because Perl's warning
169             # would be reported in this module instead of the calling code.
170 172 100 100     2582 warnings::warnif('numeric','Argument "'.(defined($_)?$_:"(undef)").'" isn\'t numeric in allow_exit')
    100          
171             unless defined && looks_like_number($_);
172 19     19   163 no warnings 'numeric', 'uninitialized'; ## no critic (ProhibitNoWarnings)
  19         64  
  19         24725  
173 170         785 $_ = 0+$_; # so later usage as a number isn't a warning
174             }
175             }
176             # Possible To-Do for Later: Define priorities for incompatible options so we can carp instead of croaking?
177             # Also maybe look at some other places where we croak at runtime to see if there is any way to carp there instead.
178             croak __PACKAGE__.": can't use options stderr and fail_on_stderr at the same time"
179 168 100 100     1075 if exists $opt{stderr} && $opt{fail_on_stderr};
180             croak __PACKAGE__.": can't use options both and stdout at the same time"
181 167 100 100     985 if $opt{both} && exists $opt{stdout};
182             croak __PACKAGE__.": can't use options both and stderr at the same time"
183 166 100 100     560 if $opt{both} && exists $opt{stderr};
184             croak __PACKAGE__.": can't use options both and fail_on_stderr at the same time"
185 165 100 100     524 if $opt{both} && $opt{fail_on_stderr};
186             # assemble command (after having processed any option hashes etc.)
187 164         865 my @fcmd = (@mcmd, @acmd);
188 164 100       596 croak __PACKAGE__.": empty command" unless @fcmd;
189             # stringify the stringifiable things, handle undef, and warn on refs
190 163         434 @fcmd = map {_strify($_)} @fcmd;
  572         2447  
191            
192             # prepare STDOUT redirection
193 155         494 my ($out, $stdout) = ('');
194 155 100       706 if (exists $opt{stdout}) ## no critic (ProhibitCascadingIfElse)
    100          
    100          
    100          
195 20         58 { $stdout = $opt{stdout} }
196             elsif ($opt{both})
197 12 100       60 { $stdout = defined(wantarray) ? \$out : undef }
198             elsif (wantarray)
199 14         66 { $stdout = $out = [] }
200             elsif (defined(wantarray))
201 65         147 { $stdout = \$out }
202             else
203 44         108 { $stdout = undef }
204             # prepare STDERR redirection
205 155         416 my ($err, $stderr) = ('');
206 155 100       523 if (exists $opt{stderr})
    100          
    100          
207 7         246 { $stderr = $opt{stderr} }
208             elsif ($opt{fail_on_stderr})
209 9         30 { $stderr = \$err }
210             elsif ($opt{both})
211 12 100       172 { $stderr = wantarray ? \$err : ( defined(wantarray) ? \$out : undef ) }
    100          
212             else
213 127         220 { $stderr = undef }
214             # prepare options hash
215 155         431 my %r3o = ( return_if_system_error=>1 );
216 155 100       1139 for (@RUN3_OPTS) { $r3o{$_} = $opt{$_} if exists $opt{$_} }
  930         3124  
217             # execute and process
218 155 50       404 debug "run3("._cmd2str(@fcmd).") ".pp(\%opt) if $DEBUG;
219 155 100       371 print { ref $opt{show_cmd} eq 'GLOB' ? $opt{show_cmd} : \*STDERR } '$ '._cmd2str(@fcmd)."\n" if $opt{show_cmd};
  5 100       41  
220 155 100       1040 local $/ = exists $opt{irs} ? $opt{irs} : $/;
221             # NOTE that we've documented that the user can rely on $?, so don't mess with it
222 155 100       996 IPC::Run3::run3( \@fcmd, $opt{stdin}, $stdout, $stderr, \%r3o )
223             or croak __PACKAGE__." (internal): run3 \"$fcmd[0]\" failed";
224 154         861212 my $exitcode = $?>>8;
225             croak "Command \"$fcmd[0]\" failed: process wrote to STDERR: \"$err\""
226 154 100 100     3798 if $opt{fail_on_stderr} && $err ne '' && $err ne $/;
      100        
227 149 100       1467 if ($? == -1) {
    100          
228 3         1049 warnings::warnif("Command \"$fcmd[0]\" failed: $!");
229             return
230 2         216 }
231             elsif ($?&127) {
232 4 100       1445 warnings::warnif(sprintf("Command \"%s\" failed: signal %d, %s coredump",
233             $fcmd[0], ($?&127), ($?&128)?'with':'without' ))
234             }
235             else {
236             # allow_exit is checked for validity above
237             warnings::warnif("Command \"$fcmd[0]\" failed: exit status $exitcode")
238 142 100 100     4352 unless $allow_exit eq 'ANY' || grep {$_==$exitcode} @$allow_exit;
  144         7802  
239             }
240 134 100       3800 return unless defined wantarray;
241 102 100       1132 if (exists $opt{stdout})
    100          
    100          
242 14         1436 { return $exitcode }
243             elsif ($opt{both}) {
244 11 100       104 chomp($out,$err) if $opt{chomp};
245 11 100       57 if ($opt{stdout_filter}) { for ($out) { $opt{stdout_filter}->() } }
  1         12  
  1         12  
246 11 100       972 return wantarray ? ($out, $err, $exitcode) : $out
247             }
248             elsif (wantarray) {
249 14 100       223 chomp(@$out) if $opt{chomp};
250 14 100       124 if ($opt{stdout_filter}) { for (@$out) { $opt{stdout_filter}->() } }
  4         20  
  8         107  
251 14         1751 return @$out
252             }
253             else {
254 63 100       409 chomp($out) if $opt{chomp};
255 63 100       316 if ($opt{stdout_filter}) { for ($out) { $opt{stdout_filter}->() } }
  7         39  
  7         84  
256 63         6825 return $out
257             }
258             }
259 63         950 }
260              
261             # This function attempts to behave like normal Perl stringification, but it adds two things:
262             # 1. Warnings on undef, in Perl's normal "uninitialized" category, the difference being that
263             # with "warnif", they will appear to originate in the calling code, and not in this function.
264             # 2. Warn if we are passed a reference that is not an object with overloaded stringification,
265             # since that is much more likely to be a mistake on the part of the user instead of intentional.
266             sub _strify {
267 602     602   26477 my ($x) = @_;
268 602 100 100     2262 if (!defined $x) {
    100          
269 4         1014 warnings::warnif('uninitialized','Use of uninitialized value in argument list');
270 1         14 return "" }
271             elsif (blessed($x) && overload::Overloaded($x)) { # an object with overloading
272 9 100       343 if (overload::Method($x,'""')) # stringification explicitly defined, it'll work
    100          
    100          
273 4         257 { return "$x" }
274             # Else, stringification is not explicitly defined - stringification *may* work through autogeneration, but it may also die.
275             # There doesn't seem to be a way to ask Perl if stringification will die or not other than trying it out with eval.
276             # See also: http://www.perlmonks.org/?node_id=1121710
277             # Reminder to self: "$x" will always be defined; even if overloaded stringify returns undef;
278             # undef interpolated into the string will cause warning, but the resulting empty string is still defined.
279 5         329 elsif (defined(my $rv = eval { "$x" }))
280 2         26 { return $rv }
281             elsif ($@=~/\bno method found\b/) { # overloading failed, throw custom error
282             # Note: as far as I can tell the message "no method found"
283             # hasn't changed since its intoduction in Perl 5.000
284             # (e.g. git log -p -S 'no method found' gv.c )
285             # Perl bug #31793, which relates to overload::StrVal, apparently also caused problems with Carp
286 2 50 33     17 if (!$overload::VERSION || $overload::VERSION<1.04)
287 0         0 { die "Package ".ref($x)." doesn't overload stringification: $@" } ## no critic (RequireCarping)
288             else
289 2         182 { croak "Package ".ref($x)." doesn't overload stringification: $@" }
290             }
291             # something other than overloading failed, just re-throw
292 1         18 else { die $@ } ## no critic (RequireCarping)
293             # Remember that Perl's normal behavior should stringification not be
294             # available is to die; we're just propagating that behavior outward.
295             }
296             else {
297             # Note that objects without any overloading will stringify using Perl's default mechanism
298 589 100       2537 ref($x) and warnings::warnif(__PACKAGE__.": argument list contains references/objects");
299 583         2194 return "$x" }
300             }
301              
302             # function for sorta-pretty-printing commands
303             sub _cmd2str {
304 5     5   14 my @c = @_;
305 5         25 my $o = '';
306 5         27 for my $c (@c) {
307 18 100       37 $o .= ' ' if $o;
308 18 50       35 if (ref $c eq 'HASH') { # options
309             # note we don't pay attention to where in the argument list we are
310             # (I don't expect hashrefs to appear as arguments, the user is even warned about them)
311 0         0 $o .= pp($c);
312             }
313             else {
314 18 50       39 my $s = defined $c ? "$c" : '';
315 18 100       123 $s = pp($s) if $s=~/[^\w\-\=\/\.]/;
316 18         439 $o .= $s;
317             }
318             }
319 5         171 return $o;
320             }
321              
322              
323             1;