File Coverage

blib/lib/Footprintless/CommandRunner/IPCRun.pm
Criterion Covered Total %
statement 56 56 100.0
branch 18 18 100.0
condition 17 19 89.4
subroutine 8 8 100.0
pod n/a
total 99 101 98.0


line stmt bran cond sub pod time code
1 7     7   1068 use strict;
  7         20  
  7         254  
2 7     7   47 use warnings;
  7         19  
  7         401  
3              
4             package Footprintless::CommandRunner::IPCRun;
5             $Footprintless::CommandRunner::IPCRun::VERSION = '1.26';
6             # ABSTRACT: An implementation of Footprintless::CommandRunner using IPC::Run
7             # PODNAME: Footprintless::CommandRunner::IPCRun
8              
9 7     7   41 use parent qw(Footprintless::CommandRunner);
  7         15  
  7         59  
10              
11 7     7   388 use Carp;
  7         17  
  7         397  
12 7     7   4624 use IPC::Run;
  7         144718  
  7         306  
13 7     7   56 use Log::Any;
  7         15  
  7         67  
14              
15             my $logger = Log::Any->get_logger();
16              
17             sub _run_options {
18 26     26   153 my ( $self, $runner_options ) = @_;
19 26         59 my @timeout;
20 26 100       100 if ( $runner_options->{timeout} ) {
21 3         36 @timeout = ( IPC::Run::timeout( $runner_options->{timeout} ) );
22             }
23              
24 26   100     923 my $in = $runner_options->{in_handle} || \undef;
25             my $out =
26             $runner_options->{out_handle}
27             || $runner_options->{out_callback}
28 26   100     242 || \$self->{last_call}{stdout};
29             my $err =
30             $runner_options->{err_handle}
31             || $runner_options->{err_callback}
32 26   100     248 || \$self->{last_call}{stderr};
33              
34 26         202 return ( '<', $in, '>', $out, '2>', $err, @timeout );
35             }
36              
37             sub _run {
38 26     26   90 my ( $self, $command, $runner_options ) = @_;
39 26 100 100     226 if ( $runner_options->{out_callback} || $runner_options->{err_callback} ) {
40 4         13 my $out_callback = $runner_options->{out_callback};
41 4         9 my $err_callback = $runner_options->{err_callback};
42              
43 4         10 my ( $out, $err );
44 4 100       16 local $runner_options->{out_callback} = \$out if ($out_callback);
45 4 100       29 local $runner_options->{err_callback} = \$err if ($err_callback);
46 4         31 my $harness =
47             IPC::Run::start( [ 'sh', '-c', $command ], $self->_run_options($runner_options) );
48              
49 4         23002 my ( $last_part_out, $last_part_err ) = ( '', '' );
50 4         14 eval {
51 4         31 while ( $harness->pump() ) {
52 11 100       2030943 if ($out_callback) {
53 8         93 my @lines = split( /\r?\n/, $last_part_out . $out, -1 );
54 8   100     54 $last_part_out = pop(@lines) || '';
55 8         50 &$out_callback($_) foreach (@lines);
56 7         104 $out = '';
57             }
58              
59 10 100       31 if ($err_callback) {
60 7         51 my @lines = split( /\r?\n/, $last_part_err . $err, -1 );
61 7   100     45 $last_part_err = pop(@lines) || '';
62 7         30 &$err_callback($_) foreach (@lines);
63 7         45 $err = '';
64             }
65             }
66              
67 3 100 66     2907 &$out_callback($last_part_out)
68             if ( $out_callback && length($last_part_out) > 0 );
69 3 100 66     40 &$err_callback($last_part_err)
70             if ( $err_callback && length($last_part_err) > 0 );
71             };
72 4         20 my $error = $@;
73 4 100       24 if ($error) {
74 1         23 $logger->debugf( "callback exited early: %s", $error );
75 1         26 $harness->kill_kill();
76 1         11367 die($error);
77             }
78             }
79             else {
80 22         157 IPC::Run::run( [ 'sh', '-c', $command ], $self->_run_options($runner_options) );
81             }
82 25         234323 return $? >> 8;
83             }
84              
85             1;
86              
87             __END__