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   946 use strict;
  7         23  
  7         229  
2 7     7   33 use warnings;
  7         21  
  7         409  
3              
4             package Footprintless::CommandRunner::IPCRun;
5             $Footprintless::CommandRunner::IPCRun::VERSION = '1.28';
6             # ABSTRACT: An implementation of Footprintless::CommandRunner using IPC::Run
7             # PODNAME: Footprintless::CommandRunner::IPCRun
8              
9 7     7   49 use parent qw(Footprintless::CommandRunner);
  7         21  
  7         73  
10              
11 7     7   396 use Carp;
  7         29  
  7         497  
12 7     7   5676 use IPC::Run;
  7         155754  
  7         270  
13 7     7   50 use Log::Any;
  7         13  
  7         58  
14              
15             my $logger = Log::Any->get_logger();
16              
17             sub _run_options {
18 26     26   77 my ( $self, $runner_options ) = @_;
19 26         46 my @timeout;
20 26 100       74 if ( $runner_options->{timeout} ) {
21 3         118 @timeout = ( IPC::Run::timeout( $runner_options->{timeout} ) );
22             }
23              
24 26   100     728 my $in = $runner_options->{in_handle} || \undef;
25             my $out =
26             $runner_options->{out_handle}
27             || $runner_options->{out_callback}
28 26   100     241 || \$self->{last_call}{stdout};
29             my $err =
30             $runner_options->{err_handle}
31             || $runner_options->{err_callback}
32 26   100     539 || \$self->{last_call}{stderr};
33              
34 26         145 return ( '<', $in, '>', $out, '2>', $err, @timeout );
35             }
36              
37             sub _run {
38 26     26   63 my ( $self, $command, $runner_options ) = @_;
39 26 100 100     211 if ( $runner_options->{out_callback} || $runner_options->{err_callback} ) {
40 4         7 my $out_callback = $runner_options->{out_callback};
41 4         7 my $err_callback = $runner_options->{err_callback};
42              
43 4         5 my ( $out, $err );
44 4 100       14 local $runner_options->{out_callback} = \$out if ($out_callback);
45 4 100       18 local $runner_options->{err_callback} = \$err if ($err_callback);
46 4         29 my $harness =
47             IPC::Run::start( [ 'sh', '-c', $command ], $self->_run_options($runner_options) );
48              
49 4         20679 my ( $last_part_out, $last_part_err ) = ( '', '' );
50 4         20 eval {
51 4         57 while ( $harness->pump() ) {
52 11 100       2020830 if ($out_callback) {
53 8         81 my @lines = split( /\r?\n/, $last_part_out . $out, -1 );
54 8   100     84 $last_part_out = pop(@lines) || '';
55 8         54 &$out_callback($_) foreach (@lines);
56 7         32 $out = '';
57             }
58              
59 10 100       33 if ($err_callback) {
60 7         40 my @lines = split( /\r?\n/, $last_part_err . $err, -1 );
61 7   100     47 $last_part_err = pop(@lines) || '';
62 7         28 &$err_callback($_) foreach (@lines);
63 7         65 $err = '';
64             }
65             }
66              
67 3 100 66     2566 &$out_callback($last_part_out)
68             if ( $out_callback && length($last_part_out) > 0 );
69 3 100 66     35 &$err_callback($last_part_err)
70             if ( $err_callback && length($last_part_err) > 0 );
71             };
72 4         23 my $error = $@;
73 4 100       35 if ($error) {
74 1         34 $logger->debugf( "callback exited early: %s", $error );
75 1         54 $harness->kill_kill();
76 1         11652 die($error);
77             }
78             }
79             else {
80 22         178 IPC::Run::run( [ 'sh', '-c', $command ], $self->_run_options($runner_options) );
81             }
82 25         218155 return $? >> 8;
83             }
84              
85             1;
86              
87             __END__