| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Command::Run; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = "0.9903"; |
|
4
|
|
|
|
|
|
|
|
|
5
|
28
|
|
|
28
|
|
3688530
|
use v5.14; |
|
|
28
|
|
|
|
|
128
|
|
|
6
|
28
|
|
|
28
|
|
201
|
use warnings; |
|
|
28
|
|
|
|
|
206
|
|
|
|
28
|
|
|
|
|
2324
|
|
|
7
|
28
|
|
|
28
|
|
23297
|
use utf8; |
|
|
28
|
|
|
|
|
9403
|
|
|
|
28
|
|
|
|
|
199
|
|
|
8
|
28
|
|
|
28
|
|
1288
|
use Carp; |
|
|
28
|
|
|
|
|
111
|
|
|
|
28
|
|
|
|
|
2477
|
|
|
9
|
28
|
|
|
28
|
|
218
|
use Fcntl; |
|
|
28
|
|
|
|
|
66
|
|
|
|
28
|
|
|
|
|
9257
|
|
|
10
|
28
|
|
|
28
|
|
20810
|
use IO::File; |
|
|
28
|
|
|
|
|
325286
|
|
|
|
28
|
|
|
|
|
7400
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
28
|
|
|
28
|
|
15391
|
use parent 'Command::Run::Tmpfile'; |
|
|
28
|
|
|
|
|
10225
|
|
|
|
28
|
|
|
|
|
219
|
|
|
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
|
165
|
my $code = shift; |
|
22
|
69
|
|
|
|
|
1685
|
require B; |
|
23
|
69
|
|
|
|
|
1220
|
my $cv = B::svref_2object($code); |
|
24
|
69
|
50
|
|
|
|
2183
|
return if $cv->GV->isa('B::SPECIAL'); |
|
25
|
69
|
|
|
|
|
1148
|
$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
|
6382876
|
my $class = shift; |
|
34
|
190
|
|
|
|
|
1851
|
my $obj = $class->SUPER::new; |
|
35
|
190
|
|
|
|
|
1530
|
$obj->{OPTION} = { %default_option }; |
|
36
|
190
|
|
|
|
|
631
|
$obj->{RESULT} = {}; |
|
37
|
190
|
100
|
|
|
|
1163
|
$obj->configure(@_) if @_; |
|
38
|
190
|
|
|
|
|
4006
|
$obj; |
|
39
|
|
|
|
|
|
|
} |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
sub configure { |
|
42
|
163
|
|
|
163
|
0
|
295
|
my $obj = shift; |
|
43
|
163
|
|
|
|
|
1039
|
my %args = @_; |
|
44
|
163
|
|
|
|
|
750
|
for my $key (keys %args) { |
|
45
|
274
|
|
|
|
|
553
|
my $val = $args{$key}; |
|
46
|
274
|
100
|
|
|
|
1383
|
if ($key eq 'command') { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
47
|
134
|
50
|
|
|
|
980
|
$obj->command(ref $val eq 'ARRAY' ? @$val : $val); |
|
48
|
|
|
|
|
|
|
} elsif ($key eq 'stdin') { |
|
49
|
31
|
|
|
|
|
382
|
$obj->_set_stdin($val); |
|
50
|
|
|
|
|
|
|
} elsif ($key eq 'stdout') { |
|
51
|
17
|
|
|
|
|
59
|
$obj->{STDOUT_REF} = $val; |
|
52
|
|
|
|
|
|
|
} elsif ($key eq 'stderr') { |
|
53
|
33
|
100
|
|
|
|
180
|
if (ref $val eq 'SCALAR') { |
|
54
|
6
|
|
|
|
|
18
|
$obj->{STDERR_REF} = $val; |
|
55
|
6
|
|
|
|
|
39
|
$obj->option(stderr => 'capture'); |
|
56
|
|
|
|
|
|
|
} else { |
|
57
|
27
|
|
|
|
|
207
|
$obj->option(stderr => $val); |
|
58
|
|
|
|
|
|
|
} |
|
59
|
|
|
|
|
|
|
} else { |
|
60
|
59
|
|
|
|
|
191
|
$obj->option($key => $val); |
|
61
|
|
|
|
|
|
|
} |
|
62
|
|
|
|
|
|
|
} |
|
63
|
163
|
|
|
|
|
621
|
$obj; |
|
64
|
|
|
|
|
|
|
} |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub command { |
|
67
|
385
|
|
|
385
|
1
|
12051
|
my $obj = shift; |
|
68
|
385
|
100
|
|
|
|
1082
|
if (@_) { |
|
69
|
190
|
|
|
|
|
1085
|
$obj->{COMMAND} = [ @_ ]; |
|
70
|
190
|
|
|
|
|
4002
|
$obj; |
|
71
|
|
|
|
|
|
|
} else { |
|
72
|
195
|
|
50
|
|
|
308
|
@{$obj->{COMMAND} // []}; |
|
|
195
|
|
|
|
|
1196
|
|
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub option { |
|
77
|
92
|
|
|
92
|
0
|
168
|
my $obj = shift; |
|
78
|
92
|
50
|
|
|
|
260
|
if (@_ == 1) { |
|
79
|
0
|
|
|
|
|
0
|
return $obj->{OPTION}->{+shift}; |
|
80
|
|
|
|
|
|
|
} else { |
|
81
|
92
|
|
|
|
|
516
|
while (my($k, $v) = splice @_, 0, 2) { |
|
82
|
92
|
|
|
|
|
402
|
$obj->{OPTION}->{$k} = $v; |
|
83
|
|
|
|
|
|
|
} |
|
84
|
92
|
|
|
|
|
324
|
return $obj; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub run { |
|
89
|
166
|
|
|
166
|
1
|
4569
|
my $obj = shift; |
|
90
|
166
|
|
|
|
|
714
|
$obj->update(@_); |
|
91
|
144
|
100
|
|
|
|
1382
|
if (my $ref = $obj->{STDOUT_REF}) { |
|
92
|
13
|
|
|
|
|
118
|
$$ref = $obj->data; |
|
93
|
|
|
|
|
|
|
} |
|
94
|
144
|
100
|
|
|
|
568
|
if (my $ref = $obj->{STDERR_REF}) { |
|
95
|
5
|
|
|
|
|
35
|
$$ref = $obj->error; |
|
96
|
|
|
|
|
|
|
} |
|
97
|
144
|
|
|
|
|
783
|
return $obj->result; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub update { |
|
101
|
28
|
|
|
28
|
|
43697
|
use Time::localtime; |
|
|
28
|
|
|
|
|
183292
|
|
|
|
28
|
|
|
|
|
90721
|
|
|
102
|
175
|
|
|
175
|
1
|
669
|
my $obj = shift; |
|
103
|
175
|
|
|
|
|
553
|
my @command = $obj->command; |
|
104
|
175
|
50
|
|
|
|
629
|
if (@command) { |
|
105
|
175
|
|
|
|
|
892
|
$obj->{RESULT} = $obj->execute(\@command, @_); |
|
106
|
|
|
|
|
|
|
# Store stdout in temp file for path access |
|
107
|
152
|
|
|
|
|
2726
|
my $fh = $obj->fh; |
|
108
|
152
|
50
|
|
|
|
2552
|
$fh->seek(0, 0) or die "seek: $!\n"; |
|
109
|
152
|
50
|
|
|
|
5072
|
$fh->truncate(0) or die "truncate: $!\n"; |
|
110
|
152
|
|
50
|
|
|
15875
|
$fh->print($obj->{RESULT}->{data} // ''); |
|
111
|
152
|
|
|
|
|
10405
|
$fh->flush; |
|
112
|
152
|
50
|
|
|
|
1156
|
$fh->seek(0, 0) or die "seek: $!\n"; |
|
113
|
|
|
|
|
|
|
} |
|
114
|
152
|
|
|
|
|
2796
|
$obj->date(ctime()); |
|
115
|
152
|
|
|
|
|
988
|
$obj; |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub result { |
|
119
|
148
|
|
|
148
|
1
|
389
|
my $obj = shift; |
|
120
|
148
|
|
|
|
|
1455
|
$obj->{RESULT}; |
|
121
|
|
|
|
|
|
|
} |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
sub execute { |
|
124
|
175
|
|
|
175
|
0
|
284
|
my $obj = shift; |
|
125
|
175
|
|
|
|
|
291
|
my $command = shift; |
|
126
|
175
|
|
|
|
|
295
|
my %opt = (%{$obj->{OPTION}}, @_); |
|
|
175
|
|
|
|
|
753
|
|
|
127
|
175
|
50
|
|
|
|
853
|
my @command = ref $command eq 'ARRAY' ? @$command : ($command); |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# Use nofork path for code references when requested |
|
130
|
175
|
100
|
100
|
|
|
829
|
if ($opt{nofork} and ref $command[0] eq 'CODE') { |
|
131
|
61
|
|
|
|
|
192
|
return $obj->_execute_nofork(\@command, %opt); |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
|
|
134
|
114
|
|
100
|
|
|
858
|
my $stderr = $opt{stderr} // ''; |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# Create pipes for stdout and stderr |
|
137
|
114
|
50
|
|
|
|
5290
|
pipe(my $stdout_r, my $stdout_w) or die "pipe: $!\n"; |
|
138
|
114
|
100
|
50
|
|
|
882
|
pipe(my $stderr_r, my $stderr_w) or die "pipe: $!\n" if $stderr eq 'capture'; |
|
139
|
|
|
|
|
|
|
|
|
140
|
114
|
|
50
|
|
|
234920
|
my $pid = fork // die "fork: $!\n"; |
|
141
|
114
|
100
|
|
|
|
3293
|
if ($pid == 0) { |
|
142
|
|
|
|
|
|
|
# Child process |
|
143
|
23
|
|
|
|
|
3202
|
close $stdout_r; |
|
144
|
23
|
100
|
|
|
|
2174
|
close $stderr_r if $stderr eq 'capture'; |
|
145
|
|
|
|
|
|
|
|
|
146
|
23
|
100
|
|
|
|
2103
|
if (exists $opt{stdin}) { |
|
|
|
100
|
|
|
|
|
|
|
147
|
1
|
50
|
|
|
|
427
|
my $tmp = new_tmpfile IO::File or die "tmpfile: $!\n"; |
|
148
|
1
|
|
|
|
|
91
|
binmode $tmp, ':encoding(utf8)'; |
|
149
|
1
|
|
|
|
|
220
|
$tmp->print($opt{stdin}); |
|
150
|
1
|
50
|
|
|
|
65
|
$tmp->seek(0, 0) or die "seek: $!\n"; |
|
151
|
1
|
50
|
|
|
|
106
|
open STDIN, '<&', $tmp or die "dup: $!\n"; |
|
152
|
1
|
|
|
|
|
114
|
binmode STDIN, ':encoding(utf8)'; |
|
153
|
|
|
|
|
|
|
} elsif (my $input = $obj->{INPUT}) { |
|
154
|
5
|
50
|
|
|
|
925
|
open STDIN, "<&=", $input->fileno or die "open: $!\n"; |
|
155
|
5
|
|
|
|
|
1013
|
binmode STDIN, ':encoding(utf8)'; |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
|
|
158
|
23
|
50
|
|
|
|
4298
|
open STDOUT, ">&=", $stdout_w->fileno or die "open stdout: $!\n"; |
|
159
|
23
|
100
|
|
|
|
3658
|
if ($stderr eq 'redirect') { |
|
|
|
100
|
|
|
|
|
|
|
160
|
3
|
50
|
|
|
|
275
|
open STDERR, ">&STDOUT" or die "open stderr: $!\n"; |
|
161
|
|
|
|
|
|
|
} elsif ($stderr eq 'capture') { |
|
162
|
4
|
50
|
|
|
|
108
|
open STDERR, ">&=", $stderr_w->fileno or die "open stderr: $!\n"; |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
# else: stderr passes through to terminal |
|
165
|
|
|
|
|
|
|
|
|
166
|
23
|
100
|
|
|
|
1393
|
if (ref $command[0] eq 'CODE') { |
|
167
|
8
|
|
|
|
|
232
|
my $code = shift @command; |
|
168
|
8
|
|
|
|
|
116
|
@ARGV = @command; |
|
169
|
8
|
50
|
|
|
|
450
|
if (my $name = code_name($code)) { |
|
170
|
8
|
|
|
|
|
302
|
$0 = $name; |
|
171
|
|
|
|
|
|
|
} |
|
172
|
8
|
|
|
|
|
406
|
$code->(@command); |
|
173
|
8
|
|
|
|
|
11952
|
exit 0; |
|
174
|
|
|
|
|
|
|
} |
|
175
|
15
|
|
|
|
|
0
|
exec @command; |
|
176
|
0
|
|
|
|
|
0
|
die "exec: $@\n"; |
|
177
|
|
|
|
|
|
|
} |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# Parent process |
|
180
|
91
|
|
|
|
|
7104
|
close $stdout_w; |
|
181
|
91
|
100
|
|
|
|
1654
|
close $stderr_w if $stderr eq 'capture'; |
|
182
|
|
|
|
|
|
|
|
|
183
|
91
|
|
|
|
|
22579
|
binmode $stdout_r, ':encoding(utf8)'; |
|
184
|
91
|
100
|
|
|
|
34848
|
binmode $stderr_r, ':encoding(utf8)' if $stderr eq 'capture'; |
|
185
|
|
|
|
|
|
|
|
|
186
|
91
|
|
|
|
|
1724
|
my $stdout = do { local $/; <$stdout_r> }; |
|
|
91
|
|
|
|
|
3981
|
|
|
|
91
|
|
|
|
|
29491653
|
|
|
187
|
91
|
100
|
|
|
|
15440548
|
my $stderr_out = $stderr eq 'capture' ? do { local $/; <$stderr_r> } : ''; |
|
|
7
|
|
|
|
|
114
|
|
|
|
7
|
|
|
|
|
350
|
|
|
188
|
|
|
|
|
|
|
|
|
189
|
91
|
|
|
|
|
3496
|
close $stdout_r; |
|
190
|
91
|
100
|
|
|
|
819
|
close $stderr_r if $stderr eq 'capture'; |
|
191
|
|
|
|
|
|
|
|
|
192
|
91
|
|
|
|
|
2811
|
waitpid $pid, 0; |
|
193
|
91
|
|
|
|
|
1085
|
my $result = $?; |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
return { |
|
196
|
91
|
|
|
|
|
8049
|
result => $result, |
|
197
|
|
|
|
|
|
|
data => $stdout, |
|
198
|
|
|
|
|
|
|
error => $stderr_out, |
|
199
|
|
|
|
|
|
|
pid => $pid, |
|
200
|
|
|
|
|
|
|
}; |
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
sub _tmpfile { |
|
204
|
114
|
|
|
114
|
|
434
|
my ($obj, $key, %opt) = @_; |
|
205
|
114
|
100
|
|
|
|
328
|
$key .= '_RAW' if $opt{raw}; |
|
206
|
114
|
|
66
|
|
|
615
|
my $fh = $obj->{$key} //= do { |
|
207
|
104
|
50
|
|
|
|
23602
|
my $f = new_tmpfile IO::File or die "tmpfile: $!\n"; |
|
208
|
104
|
100
|
|
|
|
1493
|
binmode $f, $opt{raw} ? ':utf8' : ':encoding(utf8)'; |
|
209
|
104
|
|
|
|
|
3906
|
$f; |
|
210
|
|
|
|
|
|
|
}; |
|
211
|
114
|
50
|
|
|
|
597
|
$fh->seek(0, 0) or die "seek: $!\n"; |
|
212
|
114
|
50
|
|
|
|
1868
|
$fh->truncate(0) or die "truncate: $!\n"; |
|
213
|
114
|
|
|
|
|
4959
|
$fh; |
|
214
|
|
|
|
|
|
|
} |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub _execute_nofork { |
|
217
|
61
|
|
|
61
|
|
100
|
my $obj = shift; |
|
218
|
61
|
|
|
|
|
71
|
my $command = shift; |
|
219
|
61
|
|
|
|
|
158
|
my %opt = @_; |
|
220
|
61
|
|
|
|
|
101
|
my @command = @$command; |
|
221
|
61
|
|
100
|
|
|
207
|
my $stderr_mode = $opt{stderr} // ''; |
|
222
|
61
|
|
|
|
|
89
|
my $raw = $opt{raw}; |
|
223
|
|
|
|
|
|
|
|
|
224
|
61
|
|
|
|
|
89
|
my $code = shift @command; |
|
225
|
|
|
|
|
|
|
|
|
226
|
61
|
|
|
|
|
127
|
my $tmp_stdout = $obj->_tmpfile('NOFORK_STDOUT', raw => $raw); |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# Save and redirect STDOUT (always needed) |
|
229
|
61
|
50
|
|
|
|
1381
|
open my $save_stdout, '>&', \*STDOUT or die "dup STDOUT: $!\n"; |
|
230
|
61
|
50
|
|
|
|
16746
|
open STDOUT, '>&', $tmp_stdout or die "redirect STDOUT: $!\n"; |
|
231
|
61
|
100
|
|
|
|
7638
|
binmode STDOUT, $raw ? ':utf8' : ':encoding(utf8)'; |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# Handle STDERR — only save/redirect when needed |
|
234
|
61
|
|
|
|
|
1430
|
my ($save_stderr, $tmp_stderr); |
|
235
|
61
|
100
|
|
|
|
203
|
if ($stderr_mode eq 'redirect') { |
|
|
|
100
|
|
|
|
|
|
|
236
|
3
|
50
|
|
|
|
66
|
open $save_stderr, '>&', \*STDERR or die "dup STDERR: $!\n"; |
|
237
|
3
|
50
|
|
|
|
39
|
open STDERR, '>&', \*STDOUT or die "redirect STDERR: $!\n"; |
|
238
|
|
|
|
|
|
|
} elsif ($stderr_mode eq 'capture') { |
|
239
|
9
|
|
|
|
|
30
|
$tmp_stderr = $obj->_tmpfile('NOFORK_STDERR', raw => $raw); |
|
240
|
9
|
50
|
|
|
|
312
|
open $save_stderr, '>&', \*STDERR or die "dup STDERR: $!\n"; |
|
241
|
9
|
50
|
|
|
|
114
|
open STDERR, '>&', $tmp_stderr or die "redirect STDERR: $!\n"; |
|
242
|
|
|
|
|
|
|
} |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
# Handle STDIN — only save/redirect when needed |
|
245
|
61
|
|
|
|
|
1079
|
my $save_stdin; |
|
246
|
61
|
100
|
|
|
|
187
|
if (exists $opt{stdin}) { |
|
|
|
100
|
|
|
|
|
|
|
247
|
13
|
|
|
|
|
47
|
my $tmp_stdin = $obj->_tmpfile('NOFORK_STDIN', raw => $raw); |
|
248
|
13
|
|
|
|
|
49
|
$tmp_stdin->print($opt{stdin}); |
|
249
|
13
|
50
|
|
|
|
135
|
$tmp_stdin->seek(0, 0) or die "seek: $!\n"; |
|
250
|
13
|
50
|
|
|
|
764
|
open $save_stdin, '<&', \*STDIN or die "dup STDIN: $!\n"; |
|
251
|
13
|
50
|
|
|
|
1724
|
open STDIN, '<&', $tmp_stdin or die "redirect STDIN: $!\n"; |
|
252
|
13
|
100
|
|
|
|
400
|
binmode STDIN, $raw ? ':utf8' : ':encoding(utf8)'; |
|
253
|
|
|
|
|
|
|
} elsif (my $input = $obj->{INPUT}) { |
|
254
|
3
|
50
|
|
|
|
18
|
$input->seek(0, 0) or die "seek: $!\n"; |
|
255
|
3
|
50
|
|
|
|
108
|
open $save_stdin, '<&', \*STDIN or die "dup STDIN: $!\n"; |
|
256
|
3
|
50
|
|
|
|
36
|
open STDIN, '<&', $input->fileno or die "redirect STDIN: $!\n"; |
|
257
|
3
|
50
|
|
|
|
117
|
binmode STDIN, $raw ? ':utf8' : ':encoding(utf8)'; |
|
258
|
|
|
|
|
|
|
} |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
# Set global state |
|
261
|
61
|
|
|
|
|
352
|
local $_; |
|
262
|
61
|
|
|
|
|
205
|
local @ARGV = @command; |
|
263
|
61
|
|
|
|
|
84
|
my $orig_0; |
|
264
|
61
|
50
|
|
|
|
135
|
if (my $name = code_name($code)) { |
|
265
|
61
|
|
|
|
|
148
|
$orig_0 = $0; |
|
266
|
61
|
|
|
|
|
420
|
$0 = $name; |
|
267
|
|
|
|
|
|
|
} |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# Execute |
|
270
|
61
|
|
|
|
|
171
|
my $result = 0; |
|
271
|
61
|
|
|
|
|
98
|
eval { $code->(@command) }; |
|
|
61
|
|
|
|
|
165
|
|
|
272
|
61
|
100
|
|
|
|
4290
|
if ($@) { |
|
273
|
6
|
|
|
|
|
12
|
$result = -1; |
|
274
|
|
|
|
|
|
|
} |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
# Flush and restore — only what was redirected |
|
277
|
61
|
|
|
|
|
390
|
STDOUT->flush; |
|
278
|
61
|
50
|
|
|
|
876
|
open STDOUT, '>&', $save_stdout or die "restore STDOUT: $!\n"; |
|
279
|
61
|
100
|
|
|
|
16949
|
if ($save_stderr) { |
|
280
|
12
|
|
|
|
|
63
|
STDERR->flush; |
|
281
|
12
|
50
|
|
|
|
168
|
open STDERR, '>&', $save_stderr or die "restore STDERR: $!\n"; |
|
282
|
|
|
|
|
|
|
} |
|
283
|
61
|
100
|
|
|
|
106
|
if ($save_stdin) { |
|
284
|
16
|
50
|
|
|
|
209
|
open STDIN, '<&', $save_stdin or die "restore STDIN: $!\n"; |
|
285
|
|
|
|
|
|
|
} |
|
286
|
61
|
50
|
|
|
|
1491
|
if (defined $orig_0) { |
|
287
|
61
|
|
|
|
|
327
|
$0 = $orig_0; |
|
288
|
|
|
|
|
|
|
} |
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# Read captured output from tmpfiles |
|
291
|
61
|
50
|
|
|
|
269
|
$tmp_stdout->seek(0, 0) or die "seek: $!\n"; |
|
292
|
61
|
|
|
|
|
553
|
my $stdout_data = do { local $/; <$tmp_stdout> }; |
|
|
61
|
|
|
|
|
203
|
|
|
|
61
|
|
|
|
|
2019
|
|
|
293
|
|
|
|
|
|
|
|
|
294
|
61
|
|
|
|
|
913
|
my $stderr_data = ''; |
|
295
|
61
|
100
|
|
|
|
145
|
if ($tmp_stderr) { |
|
296
|
9
|
50
|
|
|
|
27
|
$tmp_stderr->seek(0, 0) or die "seek: $!\n"; |
|
297
|
9
|
|
|
|
|
69
|
$stderr_data = do { local $/; <$tmp_stderr> }; |
|
|
9
|
|
|
|
|
27
|
|
|
|
9
|
|
|
|
|
216
|
|
|
298
|
|
|
|
|
|
|
} |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
return { |
|
301
|
61
|
|
|
|
|
1344
|
result => $result, |
|
302
|
|
|
|
|
|
|
data => $stdout_data, |
|
303
|
|
|
|
|
|
|
error => $stderr_data, |
|
304
|
|
|
|
|
|
|
}; |
|
305
|
|
|
|
|
|
|
} |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
sub data { |
|
308
|
25
|
|
|
25
|
1
|
1232
|
my $obj = shift; |
|
309
|
25
|
50
|
|
|
|
249
|
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
|
|
|
|
|
325
|
$obj->{RESULT}->{data}; |
|
321
|
|
|
|
|
|
|
} |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
sub error { |
|
324
|
9
|
|
|
9
|
1
|
27
|
my $obj = shift; |
|
325
|
9
|
|
|
|
|
160
|
$obj->{RESULT}->{error}; |
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
sub date { |
|
329
|
153
|
|
|
153
|
1
|
8372
|
my $obj = shift; |
|
330
|
153
|
100
|
|
|
|
1380
|
@_ ? $obj->{DATE} = shift : $obj->{DATE}; |
|
331
|
|
|
|
|
|
|
} |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
sub _set_stdin { |
|
334
|
31
|
|
|
31
|
|
150
|
my $obj = shift; |
|
335
|
31
|
|
|
|
|
88
|
my $data = shift; |
|
336
|
31
|
|
|
|
|
209
|
my $input = $obj->_tmpfile('INPUT'); |
|
337
|
31
|
50
|
|
|
|
145
|
$input->fcntl(F_SETFD, 0) or die "fcntl F_SETFD: $!\n"; |
|
338
|
31
|
|
|
|
|
442
|
$input->print($data); |
|
339
|
31
|
50
|
|
|
|
364
|
$input->seek(0, 0) or die "seek: $!\n"; |
|
340
|
31
|
|
|
|
|
1962
|
$obj; |
|
341
|
|
|
|
|
|
|
} |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
sub with { |
|
344
|
29
|
|
|
29
|
1
|
91
|
my $obj = shift; |
|
345
|
29
|
|
|
|
|
235
|
$obj->configure(@_); |
|
346
|
|
|
|
|
|
|
} |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
1; |
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
__END__ |