Friends:
Parrot::Configure::Step holds an internal subroutine called
_run_command() whose task is to execute a system call on a command
supplied as an argument. The command supplied is typically a small
C-executable created on the fly as a particular configuration step runs.
I've been staring at _run_command() quite a bit in the course of trying
to write unit tests for those configuration steps, and I'm unhappy with
what I see. What I don't like is all the manipulation of globally
scoped filehandles done for the purpose of logging the output of the
C-executable. The manipulation is two-fold:
1. Opening handles to STDOUT and STDERR to log the output and errors of
the C-executable. The log files live (briefly) at the top level of the
Parrot hierarchy.
2. Duplicating those handles (following tricks described in 'perldoc -f
open') so that if verbosity was requested, the output of those files can
be printed on STDOUT or STDERR.
sub _run_command {
...
# Save the old filehandles; we must not let them get closed.
open my $OLDOUT, '>&', \*STDOUT or die "Can't save stdout" if $out;
open my $OLDERR, '>&', \*STDERR or die "Can't save stderr" if $err;
open STDOUT, '>', $out or die "Can't redirect stdout" if $out;
# See 'Obscure Open Tricks' in perlopentut
open STDERR, ">$err" or die "Can't redirect stderr" if $err; ##
no critic InputOutput::ProhibitTwoArgOpen
system $command;
my $exit_code = $? >> 8;
close STDOUT or die "Can't close stdout" if $out;
close STDERR or die "Can't close stderr" if $err;
open STDOUT, '>&', $OLDOUT or die "Can't restore stdout" if $out;
open STDERR, '>&', $OLDERR or die "Can't restore stderr" if $err;
...
}
The problem with having global filehandles STDOUT and STDERR being
manipulated quite deep into a program is that it stymies you from doing
anything with those handles higher up at the surface of your program. I
found this out the hard way over this past weekend when I was trying to
respond to bug reports from Andy D. on some of my tests. For testing
purposes -- in particular, to work around a peculiarity in Test::Harness
-- I wanted to capture STDOUT by tieing. But despite many different
approaches, I could not do so correctly.
While the particular reason why _run_command() was problematic for me is
not of earth-shaking consequence, I can't help but wonder: Is there any
other way we could achieve _run_command()'s objectives without its
internal manipulation of global filehandles?
Thank you very much.
kid51