Codebase list libcapture-tiny-perl / ac30123
[svn-upgrade] Integrating new upstream version, libcapture-tiny-perl (0.07) Jonathan Yu 14 years ago
10 changed file(s) with 133 addition(s) and 113 deletion(s). Raw diff Collapse all Expand all
11 # Copyright (c) 2009 by David Golden. All rights reserved.
22 # Licensed under Apache License, Version 2.0 (the "License").
33 # You may not use this file except in compliance with the License.
4 # A copy of the License was distributed with this file or you may obtain a
4 # A copy of the License was distributed with this file or you may obtain a
55 # copy of the License from http://www.apache.org/licenses/LICENSE-2.0
66
77 Revision history for Capture-Tiny
8
9 0.07 Sun Jan 24 00:18:45 EST 2010
10
11 Fixed:
12
13 - Changed test for $? preservation to be more portable
14
15 - Dropped support for Perl 5.8.0 specifically due to excessive bugs.
16 Tests will bail out. (5.6.X is still supported)
817
918 0.06 Thu May 7 06:54:53 EDT 2009
1019
5564 Fixed:
5665
5766 - Tests skip if not Win32 and no fork() (rather than Build.PL and
58 Makefile.PL failing); this allows capture() on odd platforms, even if
67 Makefile.PL failing); this allows capture() on odd platforms, even if
5968 fork doesn't work
6069
6170 0.02 Tue Feb 17 17:24:35 EST 2009
6271
63 Fixed:
72 Fixed:
6473
6574 - Bug recovering output when STDOUT is empty (reported by Vincent Pit)
6675
2121 ^_build
2222 ^cover_db
2323 ^.*\.bat$
24 ^MYMETA\.
2425
2526 # Temp, old, vi and emacs files.
2627 ~$
00 ---
1 name: Capture-Tiny
2 version: 0.06
1 abstract: 'Capture STDOUT and STDERR from Perl, XS or external programs'
32 author:
43 - 'David Golden <dagolden@cpan.org>'
5 abstract: 'Capture STDOUT and STDERR from Perl, XS or external programs'
4 build_requires:
5 Test::More: 0.62
6 configure_requires:
7 Module::Build: 0.36
8 generated_by: 'Module::Build version 0.3603'
69 license: apache
7 resources:
8 bugtracker: http://rt.cpan.org/NoAuth/Bugs.html?Dist=Capture-Tiny
9 repository: http://github.com/dagolden/capture-tiny/
10 meta-spec:
11 url: http://module-build.sourceforge.net/META-spec-v1.4.html
12 version: 1.4
13 name: Capture-Tiny
14 no_index:
15 directory:
16 - examples
17 - inc
18 - t
19 provides:
20 Capture::Tiny:
21 file: lib/Capture/Tiny.pm
22 version: 0.07
1023 requires:
1124 Exporter: 0
1225 File::Spec: 0
1326 File::Temp: 0.14
1427 IO::Handle: 0
1528 perl: 5.006
16 build_requires:
17 Test::More: 0.62
18 provides:
19 Capture::Tiny:
20 file: lib/Capture/Tiny.pm
21 version: 0.06
22 generated_by: Module::Build version 0.3201
23 meta-spec:
24 url: http://module-build.sourceforge.net/META-spec-v1.4.html
25 version: 1.4
26 no_index:
27 directory:
28 - examples
29 - inc
30 - t
29 resources:
30 bugtracker: http://rt.cpan.org/NoAuth/Bugs.html?Dist=Capture-Tiny
31 repository: http://github.com/dagolden/capture-tiny/
32 version: 0.07
0 # Note: this file was auto-generated by Module::Build::Compat version 0.32_01
0 # Note: this file was auto-generated by Module::Build::Compat version 0.3603
11 require 5.006;
22 use ExtUtils::MakeMaker;
33 WriteMakefile
44 (
5 'PL_FILES' => {},
6 'INSTALLDIRS' => 'site',
75 'NAME' => 'Capture::Tiny',
8 'EXE_FILES' => [],
96 'VERSION_FROM' => 'lib/Capture/Tiny.pm',
107 'PREREQ_PM' => {
11 'Test::More' => '0.62',
8 'Exporter' => 0,
9 'File::Spec' => 0,
10 'File::Temp' => '0.14',
1211 'IO::Handle' => 0,
13 'File::Temp' => '0.14',
14 'File::Spec' => 0,
15 'Exporter' => 0
16 }
12 'Test::More' => '0.62'
13 },
14 'INSTALLDIRS' => 'site',
15 'EXE_FILES' => [],
16 'PL_FILES' => {}
1717 )
1818 ;
22 programs
33
44 VERSION
5 This documentation describes version 0.06.
5 This documentation describes version 0.07.
66
77 SYNOPSIS
88 use Capture::Tiny qw/capture tee capture_merged tee_merged/;
9
10 ($stdout, $stderr) = capture {
11 # your code here
12 };
13
14 ($stdout, $stderr) = tee {
15 # your code here
16 };
17
18 $merged = capture_merged {
19 # your code here
20 };
21
22 $merged = tee_merged {
9
10 ($stdout, $stderr) = capture {
11 # your code here
12 };
13
14 ($stdout, $stderr) = tee {
15 # your code here
16 };
17
18 $merged = capture_merged {
19 # your code here
20 };
21
22 $merged = tee_merged {
2323 # your code here
2424 };
2525
4242 ($stdout, $stderr) = capture \&code;
4343 $stdout = capture \&code;
4444
45 The "capture" function takes a code reference and returns what is sent
45 The `capture' function takes a code reference and returns what is sent
4646 to STDOUT and STDERR. In scalar context, it returns only STDOUT. If no
4747 output was received, returns an empty string. Regardless of context, all
4848 output is captured -- nothing is passed to the existing handles.
5757 capture_merged
5858 $merged = capture_merged \&code;
5959
60 The "capture_merged" function works just like "capture" except STDOUT
60 The `capture_merged' function works just like `capture' except STDOUT
6161 and STDERR are merged. (Technically, STDERR is redirected to STDOUT
6262 before executing the function.) If no output was received, returns an
63 empty string. As with "capture" it may be called in block form.
63 empty string. As with `capture' it may be called in block form.
6464
6565 Caution: STDOUT and STDERR output in the merged result are not
6666 guaranteed to be properly ordered due to buffering.
6969 ($stdout, $stderr) = tee \&code;
7070 $stdout = tee \&code;
7171
72 The "tee" function works just like "capture", except that output is
72 The `tee' function works just like `capture', except that output is
7373 captured as well as passed on to the original STDOUT and STDERR. As with
74 "capture" it may be called in block form.
74 `capture' it may be called in block form.
7575
7676 tee_merged
7777 $merged = tee_merged \&code;
7878
79 The "tee_merged" function works just like "capture_merged" except that
80 output is captured as well as passed on to STDOUT. As with "capture" it
79 The `tee_merged' function works just like `capture_merged' except that
80 output is captured as well as passed on to STDOUT. As with `capture' it
8181 may be called in block form.
8282
8383 Caution: STDOUT and STDERR output in the merged result are not
8585
8686 LIMITATIONS
8787 Portability
88 Portability is a goal, not a guarantee. "tee" requires fork, except on
89 Windows where "system(1, @cmd)" is used instead. Not tested on any
88 Portability is a goal, not a guarantee. `tee' requires fork, except on
89 Windows where `system(1, @cmd)' is used instead. Not tested on any
9090 particularly esoteric platforms yet.
9191
9292 PerlIO layers
9393 Capture::Tiny does it's best to preserve PerlIO layers such as ':utf8'
9494 or ':crlf' when capturing. Layers should be applied to STDOUT or STDERR
95 *before* the call to "capture" or "tee".
95 *before* the call to `capture' or `tee'.
9696
9797 Closed STDIN, STDOUT or STDERR
9898 Capture::Tiny will work even if STDIN, STDOUT or STDERR have been
104104
105105 Scalar filehandles and STDIN, STDOUT or STDERR
106106 If STDOUT or STDERR are reopened to scalar filehandles prior to the call
107 to "capture" or "tee", then Capture::Tiny will override the output
108 handle for the duration of the "capture" or "tee" call and then send
107 to `capture' or `tee', then Capture::Tiny will override the output
108 handle for the duration of the `capture' or `tee' call and then send
109109 captured output to the output handle after the capture is complete.
110110 (Requires Perl 5.8)
111111
113113 scalar reference.
114114
115115 Tied STDIN, STDOUT or STDERR
116 If STDOUT or STDERR are tied prior to the call to "capture" or "tee",
116 If STDOUT or STDERR are tied prior to the call to `capture' or `tee',
117117 then Capture::Tiny will attempt to override the tie for the duration of
118 the "capture" or "tee" call and then send captured output to the tied
118 the `capture' or `tee' call and then send captured output to the tied
119119 handle after the capture is complete. (Requires Perl 5.8)
120120
121121 Capture::Tiny does not (yet) support resending utf8 encoded data to a
125125 capturing or teeing when STDIN is tied is currently broken on Windows.
126126
127127 Modifiying STDIN, STDOUT or STDERR during a capture
128 Attempting to modify STDIN, STDOUT or STDERR *during* "capture" or "tee"
128 Attempting to modify STDIN, STDOUT or STDERR *during* `capture' or `tee'
129129 is almost certainly going to cause problems. Don't do that.
130
131 No support for Perl 5.8.0
132 It's just too buggy when it comes to layers and UTF8.
130133
131134 BUGS
132135 Please report any bugs or feature requests using the CPAN Request
133136 Tracker. Bugs can be submitted through the web interface at
134 <http://rt.cpan.org/Dist/Display.html?Queue=Capture-Tiny>
137 http://rt.cpan.org/Dist/Display.html?Queue=Capture-Tiny
135138
136139 When submitting a bug or request, please include a test-file or a patch
137140 to an existing test-file that illustrates the bug or desired feature.
193196 Licensed under Apache License, Version 2.0 (the "License"). You may not
194197 use this file except in compliance with the License. A copy of the
195198 License was distributed with this file or you may obtain a copy of the
196 License from http://www.apache.org/licenses/LICENSE-2.0
199 License from
200 http:E<sol>E<sol>www.apache.orgE<sol>licensesE<sol>LICENSE-2.0
197201
198202 Files produced as output though the use of this software, shall not be
199203 considered Derivative Works, but shall be considered the original work
00 # Copyright (c) 2009 by David Golden. All rights reserved.
11 # Licensed under Apache License, Version 2.0 (the "License").
22 # You may not use this file except in compliance with the License.
3 # A copy of the License was distributed with this file or you may obtain a
3 # A copy of the License was distributed with this file or you may obtain a
44 # copy of the License from http://www.apache.org/licenses/LICENSE-2.0
55
66 package Capture::Tiny;
1313 use File::Spec ();
1414 use File::Temp qw/tempfile tmpnam/;
1515 # Get PerlIO or fake it
16 BEGIN { eval { require PerlIO; 1 } or *PerlIO::get_layers = sub { return () }; }
17
18 our $VERSION = '0.06';
16 BEGIN {
17 eval { require PerlIO; PerlIO->can('get_layers') }
18 or *PerlIO::get_layers = sub { return () };
19 }
20
21 our $VERSION = '0.07';
1922 $VERSION = eval $VERSION; ## no critic
2023 our @ISA = qw/Exporter/;
2124 our @EXPORT_OK = qw/capture capture_merged tee tee_merged/;
3538 # This is annoying, but seems to be the best that can be done
3639 # as a simple, portable IPC technique
3740 #--------------------------------------------------------------------------#
38 my @cmd = ($^X, '-e', '$SIG{HUP}=sub{exit}; '
41 my @cmd = ($^X, '-e', '$SIG{HUP}=sub{exit}; '
3942 . 'if( my $fn=shift ){ open my $fh, qq{>$fn}; print {$fh} $$; close $fh;} '
4043 . 'my $buf; while (sysread(STDIN, $buf, 2048)) { '
41 . 'syswrite(STDOUT, $buf); syswrite(STDERR, $buf)}'
44 . 'syswrite(STDOUT, $buf); syswrite(STDERR, $buf)}'
4245 );
4346
4447 #--------------------------------------------------------------------------#
7174 }
7275
7376 my %dup; # cache this so STDIN stays fd0
74 my %proxy_count;
77 my %proxy_count;
7578 sub _proxy_std {
7679 my %proxies;
7780 if ( ! defined fileno STDIN ) {
121124
122125 sub _unproxy {
123126 my (%proxies) = @_;
124 _debug( "# unproxing " . join(" ", keys %proxies) . "\n" );
127 _debug( "# unproxing " . join(" ", keys %proxies) . "\n" );
125128 for my $p ( keys %proxies ) {
126129 $proxy_count{$p}--;
127130 _debug( "# unproxied " . uc($p) . " ($proxy_count{$p} left)\n" );
128131 if ( ! $proxy_count{$p} ) {
129132 _close $proxies{$p};
130 _close $dup{$p} unless $] < 5.008; # 5.6 will have already closed this as dup
133 _close $dup{$p} unless $] < 5.008; # 5.6 will have already closed this as dup
131134 delete $dup{$p};
132135 }
133136 }
135138
136139 sub _copy_std {
137140 my %handles = map { $_, IO::Handle->new } qw/stdin stdout stderr/;
138 _debug( "# copying std handles ...\n" );
139 _open $handles{stdin}, "<&STDIN";
141 _debug( "# copying std handles ...\n" );
142 _open $handles{stdin}, "<&STDIN";
140143 _open $handles{stdout}, ">&STDOUT";
141144 _open $handles{stderr}, ">&STDERR";
142145 return \%handles;
158161 # setup pipes
159162 $stash->{$_}{$which} = IO::Handle->new for qw/tee reader/;
160163 pipe $stash->{reader}{$which}, $stash->{tee}{$which};
161 _debug( "# pipe for $which\: " . _name($stash->{tee}{$which}) . " "
162 . fileno( $stash->{tee}{$which} ) . " => " . _name($stash->{reader}{$which})
164 _debug( "# pipe for $which\: " . _name($stash->{tee}{$which}) . " "
165 . fileno( $stash->{tee}{$which} ) . " => " . _name($stash->{reader}{$which})
163166 . " " . fileno( $stash->{reader}{$which}) . "\n" );
164167 select((select($stash->{tee}{$which}), $|=1)[0]); # autoflush
165168 # setup desired redirection for parent and child
194197
195198 sub _fork_exec {
196199 my ($which, $stash) = @_;
197 my $pid = fork;
200 my $pid = fork;
198201 if ( not defined $pid ) {
199202 Carp::confess "Couldn't fork(): $!";
200203 }
201204 elsif ($pid == 0) { # child
202 _debug( "# in child process ...\n" );
205 _debug( "# in child process ...\n" );
203206 untie *STDIN; untie *STDOUT; untie *STDERR;
204207 _close $stash->{tee}{$which};
205 _debug( "# redirecting handles in child ...\n" );
208 _debug( "# redirecting handles in child ...\n" );
206209 _open_std( $stash->{child}{$which} );
207 _debug( "# calling exec on command ...\n" );
210 _debug( "# calling exec on command ...\n" );
208211 exec @cmd, $stash->{flag_files}{$which};
209212 }
210213 $stash->{pid}{$which} = $pid
212215
213216 sub _files_exist { -f $_ || return 0 for @_; return 1 }
214217
215 sub _wait_for_tees {
218 sub _wait_for_tees {
216219 my ($stash) = @_;
217220 my $start = time;
218221 my @files = values %{$stash->{flag_files}};
219222 1 until _files_exist(@files) || (time - $start > 30);
220223 Carp::confess "Timed out waiting for subprocesses to start" if ! _files_exist(@files);
221 unlink $_ for @files;
224 unlink $_ for @files;
222225 }
223226
224227 sub _kill_tees {
236239 }
237240 }
238241
239 sub _slurp {
240 seek $_[0],0,0; local $/; return scalar readline $_[0];
242 sub _slurp {
243 seek $_[0],0,0; local $/; return scalar readline $_[0];
241244 }
242245
243246 #--------------------------------------------------------------------------#
245248 #--------------------------------------------------------------------------#
246249
247250 sub _capture_tee {
248 _debug( "# starting _capture_tee with (@_)...\n" );
251 _debug( "# starting _capture_tee with (@_)...\n" );
249252 my ($tee_stdout, $tee_stderr, $merge, $code) = @_;
250253 # save existing filehandles and setup captures
251254 local *CT_ORIG_STDIN = *STDIN ;
265268 $localize{stderr}++, local(*STDERR) if grep { $_ eq 'scalar' } @{$layers{stderr}};
266269 $localize{stdout}++, local(*STDOUT), _open( \*STDOUT, ">&=1") if tied *STDOUT && $] >= 5.008;
267270 $localize{stderr}++, local(*STDERR), _open( \*STDERR, ">&=2") if tied *STDERR && $] >= 5.008;
268 _debug( "# localized $_\n" ) for keys %localize;
271 _debug( "# localized $_\n" ) for keys %localize;
269272 my %proxy_std = _proxy_std();
270273 _debug( "# proxy std is @{ [%proxy_std] }\n" );
271274 my $stash = { old => _copy_std() };
286289 # finalize redirection
287290 $stash->{new}{stderr} = $stash->{new}{stdout} if $merge;
288291 $stash->{new}{stdin} = $stash->{old}{stdin};
289 _debug( "# redirecting in parent ...\n" );
292 _debug( "# redirecting in parent ...\n" );
290293 _open_std( $stash->{new} );
291294 # execute user provided code
292295 my $exit_code;
293296 {
294297 local *STDIN = *CT_ORIG_STDIN if $localize{stdin}; # get original, not proxy STDIN
295298 local *STDERR = *STDOUT if $merge; # minimize buffer mixups during $code
296 _debug( "# finalizing layers ...\n" );
299 _debug( "# finalizing layers ...\n" );
297300 _relayer(\*STDOUT, $layers{stdout});
298301 _relayer(\*STDERR, $layers{stderr}) unless $merge;
299 _debug( "# running code $code ...\n" );
302 _debug( "# running code $code ...\n" );
300303 $code->();
301304 $exit_code = $?; # save this for later
302305 }
303306 # restore prior filehandles and shut down tees
304 _debug( "# restoring ...\n" );
307 _debug( "# restoring ...\n" );
305308 _open_std( $stash->{old} );
306309 _close( $_ ) for values %{$stash->{old}}; # don't leak fds
307310 _unproxy( %proxy_std );
312315 _debug( "# slurping captured $_ with layers: @{[PerlIO::get_layers($stash->{capture}{$_})]}\n") for qw/stdout stderr/;
313316 my $got_out = _slurp($stash->{capture}{stdout});
314317 my $got_err = $merge ? q() : _slurp($stash->{capture}{stderr});
315 print CT_ORIG_STDOUT $got_out if $localize{stdout} && $tee_stdout;
316 print CT_ORIG_STDERR $got_err if !$merge && $localize{stderr} && $tee_stdout;
318 print CT_ORIG_STDOUT $got_out if $localize{stdout} && $tee_stdout;
319 print CT_ORIG_STDERR $got_err if !$merge && $localize{stderr} && $tee_stdout;
317320 $? = $exit_code;
318 _debug( "# ending _capture_tee with (@_)...\n" );
321 _debug( "# ending _capture_tee with (@_)...\n" );
319322 return $got_out if $merge;
320323 return wantarray ? ($got_out, $got_err) : $got_out;
321324 }
322325
323326 #--------------------------------------------------------------------------#
324 # create API subroutines from [tee STDOUT flag, tee STDERR, merge flag]
327 # create API subroutines from [tee STDOUT flag, tee STDERR, merge flag]
325328 #--------------------------------------------------------------------------#
326329
327330 my %api = (
332335 );
333336
334337 for my $sub ( keys %api ) {
335 my $args = join q{, }, @{$api{$sub}};
338 my $args = join q{, }, @{$api{$sub}};
336339 eval "sub $sub(&) {unshift \@_, $args; goto \\&_capture_tee;}"; ## no critic
337340 }
338341
485488
486489 Attempting to modify STDIN, STDOUT or STDERR ~during~ {capture} or {tee} is
487490 almost certainly going to cause problems. Don't do that.
491
492 == No support for Perl 5.8.0
493
494 It's just too buggy when it comes to layers and UTF8.
488495
489496 = BUGS
490497
77
88 =head1 VERSION
99
10 This documentation describes version 0.06.
10 This documentation describes version 0.07.
1111
1212 =head1 SYNOPSIS
1313
145145 Attempting to modify STDIN, STDOUT or STDERR I<during> C<<< capture >>> or C<<< tee >>> is
146146 almost certainly going to cause problems. Don't do that.
147147
148 =head2 No support for Perl 5.8.0
149
150 It's just too buggy when it comes to layers and UTF8.
151
148152 =head1 BUGS
149153
150154 Please report any bugs or feature requests using the CPAN Request Tracker.
1717
1818 plan tests => 2 + 2 * @api;
1919
20 if ( $] eq '5.008' ) {
21 BAIL_OUT("OS unsupported: Perl 5.8.0 is too buggy for Capture::Tiny");
22 }
23
2024 require_ok( 'Capture::Tiny' );
2125
2226 can_ok('Capture::Tiny', $_) for @api;
1010 use Capture::Tiny qw/capture/;
1111 use Config;
1212
13 plan tests => 4;
13 plan tests => 2;
1414
1515 my $builder = Test::More->builder;
1616 binmode($builder->failure_output, ':utf8') if $] >= 5.008;
1818 my $fd = next_fd;
1919
2020 capture {
21 system($^X, '-e', 'exit 42');
21 $? = 42;
2222 };
23 is( $? >> 8, 42, "exit code was 42" );
24
25 SKIP: {
26 skip "alarm() not available", 1
27 unless $Config{d_alarm};
28
29 capture {
30 system($^X, '-e', 'alarm 1; $now = time; 1 while (time - $now < 5)');
31 };
32 ok( $?, '$? is non-zero' );
33 is( ($^O eq 'MSWin32' ? $? >> 8 : $? & 127), sig_num('ALRM'), "caught SIGALRM" );
34 }
23 is( $?, 42, "\$\? preserved after capture ends" );
3524
3625 is( next_fd, $fd, "no file descriptors leaked" );
3726
4848 my %texts = (
4949 short => 'Hello World',
5050 multiline => 'First line\nSecond line\n',
51 ( $] < 5.008 ? () : ( unicode => 'Hi! \x{263a}\n') ),
51 ( $] lt "5.008" ? () : ( unicode => 'Hi! \x{263a}\n') ),
5252 );
5353
5454 #--------------------------------------------------------------------------#