about summary refs log tree commit homepage
diff options
context:
space:
mode:
-rw-r--r--lib/PublicInbox/Git.pm22
-rw-r--r--t/git.t12
2 files changed, 26 insertions, 8 deletions
diff --git a/lib/PublicInbox/Git.pm b/lib/PublicInbox/Git.pm
index bd945007..2b6782a7 100644
--- a/lib/PublicInbox/Git.pm
+++ b/lib/PublicInbox/Git.pm
@@ -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 e09a4d01..e7a3c9ea 100644
--- 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();