I was surprised when I noticed "local *STDIN = *STDIN" worked, but that was with Perl 5.28.1. Unfortunately, we can't rely on users or testers having such a recent Perl version. Even worse, it was silently a no-op on Perl 5.24.1 on Debian 9.x. So, save the original handle and manually restore the original via open, when we're done. --- lib/PublicInbox/TestCommon.pm | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/lib/PublicInbox/TestCommon.pm b/lib/PublicInbox/TestCommon.pm index 85cda031..d9b21337 100644 --- a/lib/PublicInbox/TestCommon.pm +++ b/lib/PublicInbox/TestCommon.pm @@ -67,12 +67,25 @@ sub key2script ($) { 'blib/script/'.$key; } +my @io_mode = ([ *STDIN{IO}, '<&' ], [ *STDOUT{IO}, '>&' ], [ *STDERR{IO}, '>&' ]); sub _prepare_redirects ($) { my ($fhref) = @_; - my @x = ([ \*STDIN, '<&' ], [ \*STDOUT, '>&' ], [ \*STDERR, '>&' ]); - for (my $fd = 0; $fd <= $#x; $fd++) { + my $orig_io = []; + for (my $fd = 0; $fd <= $#io_mode; $fd++) { my $fh = $fhref->[$fd] or next; - my ($oldfh, $mode) = @{$x[$fd]}; + my ($oldfh, $mode) = @{$io_mode[$fd]}; + open my $orig, $mode, $oldfh or die "$$oldfh $mode stash: $!"; + $orig_io->[$fd] = $orig; + open $oldfh, $mode, $fh or die "$$oldfh $mode redirect: $!"; + } + $orig_io; +} + +sub _undo_redirects ($) { + my ($orig_io) = @_; + for (my $fd = 0; $fd <= $#io_mode; $fd++) { + my $fh = $orig_io->[$fd] or next; + my ($oldfh, $mode) = @{$io_mode[$fd]}; open $oldfh, $mode, $fh or die "$$oldfh $mode redirect: $!"; } } @@ -174,14 +187,14 @@ sub run_script ($;$$) { $r == $pid or die "waitpid: expected $pid, got $r"; } } else { # localize and run everything in the same process: - local *STDIN = *STDIN; - local *STDOUT = *STDOUT; - local *STDERR = *STDERR; + # note: "local *STDIN = *STDIN;" and so forth did not work in + # old versions of perl local %ENV = $env ? (%ENV, %$env) : %ENV; local %SIG = %SIG; local $0 = join(' ', @$cmd); - _prepare_redirects($fhref); + my $orig_io = _prepare_redirects($fhref); _run_sub($sub, $key, \@argv); + _undo_redirects($orig_io); } # slurp the redirects back into user-supplied strings -- unsubscribe: meta+unsubscr...@public-inbox.org archive: https://public-inbox.org/meta/