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   109741 use 5.010;
  14         64  
18 14     14   78 use strict;
  14         29  
  14         365  
19 14     14   80 use warnings;
  14         72  
  14         902  
20              
21             package Git::Background::Future;
22              
23             our $VERSION = '0.008';
24              
25 14     14   9445 use Future 0.49;
  14         182849  
  14         476  
26 14     14   6534 use parent 'Future';
  14         4178  
  14         97  
27              
28             sub new {
29 29     29 1 2867 my ( $class, $run ) = @_;
30              
31 29         688 my $self = $class->SUPER::new;
32 29         1162 $self->set_udata( '_run', $run );
33 29         2790 return $self;
34             }
35              
36             sub await {
37 26     26 1 30739 my ($self) = @_;
38              
39 26         293 my $run = $self->udata('_run');
40              
41 26 100       508 return $self if !defined $run;
42              
43 23         164 $self->set_udata( '_run', undef );
44              
45 23         199 my $e;
46             my $ok;
47             {
48 23         57 local $@; ## no critic (Variables::RequireInitializationForLocalVars)
  23         52  
49 23         67 $ok = eval {
50              
51             # prevent the "(in cleanup) process is already terminated" message
52 23         138 $run->{_proc}->autoterminate(0);
53              
54             # wait for the process to finish
55 23         540 $run->{_proc}->wait;
56              
57 21         426098 1;
58             };
59              
60 23 100       392 if ( !$ok ) {
61              
62             # The Future->fail exception must be true
63 2   100     49 $e = qq{$@} || 'Failed to wait on Git process with Proc::Background';
64             }
65             }
66 23 100       142 return $self->fail( $e, 'Proc::Background' ) if !$ok;
67              
68 21         84 my $stdout_file = $run->{_stdout};
69 21         57 my $stderr_file = $run->{_stderr};
70 21         94 my @stdout;
71             my @stderr;
72             {
73 21         52 local $@; ## no critic (Variables::RequireInitializationForLocalVars)
  21         63  
74 21         103 $ok = eval {
75 21         150 $e = 'Cannot read stdout';
76 21         645 @stdout = $stdout_file->lines_utf8( { chomp => 1 } );
77              
78 20         23400 $e = 'Cannot read stderr';
79 20         187 @stderr = $stderr_file->lines_utf8( { chomp => 1 } );
80              
81 19         5441 1;
82             };
83              
84 21 100       1451 if ( !$ok ) {
85 2 50 33     43 if ( defined $@ && $@ ne q{} ) {
86 2         15 $e .= ": $@";
87             }
88             }
89             }
90 21 100       156 return $self->fail( $e, 'Path::Tiny' ) if !$ok;
91              
92             # get exit code and signal from git process
93 19         251 my $exit_code = $run->{_proc}->exit_code;
94              
95 19         264 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       116 return $self->fail( 'Git was terminated by a signal', 'Proc::Background', @result ) if $run->{_proc}->exit_signal;
105              
106 18 100 100     773 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         98 my $message = join "\n", @stderr;
118 8 100       75 if ( !length $message ) {
119 2         50 $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         192 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         201 return $self->done(@result);
128             }
129              
130             sub exit_code {
131 1     1 1 705 my ($self) = @_;
132 1         11 return ( $self->get )[2];
133             }
134              
135             sub is_done {
136 17     17 1 30051 my ($self) = @_;
137 17         189 $self->_await_if_git_is_done;
138 17         170 return $self->SUPER::is_done;
139             }
140              
141             sub is_failed {
142 17     17 1 6418 my ($self) = @_;
143 17         79 $self->_await_if_git_is_done;
144 17         215 return $self->SUPER::is_failed;
145             }
146              
147             sub is_ready {
148 17     17 1 10131 my ($self) = @_;
149 17         120 $self->_await_if_git_is_done;
150 17         177 return $self->SUPER::is_ready;
151             }
152              
153             sub path_stderr {
154 1     1 1 929 my ($self) = @_;
155 1         17 return ( $self->get )[4];
156             }
157              
158             sub path_stdout {
159 1     1 1 1297 my ($self) = @_;
160 1         25 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 1194 my ($self) = @_;
171 1         6 return @{ ( $self->get )[1] };
  1         16  
172             }
173              
174             sub stdout {
175 5     5 1 592 my ($self) = @_;
176 5         17 return @{ ( $self->get )[0] };
  5         54  
177             }
178              
179             sub _await_if_git_is_done {
180 51     51   129 my ($self) = @_;
181              
182 51         230 my $run = $self->udata('_run');
183 51 50 33     544 if ( defined $run && !$run->{_proc}->alive ) {
184 0         0 $self->await;
185             }
186              
187 51         102 return;
188             }
189              
190             1;
191              
192             __END__