gitweb/lib - capture output directly to cache entry file
[git/jnareb-git.git] / gitweb / lib / GitwebCache / Capture / Simple.pm
blob74dd24048e76a8e9e1a0644cd9ace3a569ec2ff6
1 # gitweb - simple web interface to track changes in git repositories
3 # (C) 2010, Jakub Narebski <jnareb@gmail.com>
5 # This program is licensed under the GPLv2
8 # Simple output capturing via redirecting STDOUT to in-memory file.
11 # This is the same mechanism that Capture::Tiny uses, only simpler;
12 # we don't capture STDERR at all, we don't tee, we don't support
13 # capturing output of external commands.
15 package GitwebCache::Capture::Simple;
17 use strict;
18 use warnings;
20 use PerlIO;
21 use Symbol qw(qualify_to_ref);
23 # Constructor
24 sub new {
25 my $class = shift;
27 my $self = {};
28 $self = bless($self, $class);
30 return $self;
33 sub capture {
34 my ($self, $code) = @_;
36 $self->capture_start(@_[2..$#_]); # pass rest of params
37 $code->();
38 return $self->capture_stop();
41 # ----------------------------------------------------------------------
43 # Start capturing data (STDOUT)
44 sub capture_start {
45 my $self = shift;
46 my $to = shift;
48 # save copy of real STDOUT via duplicating it
49 my @layers = PerlIO::get_layers(\*STDOUT);
50 open $self->{'orig_stdout'}, ">&", \*STDOUT
51 or die "Couldn't dup STDOUT for capture: $!";
53 # close STDOUT, so that it isn't used anymode (to have it fd0)
54 close STDOUT;
56 if (defined $to) {
57 $self->{'to'} = $to;
58 if (defined fileno(qualify_to_ref($to))) {
59 # if $to is filehandle, redirect
60 open STDOUT, '>&', fileno($to);
61 } elsif (! ref($to)) {
62 # if $to is name of file, open it
63 open STDOUT, '>', $to;
66 } else {
67 # reopen STDOUT as in-memory file
68 $self->{'data'} = '';
69 unless (open STDOUT, '>', \$self->{'data'}) {
70 open STDOUT, '>&', fileno($self->{'orig_stdout'});
71 die "Couldn't reopen STDOUT as in-memory file for capture: $!";
74 _relayer(\*STDOUT, \@layers);
76 # started capturing
77 $self->{'capturing'} = 1;
80 # Stop capturing data (required for die_error)
81 sub capture_stop {
82 my $self = shift;
84 # return if we didn't start capturing
85 return unless delete $self->{'capturing'};
87 # close in-memory file, and restore original STDOUT
88 my @layers = PerlIO::get_layers(\*STDOUT);
89 close STDOUT;
90 open STDOUT, '>&', fileno($self->{'orig_stdout'});
91 _relayer(\*STDOUT, \@layers);
93 return exists $self->{'to'} ? $self->{'to'} : $self->{'data'};
96 # taken from Capture::Tiny by David Golden, Apache License 2.0
97 # with debugging stripped out, and added filtering out 'scalar' layer
98 sub _relayer {
99 my ($fh, $layers) = @_;
101 my %seen = ( unix => 1, perlio => 1, scalar => 1 ); # filter these out
102 my @unique = grep { !$seen{$_}++ } @$layers;
104 binmode($fh, join(":", ":raw", @unique));
109 __END__
110 # end of package GitwebCache::Capture::Simple