File Coverage

lib/Git/Background/Future.pm
Criterion Covered Total %
statement 81 85 95.2
branch 18 20 90.0
condition 13 17 76.4
subroutine 16 17 94.1
pod 11 11 100.0
total 139 150 92.6


line stmt bran cond sub pod time code
1             # vim: ts=4 sts=4 sw=4 et: syntax=perl
2             #
3             # Copyright (c) 2021-2023 Sven Kirmess
4             #
5             # Permission to use, copy, modify, and distribute this software for any
6             # purpose with or without fee is hereby granted, provided that the above
7             # copyright notice and this permission notice appear in all copies.
8             #
9             # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10             # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11             # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12             # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13             # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14             # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15             # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16              
17 14     14   106264 use 5.010;
  14         61  
18 14     14   75 use strict;
  14         39  
  14         394  
19 14     14   74 use warnings;
  14         41  
  14         864  
20              
21             package Git::Background::Future;
22              
23             our $VERSION = '0.007_02';
24              
25 14     14   8722 use Future 0.49;
  14         175867  
  14         449  
26 14     14   6367 use parent 'Future';
  14         4235  
  14         90  
27              
28             sub new {
29 29     29 1 2328 my ( $class, $run ) = @_;
30              
31 29         644 my $self = $class->SUPER::new;
32 29         1067 $self->set_udata( '_run', $run );
33 29         2508 return $self;
34             }
35              
36             sub await {
37 26     26 1 32239 my ($self) = @_;
38              
39 26         204 my $run = $self->udata('_run');
40              
41 26 100       422 return $self if !defined $run;
42              
43 23         190 $self->set_udata( '_run', undef );
44              
45 23         267 my $e;
46             my $ok;
47             {
48 23         64 local $@; ## no critic (Variables::RequireInitializationForLocalVars)
  23         53  
49 23         81 $ok = eval {
50              
51             # prevent the "(in cleanup) process is already terminated" message
52 23         132 $run->{_proc}->autoterminate(0);
53              
54             # wait for the process to finish
55 23         519 $run->{_proc}->wait;
56              
57 21         381549 1;
58             };
59              
60 23 100       257 if ( !$ok ) {
61              
62             # The Future->fail exception must be true
63 2   100     123 $e = qq{$@} || 'Failed to wait on Git process with Proc::Background';
64             }
65             }
66 23 100       136 return $self->fail( $e, 'Proc::Background' ) if !$ok;
67              
68 21         80 my $stdout_file = $run->{_stdout};
69 21         62 my $stderr_file = $run->{_stderr};
70 21         63 my @stdout;
71             my @stderr;
72             {
73 21         50 local $@; ## no critic (Variables::RequireInitializationForLocalVars)
  21         80  
74 21         65 $ok = eval {
75 21         119 $e = 'Cannot read stdout';
76 21         584 @stdout = $stdout_file->lines_utf8( { chomp => 1 } );
77              
78 20         19977 $e = 'Cannot read stderr';
79 20         167 @stderr = $stderr_file->lines_utf8( { chomp => 1 } );
80              
81 19         4520 1;
82             };
83              
84 21 100       1291 if ( !$ok ) {
85 2 50 33     34 if ( defined $@ && $@ ne q{} ) {
86 2         13 $e .= ": $@";
87             }
88             }
89             }
90 21 100       124 return $self->fail( $e, 'Path::Tiny' ) if !$ok;
91              
92             # get exit code and signal from git process
93 19         211 my $exit_code = $run->{_proc}->exit_code;
94              
95 19         210 my @result = (
96             \@stdout,
97             \@stderr,
98             $exit_code,
99             $stdout_file,
100             $stderr_file,
101             );
102              
103             # git died by a signal
104 19 100       104 return $self->fail( 'Git was terminated by a signal', 'Proc::Background', @result ) if $run->{_proc}->exit_signal;
105              
106 18 100 100     454 if (
      100        
      100        
107             # fatal error
108             ( $exit_code == 128 )
109              
110             # usage error
111             || ( $exit_code == 129 )
112              
113             # non-zero return code
114             || ( $exit_code && $run->{_fatal} )
115             )
116             {
117 8         83 my $message = join "\n", @stderr;
118 8 100       50 if ( !length $message ) {
119 2         40 $message = "git exited with fatal exit code $exit_code but had no output to stderr";
120             }
121              
122             # $run goes out of scope and the file handles and the proc object are freed
123 8         129 return $self->fail( $message, 'git', @result );
124             }
125              
126             # $run goes out of scope and the file handles and the proc object are freed
127 10         172 return $self->done(@result);
128             }
129              
130             sub exit_code {
131 1     1 1 643 my ($self) = @_;
132 1         11 return ( $self->get )[2];
133             }
134              
135             sub is_done {
136 17     17 1 15322 my ($self) = @_;
137 17         145 $self->_await_if_git_is_done;
138 17         148 return $self->SUPER::is_done;
139             }
140              
141             sub is_failed {
142 17     17 1 6040 my ($self) = @_;
143 17         79 $self->_await_if_git_is_done;
144 17         184 return $self->SUPER::is_failed;
145             }
146              
147             sub is_ready {
148 17     17 1 9390 my ($self) = @_;
149 17         93 $self->_await_if_git_is_done;
150 17         98 return $self->SUPER::is_ready;
151             }
152              
153             sub path_stderr {
154 1     1 1 576 my ($self) = @_;
155 1         10 return ( $self->get )[4];
156             }
157              
158             sub path_stdout {
159 1     1 1 1049 my ($self) = @_;
160 1         22 return ( $self->get )[3];
161             }
162              
163             sub state { ## no critic (Subroutines::ProhibitBuiltinHomonyms)
164 0     0 1 0 my ($self) = @_;
165 0         0 $self->_await_if_git_is_done;
166 0         0 return $self->SUPER::state;
167             }
168              
169             sub stderr {
170 1     1 1 808 my ($self) = @_;
171 1         9 return @{ ( $self->get )[1] };
  1         6  
172             }
173              
174             sub stdout {
175 5     5 1 465 my ($self) = @_;
176 5         21 return @{ ( $self->get )[0] };
  5         55  
177             }
178              
179             sub _await_if_git_is_done {
180 51     51   130 my ($self) = @_;
181              
182 51         204 my $run = $self->udata('_run');
183 51 50 33     589 if ( defined $run && !$run->{_proc}->alive ) {
184 0         0 $self->await;
185             }
186              
187 51         112 return;
188             }
189              
190             1;
191              
192             __END__