Hi,

Please find attached a patch that addresses the issues raised in RT #9793 
regarding the 
absense of build and test output in CPAN Tester reports.

I test exclusively on CPANPLUS and with the wide adoption of Module::Build, I 
am starting to
be pestered daily by CPAN authors for more information regarding FAIL reports 
that have been
sent.

I have taken code from IO::CaptureOutput and wrapped that around the method 
calls for 
'build', 'test' and 'install' calls in ->create() and ->install().

I've tested against Andreas' CPAN-Test-Dummy-Perl5-Build-Fails distribution:

Before hackery:

http://www.nntp.perl.org/group/perl.cpan.testers/2008/09/msg2303214.html

After hackery:

http://www.nntp.perl.org/group/perl.cpan.testers/2008/09/msg2303378.html

Many thanks in advance,

-- 
Chris Williams
aka BinGOs
PGP ID 0x4658671F
http://www.gumbynet.org.uk
==========================
--- Build.pm.orig       2008-09-26 15:25:17.000000000 +0100
+++ Build.pm    2008-09-26 15:41:13.000000000 +0100
@@ -29,7 +29,7 @@
 
 local $Params::Check::VERBOSE = 1;
 
-$VERSION = '0.05';
+$VERSION = '0.06_02';
 
 =pod
 
@@ -509,7 +509,10 @@
             last RUN;
         }
 
-        eval { $mb->dispatch('build', %buildflags) };
+        my $build_output;
+        eval { _capture ( sub { $mb->dispatch('build', %buildflags) }, 
\$build_output, \$build_output ) };
+        msg( $build_output, $verbose );
+
         if( $@ ) {
             error(loc("Could not run '%1': %2", 'Build', "$@"));
             $dist->status->build(0);
@@ -527,7 +530,9 @@
         ### M::B/Test::Harness bug. Reported as #9793 with patch 
         ### against 0.2607 on 26/1/2005
         unless( $skiptest ) {
-            eval { $mb->dispatch('test', %buildflags) };
+            my $test_output;
+            eval { _capture ( sub { $mb->dispatch('test', %buildflags) }, 
\$test_output, \$test_output ) };
+            msg( $test_output, $verbose );
             if( $@ ) {
                 error(loc("Could not run '%1': %2", 'Build test', "$@"));
 
@@ -535,10 +540,13 @@
                 ### send success on force...
                 $test_fail++;
 
-                unless($force) {
-                    $dist->status->test(0);
-                    $fail++; last RUN;
+                if( !$force and !$cb->_callbacks->proceed_on_test_failure->(
+                                      $self, $@ ) 
+                ) {
+                    $dist->status->test(0);                 
+                    $fail++; last RUN;     
                 }
+                
             } else {
                 $dist->status->test(1);
             }
@@ -637,7 +645,9 @@
         ### don't worry about loading the right version of M::B anymore
         ### the 'new_from_context' already added the 'right' path to
         ### M::B at the top of the build.pl
-        my $cmd     = [$perl, BUILD->($dir), 'install', $buildflags];
+        ### On VMS, flags need to be quoted
+        my $flag    = ON_VMS ? '"install"' : 'install';
+        my $cmd     = [$perl, BUILD->($dir), $flag, $buildflags];
         my $sudo    = $conf->get_program('sudo');
         unshift @$cmd, $sudo if $sudo;
 
@@ -653,7 +663,9 @@
     } else {
         my %buildflags = $dist->_buildflags_as_hash($buildflags);
 
-        eval { $mb->dispatch('install', %buildflags) };
+        my $install_output;
+        eval { _capture ( sub { $mb->dispatch('install', %buildflags) }, 
\$install_output, \$install_output ) };
+        msg( $install_output, $verbose );
         if( $@ ) {
             error(loc("Could not run '%1': %2", 'Build install', "$@"));
             $fail++;
@@ -739,6 +751,131 @@
     return $distdir;
 }    
 
+sub _capture (&@) { ## no critic
+    my ($code, $output, $error, $output_file, $error_file) = @_;
+
+
+    # if either $output or $error are defined, then we need a variable for 
+    # results; otherwise we only capture to files and don't waste memory
+    if ( defined $output || defined $error ) {
+      for ($output, $error) {
+          $_ = \do { my $s; $s = ''} unless ref $_;
+          $$_ = '' if $_ != \undef && !defined($$_);
+      }
+    }
+
+    # merge if same refs for $output and $error or if both are undef -- 
+    # i.e. capture \&foo, undef, undef, $merged_file
+    # this means capturing into separate files *requires* at least one
+    # capture variable
+    my $should_merge = 
+      (defined $error && defined $output && $output == $error) || 
+      ( !defined $output && !defined $error ) || 
+      0;
+
+    my ($capture_out, $capture_err);
+
+    # undef means capture anonymously; anything other than \undef means 
+    # capture to that ref; \undef means skip capture
+    if ( !defined $output || $output != \undef ) { 
+        $capture_out = CPANPLUS::Dist::Build::_proxy->new(
+            'STDOUT', $output, undef, $output_file
+        );
+    }
+    if ( !defined $error || $error != \undef ) { 
+        my $capture_err = CPANPLUS::Dist::Build::_proxy->new(
+            'STDERR', $error, ($should_merge ? 'STDOUT' : undef), $error_file
+        );
+    }
+
+    # now that output capture is setup, call the subroutine
+    # results get read when IO::CaptureOutput::_proxy objects go out of scope
+    &$code();
+}
+
+package CPANPLUS::Dist::Build::_proxy;
+use File::Temp 'tempfile';
+use File::Basename qw/basename/;
+use Symbol qw/gensym qualify qualify_to_ref/;
+use Carp;
+
+sub _is_wperl { $^O eq 'MSWin32' && basename($^X) eq 'wperl.exe' }
+
+sub new {
+    my $class = shift;
+    my ($orig_fh, $capture_var, $merge_fh, $capture_file) = @_;
+    $orig_fh       = qualify($orig_fh);         # e.g. main::STDOUT
+    my $fhref = qualify_to_ref($orig_fh);  # e.g. \*STDOUT
+
+    # Duplicate the filehandle
+    my $saved_fh;
+    {
+        no strict 'refs'; ## no critic - needed for 5.005
+        if ( defined fileno($orig_fh) && ! _is_wperl() ) {
+            $saved_fh = gensym;
+            open $saved_fh, ">&$orig_fh" or croak "Can't redirect <$orig_fh> - 
$!";
+        }
+    }
+
+    # Create replacement filehandle if not merging
+    my ($newio_fh, $newio_file);
+    if ( ! $merge_fh ) {
+        $newio_fh = gensym;
+        if ($capture_file) {
+            $newio_file = $capture_file;
+        } else {
+            (undef, $newio_file) = tempfile;
+        }
+        open $newio_fh, "+>$newio_file" or croak "Can't write temp file for 
$orig_fh - $!";
+    }
+    else {
+        $newio_fh = qualify($merge_fh);
+    }
+
+    # Redirect (or merge)
+    {
+        no strict 'refs'; ## no critic -- needed for 5.005
+        open $fhref, ">&".fileno($newio_fh) or croak "Can't redirect $orig_fh 
- $!";
+    }
+
+    bless [$$, $orig_fh, $saved_fh, $capture_var, $newio_fh, $newio_file, 
$capture_file], $class;
+}
+
+sub DESTROY {
+    my $self = shift;
+
+    my ($pid, $orig_fh, $saved_fh, $capture_var, $newio_fh, 
+      $newio_file, $capture_file) = @$self;
+    return unless $pid eq $$; # only cleanup in the process that is capturing
+
+    # restore the original filehandle
+    my $fh_ref = Symbol::qualify_to_ref($orig_fh);
+    select((select ($fh_ref), $|=1)[0]);
+    if (defined $saved_fh) {
+        open $fh_ref, ">&". fileno($saved_fh) or croak "Can't restore $orig_fh 
- $!";
+    }
+    else {
+        close $fh_ref;
+    }
+
+    # transfer captured data to the scalar reference if we didn't merge
+    # $newio_file is undef if this file handle is merged to another
+    if (ref $capture_var && $newio_file) {
+        # some versions of perl complain about reading from fd 1 or 2
+        # which could happen if STDOUT and STDERR were closed when $newio
+        # was opened, so we just squelch warnings here and continue
+        local $^W; 
+        seek $newio_fh, 0, 0;
+        $$capture_var = do {local $/; <$newio_fh>};
+    }
+    close $newio_fh if $newio_file;
+
+    # Cleanup
+    return unless defined $newio_file && -e $newio_file;
+    return if $capture_file; # the "temp" file was explicitly named
+    unlink $newio_file or carp "Couldn't remove temp file '$newio_file' - $!";
+}
+
 =head1 KNOWN ISSUES
 
 Below are some of the known issues with Module::Build, that we hope 
@@ -783,6 +920,7 @@
 
 1;
 
+
 # Local variables:
 # c-indentation-style: bsd
 # c-basic-offset: 4

Attachment: pgpaMg5m99LuM.pgp
Description: PGP signature

Reply via email to