| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Command::Run; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = "1.00"; |
|
4
|
|
|
|
|
|
|
|
|
5
|
28
|
|
|
28
|
|
2633854
|
use v5.14; |
|
|
28
|
|
|
|
|
91
|
|
|
6
|
28
|
|
|
28
|
|
143
|
use warnings; |
|
|
28
|
|
|
|
|
189
|
|
|
|
28
|
|
|
|
|
1683
|
|
|
7
|
28
|
|
|
28
|
|
10374
|
use utf8; |
|
|
28
|
|
|
|
|
5930
|
|
|
|
28
|
|
|
|
|
157
|
|
|
8
|
28
|
|
|
28
|
|
781
|
use Carp; |
|
|
28
|
|
|
|
|
62
|
|
|
|
28
|
|
|
|
|
1712
|
|
|
9
|
28
|
|
|
28
|
|
138
|
use Fcntl; |
|
|
28
|
|
|
|
|
36
|
|
|
|
28
|
|
|
|
|
5712
|
|
|
10
|
28
|
|
|
28
|
|
13338
|
use IO::File; |
|
|
28
|
|
|
|
|
242118
|
|
|
|
28
|
|
|
|
|
5433
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
28
|
|
|
28
|
|
12076
|
use parent 'Command::Run::Tmpfile'; |
|
|
28
|
|
|
|
|
7473
|
|
|
|
28
|
|
|
|
|
166
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our $debug; |
|
15
|
|
|
|
|
|
|
sub debug { |
|
16
|
0
|
|
|
0
|
0
|
0
|
my $obj = shift; |
|
17
|
0
|
0
|
|
|
|
0
|
@_ ? $debug = shift : $debug; |
|
18
|
|
|
|
|
|
|
} |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub code_name { |
|
21
|
69
|
|
|
69
|
0
|
147
|
my $code = shift; |
|
22
|
69
|
|
|
|
|
788
|
require B; |
|
23
|
69
|
|
|
|
|
876
|
my $cv = B::svref_2object($code); |
|
24
|
69
|
50
|
|
|
|
1821
|
return if $cv->GV->isa('B::SPECIAL'); |
|
25
|
69
|
|
|
|
|
885
|
$cv->GV->NAME; |
|
26
|
|
|
|
|
|
|
} |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
my %default_option = ( |
|
29
|
|
|
|
|
|
|
stderr => undef, # undef: pass-through, 'redirect': merge to stdout, 'capture': separate capture |
|
30
|
|
|
|
|
|
|
); |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub new { |
|
33
|
190
|
|
|
190
|
1
|
4547435
|
my $class = shift; |
|
34
|
190
|
|
|
|
|
1840
|
my $obj = $class->SUPER::new; |
|
35
|
190
|
|
|
|
|
1082
|
$obj->{OPTION} = { %default_option }; |
|
36
|
190
|
|
|
|
|
473
|
$obj->{RESULT} = {}; |
|
37
|
190
|
100
|
|
|
|
1109
|
$obj->configure(@_) if @_; |
|
38
|
190
|
|
|
|
|
2288
|
$obj; |
|
39
|
|
|
|
|
|
|
} |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
sub configure { |
|
42
|
163
|
|
|
163
|
0
|
228
|
my $obj = shift; |
|
43
|
163
|
|
|
|
|
795
|
my %args = @_; |
|
44
|
163
|
|
|
|
|
663
|
for my $key (keys %args) { |
|
45
|
274
|
|
|
|
|
446
|
my $val = $args{$key}; |
|
46
|
274
|
100
|
|
|
|
1006
|
if ($key eq 'command') { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
47
|
134
|
50
|
|
|
|
611
|
$obj->command(ref $val eq 'ARRAY' ? @$val : $val); |
|
48
|
|
|
|
|
|
|
} elsif ($key eq 'stdin') { |
|
49
|
31
|
|
|
|
|
215
|
$obj->_set_stdin($val); |
|
50
|
|
|
|
|
|
|
} elsif ($key eq 'stdout') { |
|
51
|
17
|
|
|
|
|
60
|
$obj->{STDOUT_REF} = $val; |
|
52
|
|
|
|
|
|
|
} elsif ($key eq 'stderr') { |
|
53
|
33
|
100
|
|
|
|
137
|
if (ref $val eq 'SCALAR') { |
|
54
|
6
|
|
|
|
|
33
|
$obj->{STDERR_REF} = $val; |
|
55
|
6
|
|
|
|
|
36
|
$obj->option(stderr => 'capture'); |
|
56
|
|
|
|
|
|
|
} else { |
|
57
|
27
|
|
|
|
|
166
|
$obj->option(stderr => $val); |
|
58
|
|
|
|
|
|
|
} |
|
59
|
|
|
|
|
|
|
} else { |
|
60
|
59
|
|
|
|
|
94
|
$obj->option($key => $val); |
|
61
|
|
|
|
|
|
|
} |
|
62
|
|
|
|
|
|
|
} |
|
63
|
163
|
|
|
|
|
624
|
$obj; |
|
64
|
|
|
|
|
|
|
} |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub command { |
|
67
|
385
|
|
|
385
|
1
|
8962
|
my $obj = shift; |
|
68
|
385
|
100
|
|
|
|
763
|
if (@_) { |
|
69
|
190
|
|
|
|
|
725
|
$obj->{COMMAND} = [ @_ ]; |
|
70
|
190
|
|
|
|
|
2896
|
$obj; |
|
71
|
|
|
|
|
|
|
} else { |
|
72
|
195
|
|
50
|
|
|
220
|
@{$obj->{COMMAND} // []}; |
|
|
195
|
|
|
|
|
868
|
|
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub option { |
|
77
|
92
|
|
|
92
|
0
|
122
|
my $obj = shift; |
|
78
|
92
|
50
|
|
|
|
200
|
if (@_ == 1) { |
|
79
|
0
|
|
|
|
|
0
|
return $obj->{OPTION}->{+shift}; |
|
80
|
|
|
|
|
|
|
} else { |
|
81
|
92
|
|
|
|
|
353
|
while (my($k, $v) = splice @_, 0, 2) { |
|
82
|
92
|
|
|
|
|
305
|
$obj->{OPTION}->{$k} = $v; |
|
83
|
|
|
|
|
|
|
} |
|
84
|
92
|
|
|
|
|
194
|
return $obj; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub run { |
|
89
|
166
|
|
|
166
|
1
|
3629
|
my $obj = shift; |
|
90
|
166
|
|
|
|
|
622
|
$obj->update(@_); |
|
91
|
144
|
100
|
|
|
|
596
|
if (my $ref = $obj->{STDOUT_REF}) { |
|
92
|
13
|
|
|
|
|
152
|
$$ref = $obj->data; |
|
93
|
|
|
|
|
|
|
} |
|
94
|
144
|
100
|
|
|
|
503
|
if (my $ref = $obj->{STDERR_REF}) { |
|
95
|
5
|
|
|
|
|
41
|
$$ref = $obj->error; |
|
96
|
|
|
|
|
|
|
} |
|
97
|
144
|
|
|
|
|
555
|
return $obj->result; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub update { |
|
101
|
28
|
|
|
28
|
|
29862
|
use Time::localtime; |
|
|
28
|
|
|
|
|
119922
|
|
|
|
28
|
|
|
|
|
56464
|
|
|
102
|
175
|
|
|
175
|
1
|
319
|
my $obj = shift; |
|
103
|
175
|
|
|
|
|
360
|
my @command = $obj->command; |
|
104
|
175
|
50
|
|
|
|
347
|
if (@command) { |
|
105
|
175
|
|
|
|
|
699
|
$obj->{RESULT} = $obj->execute(\@command, @_); |
|
106
|
|
|
|
|
|
|
# Store stdout in temp file for path access |
|
107
|
152
|
|
|
|
|
2412
|
my $fh = $obj->fh; |
|
108
|
152
|
50
|
|
|
|
1969
|
$fh->seek(0, 0) or die "seek: $!\n"; |
|
109
|
152
|
50
|
|
|
|
3482
|
$fh->truncate(0) or die "truncate: $!\n"; |
|
110
|
152
|
|
50
|
|
|
8405
|
$fh->print($obj->{RESULT}->{data} // ''); |
|
111
|
152
|
|
|
|
|
7596
|
$fh->flush; |
|
112
|
152
|
50
|
|
|
|
786
|
$fh->seek(0, 0) or die "seek: $!\n"; |
|
113
|
|
|
|
|
|
|
} |
|
114
|
152
|
|
|
|
|
2374
|
$obj->date(ctime()); |
|
115
|
152
|
|
|
|
|
826
|
$obj; |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub result { |
|
119
|
148
|
|
|
148
|
1
|
274
|
my $obj = shift; |
|
120
|
148
|
|
|
|
|
1592
|
$obj->{RESULT}; |
|
121
|
|
|
|
|
|
|
} |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
sub execute { |
|
124
|
175
|
|
|
175
|
0
|
237
|
my $obj = shift; |
|
125
|
175
|
|
|
|
|
238
|
my $command = shift; |
|
126
|
175
|
|
|
|
|
223
|
my %opt = (%{$obj->{OPTION}}, @_); |
|
|
175
|
|
|
|
|
614
|
|
|
127
|
175
|
50
|
|
|
|
589
|
my @command = ref $command eq 'ARRAY' ? @$command : ($command); |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# Use nofork path for code references when requested |
|
130
|
175
|
100
|
100
|
|
|
681
|
if ($opt{nofork} and ref $command[0] eq 'CODE') { |
|
131
|
61
|
|
|
|
|
162
|
return $obj->_execute_nofork(\@command, %opt); |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
|
|
134
|
114
|
|
100
|
|
|
760
|
my $stderr = $opt{stderr} // ''; |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# Create pipes for stdout and stderr |
|
137
|
114
|
50
|
|
|
|
3818
|
pipe(my $stdout_r, my $stdout_w) or die "pipe: $!\n"; |
|
138
|
114
|
100
|
50
|
|
|
737
|
pipe(my $stderr_r, my $stderr_w) or die "pipe: $!\n" if $stderr eq 'capture'; |
|
139
|
|
|
|
|
|
|
|
|
140
|
114
|
|
50
|
|
|
158376
|
my $pid = fork // die "fork: $!\n"; |
|
141
|
114
|
100
|
|
|
|
2875
|
if ($pid == 0) { |
|
142
|
|
|
|
|
|
|
# Child process |
|
143
|
23
|
|
|
|
|
3428
|
close $stdout_r; |
|
144
|
23
|
100
|
|
|
|
1665
|
close $stderr_r if $stderr eq 'capture'; |
|
145
|
|
|
|
|
|
|
|
|
146
|
23
|
100
|
|
|
|
1722
|
if (exists $opt{stdin}) { |
|
|
|
100
|
|
|
|
|
|
|
147
|
1
|
50
|
|
|
|
619
|
my $tmp = new_tmpfile IO::File or die "tmpfile: $!\n"; |
|
148
|
1
|
|
|
|
|
121
|
binmode $tmp, ':encoding(utf8)'; |
|
149
|
1
|
|
|
|
|
250
|
$tmp->print($opt{stdin}); |
|
150
|
1
|
50
|
|
|
|
89
|
$tmp->seek(0, 0) or die "seek: $!\n"; |
|
151
|
1
|
50
|
|
|
|
184
|
open STDIN, '<&', $tmp or die "dup: $!\n"; |
|
152
|
1
|
|
|
|
|
120
|
binmode STDIN, ':encoding(utf8)'; |
|
153
|
|
|
|
|
|
|
} elsif (my $input = $obj->{INPUT}) { |
|
154
|
5
|
50
|
|
|
|
553
|
open STDIN, "<&=", $input->fileno or die "open: $!\n"; |
|
155
|
5
|
|
|
|
|
868
|
binmode STDIN, ':encoding(utf8)'; |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
|
|
158
|
23
|
50
|
|
|
|
2290
|
open STDOUT, ">&=", $stdout_w->fileno or die "open stdout: $!\n"; |
|
159
|
23
|
100
|
|
|
|
3014
|
if ($stderr eq 'redirect') { |
|
|
|
100
|
|
|
|
|
|
|
160
|
3
|
50
|
|
|
|
156
|
open STDERR, ">&STDOUT" or die "open stderr: $!\n"; |
|
161
|
|
|
|
|
|
|
} elsif ($stderr eq 'capture') { |
|
162
|
4
|
50
|
|
|
|
95
|
open STDERR, ">&=", $stderr_w->fileno or die "open stderr: $!\n"; |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
# else: stderr passes through to terminal |
|
165
|
|
|
|
|
|
|
|
|
166
|
23
|
100
|
|
|
|
1026
|
if (ref $command[0] eq 'CODE') { |
|
167
|
8
|
|
|
|
|
240
|
my $code = shift @command; |
|
168
|
8
|
|
|
|
|
166
|
@ARGV = @command; |
|
169
|
8
|
50
|
|
|
|
377
|
if (my $name = code_name($code)) { |
|
170
|
8
|
|
|
|
|
319
|
$0 = $name; |
|
171
|
|
|
|
|
|
|
} |
|
172
|
8
|
|
|
|
|
269
|
$code->(@command); |
|
173
|
8
|
|
|
|
|
7365
|
exit 0; |
|
174
|
|
|
|
|
|
|
} |
|
175
|
15
|
|
|
|
|
0
|
exec @command; |
|
176
|
0
|
|
|
|
|
0
|
die "exec: $@\n"; |
|
177
|
|
|
|
|
|
|
} |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# Parent process |
|
180
|
91
|
|
|
|
|
6329
|
close $stdout_w; |
|
181
|
91
|
100
|
|
|
|
1333
|
close $stderr_w if $stderr eq 'capture'; |
|
182
|
|
|
|
|
|
|
|
|
183
|
91
|
|
|
|
|
18747
|
binmode $stdout_r, ':encoding(utf8)'; |
|
184
|
91
|
100
|
|
|
|
53531
|
binmode $stderr_r, ':encoding(utf8)' if $stderr eq 'capture'; |
|
185
|
|
|
|
|
|
|
|
|
186
|
91
|
|
|
|
|
928
|
my $stdout = do { local $/; <$stdout_r> }; |
|
|
91
|
|
|
|
|
3388
|
|
|
|
91
|
|
|
|
|
18219291
|
|
|
187
|
91
|
100
|
|
|
|
10643059
|
my $stderr_out = $stderr eq 'capture' ? do { local $/; <$stderr_r> } : ''; |
|
|
7
|
|
|
|
|
188
|
|
|
|
7
|
|
|
|
|
421
|
|
|
188
|
|
|
|
|
|
|
|
|
189
|
91
|
|
|
|
|
3498
|
close $stdout_r; |
|
190
|
91
|
100
|
|
|
|
711
|
close $stderr_r if $stderr eq 'capture'; |
|
191
|
|
|
|
|
|
|
|
|
192
|
91
|
|
|
|
|
2453
|
waitpid $pid, 0; |
|
193
|
91
|
|
|
|
|
936
|
my $result = $?; |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
return { |
|
196
|
91
|
|
|
|
|
6263
|
result => $result, |
|
197
|
|
|
|
|
|
|
data => $stdout, |
|
198
|
|
|
|
|
|
|
error => $stderr_out, |
|
199
|
|
|
|
|
|
|
pid => $pid, |
|
200
|
|
|
|
|
|
|
}; |
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
sub _tmpfile { |
|
204
|
114
|
|
|
114
|
|
315
|
my ($obj, $key, %opt) = @_; |
|
205
|
114
|
100
|
|
|
|
269
|
$key .= '_RAW' if $opt{raw}; |
|
206
|
114
|
|
66
|
|
|
497
|
my $fh = $obj->{$key} //= do { |
|
207
|
104
|
50
|
|
|
|
23270
|
my $f = new_tmpfile IO::File or die "tmpfile: $!\n"; |
|
208
|
104
|
100
|
|
|
|
1304
|
binmode $f, $opt{raw} ? ':utf8' : ':encoding(utf8)'; |
|
209
|
104
|
|
|
|
|
3294
|
$f; |
|
210
|
|
|
|
|
|
|
}; |
|
211
|
114
|
50
|
|
|
|
513
|
$fh->seek(0, 0) or die "seek: $!\n"; |
|
212
|
114
|
50
|
|
|
|
1182
|
$fh->truncate(0) or die "truncate: $!\n"; |
|
213
|
114
|
|
|
|
|
3772
|
$fh; |
|
214
|
|
|
|
|
|
|
} |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub _execute_nofork { |
|
217
|
61
|
|
|
61
|
|
60
|
my $obj = shift; |
|
218
|
61
|
|
|
|
|
53
|
my $command = shift; |
|
219
|
61
|
|
|
|
|
112
|
my %opt = @_; |
|
220
|
61
|
|
|
|
|
73
|
my @command = @$command; |
|
221
|
61
|
|
100
|
|
|
165
|
my $stderr_mode = $opt{stderr} // ''; |
|
222
|
61
|
|
|
|
|
72
|
my $raw = $opt{raw}; |
|
223
|
|
|
|
|
|
|
|
|
224
|
61
|
|
|
|
|
75
|
my $code = shift @command; |
|
225
|
|
|
|
|
|
|
|
|
226
|
61
|
|
|
|
|
110
|
my $tmp_stdout = $obj->_tmpfile('NOFORK_STDOUT', raw => $raw); |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# Save and redirect STDOUT (always needed) |
|
229
|
61
|
50
|
|
|
|
949
|
open my $save_stdout, '>&', \*STDOUT or die "dup STDOUT: $!\n"; |
|
230
|
61
|
50
|
|
|
|
12233
|
open STDOUT, '>&', $tmp_stdout or die "redirect STDOUT: $!\n"; |
|
231
|
61
|
100
|
|
|
|
2200
|
binmode STDOUT, $raw ? ':utf8' : ':encoding(utf8)'; |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# Handle STDERR — only save/redirect when needed |
|
234
|
61
|
|
|
|
|
1020
|
my ($save_stderr, $tmp_stderr); |
|
235
|
61
|
100
|
|
|
|
146
|
if ($stderr_mode eq 'redirect') { |
|
|
|
100
|
|
|
|
|
|
|
236
|
3
|
50
|
|
|
|
42
|
open $save_stderr, '>&', \*STDERR or die "dup STDERR: $!\n"; |
|
237
|
3
|
50
|
|
|
|
21
|
open STDERR, '>&', \*STDOUT or die "redirect STDERR: $!\n"; |
|
238
|
|
|
|
|
|
|
} elsif ($stderr_mode eq 'capture') { |
|
239
|
9
|
|
|
|
|
27
|
$tmp_stderr = $obj->_tmpfile('NOFORK_STDERR', raw => $raw); |
|
240
|
9
|
50
|
|
|
|
126
|
open $save_stderr, '>&', \*STDERR or die "dup STDERR: $!\n"; |
|
241
|
9
|
50
|
|
|
|
66
|
open STDERR, '>&', $tmp_stderr or die "redirect STDERR: $!\n"; |
|
242
|
|
|
|
|
|
|
} |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
# Handle STDIN — only save/redirect when needed |
|
245
|
61
|
|
|
|
|
650
|
my $save_stdin; |
|
246
|
61
|
100
|
|
|
|
175
|
if (exists $opt{stdin}) { |
|
|
|
100
|
|
|
|
|
|
|
247
|
13
|
|
|
|
|
39
|
my $tmp_stdin = $obj->_tmpfile('NOFORK_STDIN', raw => $raw); |
|
248
|
13
|
|
|
|
|
48
|
$tmp_stdin->print($opt{stdin}); |
|
249
|
13
|
50
|
|
|
|
105
|
$tmp_stdin->seek(0, 0) or die "seek: $!\n"; |
|
250
|
13
|
50
|
|
|
|
642
|
open $save_stdin, '<&', \*STDIN or die "dup STDIN: $!\n"; |
|
251
|
13
|
50
|
|
|
|
1099
|
open STDIN, '<&', $tmp_stdin or die "redirect STDIN: $!\n"; |
|
252
|
13
|
100
|
|
|
|
443
|
binmode STDIN, $raw ? ':utf8' : ':encoding(utf8)'; |
|
253
|
|
|
|
|
|
|
} elsif (my $input = $obj->{INPUT}) { |
|
254
|
3
|
50
|
|
|
|
9
|
$input->seek(0, 0) or die "seek: $!\n"; |
|
255
|
3
|
50
|
|
|
|
60
|
open $save_stdin, '<&', \*STDIN or die "dup STDIN: $!\n"; |
|
256
|
3
|
50
|
|
|
|
12
|
open STDIN, '<&', $input->fileno or die "redirect STDIN: $!\n"; |
|
257
|
3
|
50
|
|
|
|
63
|
binmode STDIN, $raw ? ':utf8' : ':encoding(utf8)'; |
|
258
|
|
|
|
|
|
|
} |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
# Set global state |
|
261
|
61
|
|
|
|
|
262
|
local $_; |
|
262
|
61
|
|
|
|
|
123
|
local @ARGV = @command; |
|
263
|
61
|
|
|
|
|
63
|
my $orig_0; |
|
264
|
61
|
50
|
|
|
|
175
|
if (my $name = code_name($code)) { |
|
265
|
61
|
|
|
|
|
120
|
$orig_0 = $0; |
|
266
|
61
|
|
|
|
|
371
|
$0 = $name; |
|
267
|
|
|
|
|
|
|
} |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# Execute |
|
270
|
61
|
|
|
|
|
87
|
my $result = 0; |
|
271
|
61
|
|
|
|
|
64
|
eval { $code->(@command) }; |
|
|
61
|
|
|
|
|
140
|
|
|
272
|
61
|
100
|
|
|
|
3361
|
if ($@) { |
|
273
|
6
|
|
|
|
|
9
|
$result = -1; |
|
274
|
|
|
|
|
|
|
} |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
# Flush and restore — only what was redirected |
|
277
|
61
|
|
|
|
|
283
|
STDOUT->flush; |
|
278
|
61
|
50
|
|
|
|
838
|
open STDOUT, '>&', $save_stdout or die "restore STDOUT: $!\n"; |
|
279
|
61
|
100
|
|
|
|
12052
|
if ($save_stderr) { |
|
280
|
12
|
|
|
|
|
33
|
STDERR->flush; |
|
281
|
12
|
50
|
|
|
|
147
|
open STDERR, '>&', $save_stderr or die "restore STDERR: $!\n"; |
|
282
|
|
|
|
|
|
|
} |
|
283
|
61
|
100
|
|
|
|
89
|
if ($save_stdin) { |
|
284
|
16
|
50
|
|
|
|
141
|
open STDIN, '<&', $save_stdin or die "restore STDIN: $!\n"; |
|
285
|
|
|
|
|
|
|
} |
|
286
|
61
|
50
|
|
|
|
962
|
if (defined $orig_0) { |
|
287
|
61
|
|
|
|
|
252
|
$0 = $orig_0; |
|
288
|
|
|
|
|
|
|
} |
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# Read captured output from tmpfiles |
|
291
|
61
|
50
|
|
|
|
194
|
$tmp_stdout->seek(0, 0) or die "seek: $!\n"; |
|
292
|
61
|
|
|
|
|
436
|
my $stdout_data = do { local $/; <$tmp_stdout> }; |
|
|
61
|
|
|
|
|
171
|
|
|
|
61
|
|
|
|
|
1441
|
|
|
293
|
|
|
|
|
|
|
|
|
294
|
61
|
|
|
|
|
547
|
my $stderr_data = ''; |
|
295
|
61
|
100
|
|
|
|
92
|
if ($tmp_stderr) { |
|
296
|
9
|
50
|
|
|
|
15
|
$tmp_stderr->seek(0, 0) or die "seek: $!\n"; |
|
297
|
9
|
|
|
|
|
57
|
$stderr_data = do { local $/; <$tmp_stderr> }; |
|
|
9
|
|
|
|
|
18
|
|
|
|
9
|
|
|
|
|
165
|
|
|
298
|
|
|
|
|
|
|
} |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
return { |
|
301
|
61
|
|
|
|
|
1021
|
result => $result, |
|
302
|
|
|
|
|
|
|
data => $stdout_data, |
|
303
|
|
|
|
|
|
|
error => $stderr_data, |
|
304
|
|
|
|
|
|
|
}; |
|
305
|
|
|
|
|
|
|
} |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
sub data { |
|
308
|
25
|
|
|
25
|
1
|
848
|
my $obj = shift; |
|
309
|
25
|
50
|
|
|
|
152
|
if (@_) { |
|
310
|
0
|
|
|
|
|
0
|
my $data = shift; |
|
311
|
0
|
|
|
|
|
0
|
$obj->{RESULT}->{data} = $data; |
|
312
|
0
|
|
|
|
|
0
|
my $fh = $obj->fh; |
|
313
|
0
|
0
|
|
|
|
0
|
$fh->seek(0, 0) or die "seek: $!\n"; |
|
314
|
0
|
0
|
|
|
|
0
|
$fh->truncate(0) or die "truncate: $!\n"; |
|
315
|
0
|
|
|
|
|
0
|
$fh->print($data); |
|
316
|
0
|
|
|
|
|
0
|
$fh->flush; |
|
317
|
0
|
0
|
|
|
|
0
|
$fh->seek(0, 0) or die "seek: $!\n"; |
|
318
|
0
|
|
|
|
|
0
|
return $obj; |
|
319
|
|
|
|
|
|
|
} |
|
320
|
25
|
|
|
|
|
388
|
$obj->{RESULT}->{data}; |
|
321
|
|
|
|
|
|
|
} |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
sub error { |
|
324
|
9
|
|
|
9
|
1
|
27
|
my $obj = shift; |
|
325
|
9
|
|
|
|
|
40
|
$obj->{RESULT}->{error}; |
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
sub date { |
|
329
|
153
|
|
|
153
|
1
|
6149
|
my $obj = shift; |
|
330
|
153
|
100
|
|
|
|
1203
|
@_ ? $obj->{DATE} = shift : $obj->{DATE}; |
|
331
|
|
|
|
|
|
|
} |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
sub _set_stdin { |
|
334
|
31
|
|
|
31
|
|
101
|
my $obj = shift; |
|
335
|
31
|
|
|
|
|
70
|
my $data = shift; |
|
336
|
31
|
|
|
|
|
145
|
my $input = $obj->_tmpfile('INPUT'); |
|
337
|
31
|
50
|
|
|
|
200
|
$input->fcntl(F_SETFD, 0) or die "fcntl F_SETFD: $!\n"; |
|
338
|
31
|
|
|
|
|
409
|
$input->print($data); |
|
339
|
31
|
50
|
|
|
|
298
|
$input->seek(0, 0) or die "seek: $!\n"; |
|
340
|
31
|
|
|
|
|
1556
|
$obj; |
|
341
|
|
|
|
|
|
|
} |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
sub with { |
|
344
|
29
|
|
|
29
|
1
|
75
|
my $obj = shift; |
|
345
|
29
|
|
|
|
|
130
|
$obj->configure(@_); |
|
346
|
|
|
|
|
|
|
} |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
1; |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
__END__ |