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

Reply via email to