]> git.ipfire.org Git - thirdparty/public-inbox.git/commitdiff
git: support an error tmpfile for stashing stderr output
authorEric Wong <e@80x24.org>
Thu, 3 Mar 2016 03:12:12 +0000 (03:12 +0000)
committerEric Wong <e@80x24.org>
Tue, 5 Apr 2016 18:58:27 +0000 (18:58 +0000)
This should allow us to avoid polluting stderr output when
HTTP clients inevitably request broken revisions.

lib/PublicInbox/Git.pm
t/git.t

index bd945007fdad4ae7efdc4d746b144226641c42b2..2b6782a75828b4ca5778058279338d72840701e8 100644 (file)
@@ -12,6 +12,8 @@ use warnings;
 use POSIX qw(dup2);
 require IO::Handle;
 use PublicInbox::Spawn qw(spawn popen_rd);
+use IO::File;
+use Fcntl qw(:seek);
 
 # Documentation/SubmittingPatches recommends 12 (Linux v4.4)
 my $abbrev = `git config core.abbrev` || 12;
@@ -20,7 +22,25 @@ sub abbrev { "--abbrev=$abbrev" }
 
 sub new {
        my ($class, $git_dir) = @_;
-       bless { git_dir => $git_dir }, $class
+       bless { git_dir => $git_dir, err => IO::File->new_tmpfile }, $class
+}
+
+sub err_begin ($) {
+       my $err = $_[0]->{err};
+       sysseek($err, 0, SEEK_SET) or die "sysseek failed: $!";
+       truncate($err, 0) or die "truncate failed: $!";
+       my $ret = fileno($err);
+       defined $ret or die "fileno failed: $!";
+       $ret;
+}
+
+sub err ($) {
+       my $err = $_[0]->{err};
+       sysseek($err, 0, SEEK_SET) or die "sysseek failed: $!";
+       defined(sysread($err, my $buf, -s $err)) or die "sysread failed: $!";
+       sysseek($err, 0, SEEK_SET) or die "sysseek failed: $!";
+       truncate($err, 0) or die "truncate failed: $!";
+       $buf;
 }
 
 sub _bidi_pipe {
diff --git a/t/git.t b/t/git.t
index e09a4d0113c1100d2434d093c8de80960d276a5d..e7a3c9ea9d28accf6b6bae29ab63a9064bb8347c 100644 (file)
--- a/t/git.t
+++ b/t/git.t
@@ -141,27 +141,25 @@ if (1) {
 
 {
        my $git = PublicInbox::Git->new($dir);
-       open my $tmperr, '>&', \*STDERR or die "dup stderr failed: $!\n";
 
-       open STDERR, '>', '/dev/null' or die "redirect stderr failed: $!\n";
-       my $err = $git->popen(qw(cat-file blob non-existent));
+       my $err = $git->popen([qw(cat-file blob non-existent)], undef,
+                               { 2 => $git->err_begin });
        my @out = <$err>;
        my $close_ret = close $err;
        my $close_err = $?;
-       open STDERR, '>&', $tmperr or die "restore stderr failed: $!\n";
        is(join('', @out), '', 'no output on stdout on error');
        isnt($close_err, 0, 'close set $? on bad command');
        ok(!$close_ret, 'close returned error on bad command');
+       isnt($git->err, '', 'got stderr output');
 
-       open STDERR, '>', '/dev/null' or die "redirect stderr failed: $!\n";
-       $err = $git->popen(qw(tag -l));
+       $err = $git->popen([qw(tag -l)], undef, { 2 => $git->err_begin });
        @out = <$err>;
        $close_ret = close $err;
        $close_err = $?;
-       open STDERR, '>&', $tmperr or die "restore stderr failed: $!\n";
        is(join('', @out), '', 'no output on stdout on error');
        ok(!$close_err, 'close clobbered $? on empty output');
        ok($close_ret, 'close returned error on empty output');
+       is($git->err, '', 'no stderr output');
 }
 
 done_testing();