File Coverage

blib/lib/IO/CaptureOutput.pm
Criterion Covered Total %
statement 112 120 93.3
branch 50 58 86.2
condition 50 53 94.3
subroutine 22 23 95.6
pod 3 3 100.0
total 237 257 92.2


line stmt bran cond sub pod time code
1 6     6   386302 use strict;
  6         55  
  6         144  
2 6     6   24 use warnings;
  6         8  
  6         280  
3              
4             package IO::CaptureOutput;
5             # ABSTRACT: (DEPRECATED) capture STDOUT and STDERR from Perl code, subprocesses or XS
6              
7             our $VERSION = '1.1105';
8              
9 6     6   29 use vars qw/@ISA @EXPORT_OK %EXPORT_TAGS $CarpLevel/;
  6         9  
  6         354  
10 6     6   31 use Exporter;
  6         6  
  6         236  
11 6     6   40 use Carp qw/croak/;
  6         22  
  6         4065  
12             @ISA = 'Exporter';
13             @EXPORT_OK = qw/capture capture_exec qxx capture_exec_combined qxy/;
14             %EXPORT_TAGS = (all => \@EXPORT_OK);
15             $CarpLevel = 0; # help capture report errors at the right level
16              
17             sub _capture (&@) { ## no critic
18 60     60   153 my ($code, $output, $error, $output_file, $error_file) = @_;
19              
20             # check for valid combinations of input
21             {
22 60         90 local $Carp::CarpLevel = 1;
  60         185  
23 60         359 my $error = _validate($output, $error, $output_file, $error_file);
24 60 100       501 croak $error if $error;
25             }
26              
27             # if either $output or $error are defined, then we need a variable for
28             # results; otherwise we only capture to files and don't waste memory
29 58 100 100     159 if ( defined $output || defined $error ) {
30 48         104 for ($output, $error) {
31 96 100       173 $_ = \do { my $s; $s = ''} unless ref $_;
  10         12  
  10         21  
32 96 100 100     510 $$_ = '' if $_ != \undef && !defined($$_);
33             }
34             }
35              
36             # merge if same refs for $output and $error or if both are undef --
37             # i.e. capture \&foo, undef, undef, $merged_file
38             # this means capturing into separate files *requires* at least one
39             # capture variable
40 58   100     473 my $should_merge =
41             (defined $error && defined $output && $output == $error) ||
42             ( !defined $output && !defined $error ) ||
43             0;
44              
45 58         87 my ($capture_out, $capture_err);
46              
47             # undef means capture anonymously; anything other than \undef means
48             # capture to that ref; \undef means skip capture
49 58 100 100     245 if ( !defined $output || $output != \undef ) {
50 56         183 $capture_out = IO::CaptureOutput::_proxy->new(
51             'STDOUT', $output, undef, $output_file
52             );
53             }
54 58 100 100     949 if ( !defined $error || $error != \undef ) {
55 56 100       238 $capture_err = IO::CaptureOutput::_proxy->new(
56             'STDERR', $error, ($should_merge ? 'STDOUT' : undef), $error_file
57             );
58             }
59              
60             # now that output capture is setup, call the subroutine
61             # results get read when IO::CaptureOutput::_proxy objects go out of scope
62 58         374 &$code();
63             }
64              
65             # Extra indirection for symmetry with capture_exec, etc. Gets error reporting
66             # to the right level
67             sub capture (&@) { ## no critic
68 50     50 1 90949 return &_capture;
69             }
70              
71             sub capture_exec {
72 5     5 1 10108 my @args = @_;
73 5         10 my ($output, $error);
74 5     5   50 my $exit = _capture sub { system _shell_quote(@args) }, \$output, \$error;
  5         36  
75 5 100       71 my $success = ($exit == 0 ) ? 1 : 0 ;
76 5         50 $? = $exit;
77 5 100       75 return wantarray ? ($output, $error, $success, $exit) : $output;
78             }
79              
80             *qxx = \&capture_exec;
81              
82             sub capture_exec_combined {
83 5     5 1 20238 my @args = @_;
84 5         10 my $output;
85 5     5   131 my $exit = _capture sub { system _shell_quote(@args) }, \$output, \$output;
  5         18  
86 5 100       127 my $success = ($exit == 0 ) ? 1 : 0 ;
87 5         46 $? = $exit;
88 5 100       85 return wantarray ? ($output, $success, $exit) : $output;
89             }
90              
91             *qxy = \&capture_exec_combined;
92              
93             # extra quoting required on Win32 systems
94 10     10   53426 *_shell_quote = ($^O =~ /MSWin32/) ? \&_shell_quote_win32 : sub {@_};
95             sub _shell_quote_win32 {
96 0     0   0 my @args;
97 0         0 for (@_) {
98 0 0       0 if (/[ \"]/) { # TODO: check if ^ requires escaping
99 0         0 (my $escaped = $_) =~ s/([\"])/\\$1/g;
100 0         0 push @args, '"' . $escaped . '"';
101 0         0 next;
102             }
103 0         0 push @args, $_
104             }
105 0         0 return @args;
106             }
107              
108             # detect errors and return an error message or empty string;
109             sub _validate {
110 60     60   210 my ($output, $error, $output_file, $error_file) = @_;
111              
112             # default to "ok"
113 60         123 my $msg = q{};
114              
115             # \$out, \$out, $outfile, $errfile
116 60 100 100     712 if ( defined $output && defined $error
    100 100        
      100        
      100        
      66        
      100        
      100        
      100        
      100        
      100        
117             && defined $output_file && defined $error_file
118             && $output == $error
119             && $output != \undef
120             && $output_file ne $error_file
121             ) {
122 1         2 $msg = "Merged STDOUT and STDERR, but specified different output and error files";
123             }
124             # undef, undef, $outfile, $errfile
125             elsif ( !defined $output && !defined $error
126             && defined $output_file && defined $error_file
127             && $output_file ne $error_file
128             ) {
129 1         3 $msg = "Merged STDOUT and STDERR, but specified different output and error files";
130             }
131              
132 60         117 return $msg;
133             }
134              
135             # Captures everything printed to a filehandle for the lifetime of the object
136             # and then transfers it to a scalar reference
137             package IO::CaptureOutput::_proxy;
138 6     6   3608 use File::Temp 0.16 'tempfile';
  6         107271  
  6         1063  
139 6     6   43 use File::Basename qw/basename/;
  6         8  
  6         510  
140 6     6   31 use Symbol qw/gensym qualify qualify_to_ref/;
  6         11  
  6         234  
141 6     6   27 use Carp;
  6         11  
  6         752  
142              
143 110 50   110   575 sub _is_wperl { $^O eq 'MSWin32' && basename($^X) eq 'wperl.exe' }
144              
145             sub new {
146 112     112   245 my $class = shift;
147 112         209 my ($orig_fh, $capture_var, $merge_fh, $capture_file) = @_;
148 112         299 $orig_fh = qualify($orig_fh); # e.g. main::STDOUT
149 112         2992 my $fhref = qualify_to_ref($orig_fh); # e.g. \*STDOUT
150              
151             # Duplicate the filehandle
152 112         1266 my $saved_fh;
153             {
154 6     6   37 no strict 'refs'; ## no critic - needed for 5.005
  6         9  
  6         809  
  112         135  
155 112 100 66     442 if ( defined fileno($orig_fh) && ! _is_wperl() ) {
156 110         243 $saved_fh = gensym;
157 110 50       4023 open $saved_fh, ">&$orig_fh" or croak "Can't redirect <$orig_fh> - $!";
158             }
159             }
160              
161             # Create replacement filehandle if not merging
162 112         343 my ($newio_fh, $newio_file);
163 112 100       273 if ( ! $merge_fh ) {
164 92         198 $newio_fh = gensym;
165 92 100       1361 if ($capture_file) {
166 19         31 $newio_file = $capture_file;
167             } else {
168 73         258 (undef, $newio_file) = tempfile;
169             }
170 92 50       27684 open $newio_fh, "+>$newio_file" or croak "Can't write temp file for $orig_fh - $!";
171             }
172             else {
173 20         58 $newio_fh = qualify($merge_fh);
174             }
175              
176             # Redirect (or merge)
177             {
178 6     6   34 no strict 'refs'; ## no critic -- needed for 5.005
  6         9  
  6         1566  
  112         577  
179 112 50       2632 open $fhref, ">&".fileno($newio_fh) or croak "Can't redirect $orig_fh - $!";
180             }
181              
182 112         1681 bless [$$, $orig_fh, $saved_fh, $capture_var, $newio_fh, $newio_file, $capture_file], $class;
183             }
184              
185             sub DESTROY {
186 112     112   267946 my $self = shift;
187              
188 112         560 my ($pid, $orig_fh, $saved_fh, $capture_var, $newio_fh,
189             $newio_file, $capture_file) = @$self;
190 112 100       1015 return unless $pid eq $$; # only cleanup in the process that is capturing
191              
192             # restore the original filehandle
193 110         564 my $fh_ref = Symbol::qualify_to_ref($orig_fh);
194 110         3527 select((select ($fh_ref), $|=1)[0]);
195 110 100       286 if (defined $saved_fh) {
196 108 50       2792 open $fh_ref, ">&". fileno($saved_fh) or croak "Can't restore $orig_fh - $!";
197             }
198             else {
199 2         14 close $fh_ref;
200             }
201              
202             # transfer captured data to the scalar reference if we didn't merge
203             # $newio_file is undef if this file handle is merged to another
204 110 100 100     760 if (ref $capture_var && $newio_file) {
205             # some versions of perl complain about reading from fd 1 or 2
206             # which could happen if STDOUT and STDERR were closed when $newio
207             # was opened, so we just squelch warnings here and continue
208 80         438 local $^W;
209 80         520 seek $newio_fh, 0, 0;
210 80         151 $$capture_var = do {local $/; <$newio_fh>};
  80         426  
  80         2904  
211             }
212 110 100       5556 close $newio_fh if $newio_file;
213              
214             # Cleanup
215 110 100 66     2058 return unless defined $newio_file && -e $newio_file;
216 90 100       438 return if $capture_file; # the "temp" file was explicitly named
217 71 50       107101 unlink $newio_file or carp "Couldn't remove temp file '$newio_file' - $!";
218             }
219              
220             1;
221              
222             __END__
223              
224             =pod
225              
226             =encoding UTF-8
227              
228             =head1 NAME
229              
230             IO::CaptureOutput - (DEPRECATED) capture STDOUT and STDERR from Perl code, subprocesses or XS
231              
232             =head1 VERSION
233              
234             version 1.1105
235              
236             =head1 SYNOPSIS
237              
238             use IO::CaptureOutput qw(capture qxx qxy);
239              
240             # STDOUT and STDERR separately
241             capture { noisy_sub(@args) } \$stdout, \$stderr;
242              
243             # STDOUT and STDERR together
244             capture { noisy_sub(@args) } \$combined, \$combined;
245              
246             # STDOUT and STDERR from external command
247             ($stdout, $stderr, $success) = qxx( @cmd );
248              
249             # STDOUT and STDERR together from external command
250             ($combined, $success) = qxy( @cmd );
251              
252             =head1 DESCRIPTION
253              
254             B<This module is no longer recommended by the maintainer> - see
255             L<Capture::Tiny> instead.
256              
257             This module provides routines for capturing STDOUT and STDERR from perl
258             subroutines, forked system calls (e.g. C<system()>, C<fork()>) and from XS
259             or C modules.
260              
261             =head1 NAME
262              
263             =head1 FUNCTIONS
264              
265             The following functions will be exported on demand.
266              
267             =head2 capture()
268              
269             capture \&subroutine, \$stdout, \$stderr;
270              
271             Captures everything printed to C<STDOUT> and C<STDERR> for the duration of
272             C<&subroutine>. C<$stdout> and C<$stderr> are optional scalars that will
273             contain C<STDOUT> and C<STDERR> respectively.
274              
275             C<capture()> uses a code prototype so the first argument can be specified
276             directly within brackets if desired.
277              
278             # shorthand with prototype
279             capture C< print __PACKAGE__ > \$stdout, \$stderr;
280              
281             Returns the return value(s) of C<&subroutine>. The sub is called in the
282             same context as C<capture()> was called e.g.:
283              
284             @rv = capture C< wantarray > ; # returns true
285             $rv = capture C< wantarray > ; # returns defined, but not true
286             capture C< wantarray >; # void, returns undef
287              
288             C<capture()> is able to capture output from subprocesses and C code, which
289             traditional C<tie()> methods of output capture are unable to do.
290              
291             B<Note:> C<capture()> will only capture output that has been written or
292             flushed to the filehandle.
293              
294             If the two scalar references refer to the same scalar, then C<STDERR> will
295             be merged to C<STDOUT> before capturing and the scalar will hold the
296             combined output of both.
297              
298             capture \&subroutine, \$combined, \$combined;
299              
300             Normally, C<capture()> uses anonymous, temporary files for capturing
301             output. If desired, specific file names may be provided instead as
302             additional options.
303              
304             capture \&subroutine, \$stdout, \$stderr, $out_file, $err_file;
305              
306             Files provided will be clobbered, overwriting any previous data, but will
307             persist after the call to C<capture()> for inspection or other
308             manipulation.
309              
310             By default, when no references are provided to hold STDOUT or STDERR,
311             output is captured and silently discarded.
312              
313             # Capture STDOUT, discard STDERR
314             capture \&subroutine, \$stdout;
315              
316             # Discard STDOUT, capture STDERR
317             capture \&subroutine, undef, \$stderr;
318              
319             However, even when using C<undef>, output can be captured to specific
320             files.
321              
322             # Capture STDOUT to a specific file, discard STDERR
323             capture \&subroutine, \$stdout, undef, $outfile;
324              
325             # Discard STDOUT, capture STDERR to a specific file
326             capture \&subroutine, undef, \$stderr, undef, $err_file;
327              
328             # Discard both, capture merged output to a specific file
329             capture \&subroutine, undef, undef, $mergedfile;
330              
331             It is a fatal error to merge STDOUT and STDERR and request separate,
332             specific files for capture.
333              
334             # ERROR:
335             capture \&subroutine, \$stdout, \$stdout, $out_file, $err_file;
336             capture \&subroutine, undef, undef, $out_file, $err_file;
337              
338             If either STDOUT or STDERR should be passed through to the terminal instead
339             of captured, provide a reference to undef -- C<\undef> -- instead of a
340             capture variable.
341              
342             # Capture STDOUT, display STDERR
343             capture \&subroutine, \$stdout, \undef;
344              
345             # Display STDOUT, capture STDERR
346             capture \&subroutine, \undef, \$stderr;
347              
348             =head2 capture_exec()
349              
350             ($stdout, $stderr, $success, $exit_code) = capture_exec(@args);
351              
352             Captures and returns the output from C<system(@args)>. In scalar context,
353             C<capture_exec()> will return what was printed to C<STDOUT>. In list
354             context, it returns what was printed to C<STDOUT> and C<STDERR> as well as
355             a success flag and the exit value.
356              
357             $stdout = capture_exec('perl', '-e', 'print "hello world"');
358              
359             ($stdout, $stderr, $success, $exit_code) =
360             capture_exec('perl', '-e', 'warn "Test"');
361              
362             C<capture_exec> passes its arguments to C<system()> and on MSWin32 will
363             protect arguments with shell quotes if necessary. This makes it a handy
364             and slightly more portable alternative to backticks, piped C<open()> and
365             C<IPC::Open3>.
366              
367             The C<$success> flag returned will be true if the command ran successfully
368             and false if it did not (if the command could not be run or if it ran and
369             returned a non-zero exit value). On failure, the raw exit value of the
370             C<system()> call is available both in the C<$exit_code> returned and in the
371             C<$?> variable.
372              
373             ($stdout, $stderr, $success, $exit_code) =
374             capture_exec('perl', '-e', 'warn "Test" and exit 1');
375              
376             if ( ! $success ) {
377             print "The exit code was " . ($exit_code >> 8) . "\n";
378             }
379              
380             See L<perlvar> for more information on interpreting a child process exit
381             code.
382              
383             =head2 capture_exec_combined()
384              
385             ($combined, $success, $exit_code) = capture_exec_combined(
386             'perl', '-e', 'print "hello\n"', 'warn "Test\n"
387             );
388              
389             This is just like C<capture_exec()>, except that it merges C<STDERR> with
390             C<STDOUT> before capturing output.
391              
392             B<Note:> there is no guarantee that text printed to C<STDOUT> and C<STDERR>
393             in the subprocess will be appear in order. The actual order will depend on
394             how IO buffering is handled in the subprocess.
395              
396             =head2 qxx()
397              
398             This is an alias for C<capture_exec()>.
399              
400             =head2 qxy()
401              
402             This is an alias for C<capture_exec_combined()>.
403              
404             =head1 SEE ALSO
405              
406             =over 4
407              
408             =item *
409              
410             L<Capture::Tiny>
411              
412             =item *
413              
414             L<IPC::Open3>
415              
416             =item *
417              
418             L<IO::Capture>
419              
420             =item *
421              
422             L<IO::Utils>
423              
424             =item *
425              
426             L<IPC::System::Simple>
427              
428             =back
429              
430             =for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan
431              
432             =head1 SUPPORT
433              
434             =head2 Bugs / Feature Requests
435              
436             Please report any bugs or feature requests through the issue tracker
437             at L<https://github.com/dagolden/IO-CaptureOutput/issues>.
438             You will be notified automatically of any progress on your issue.
439              
440             =head2 Source Code
441              
442             This is open source software. The code repository is available for
443             public review and contribution under the terms of the license.
444              
445             L<https://github.com/dagolden/IO-CaptureOutput>
446              
447             git clone https://github.com/dagolden/IO-CaptureOutput.git
448              
449             =head1 AUTHORS
450              
451             =over 4
452              
453             =item *
454              
455             Simon Flack <simonflk@cpan.org>
456              
457             =item *
458              
459             David Golden <dagolden@cpan.org>
460              
461             =back
462              
463             =head1 CONTRIBUTORS
464              
465             =for stopwords David Golden José Joaquín Atria Mike Latimer Olivier Mengué Tony Cook
466              
467             =over 4
468              
469             =item *
470              
471             David Golden <xdg@xdg.me>
472              
473             =item *
474              
475             José Joaquín Atria <jjatria@gmail.com>
476              
477             =item *
478              
479             Mike Latimer <mlatimer@suse.com>
480              
481             =item *
482              
483             Olivier Mengué <dolmen@cpan.org>
484              
485             =item *
486              
487             Tony Cook <tony@develop-help.com>
488              
489             =back
490              
491             =head1 COPYRIGHT AND LICENSE
492              
493             This software is copyright (c) 2019 by Simon Flack and David Golden.
494              
495             This is free software; you can redistribute it and/or modify it under
496             the same terms as the Perl 5 programming language system itself.
497              
498             =cut