On Fri, 03 Feb 2017 18:27:34 -0800, comdog wrote:
> While trying to work around #125757 (using :out
> makes the Proc object always return zero, I ran
> into a different problem. I was writing test code
> to check what a program does in cases where it
> should exit with a non-zero status.
>
> The docs for IO::Handle::close say only:
>
> Will close a previously opened filehandle.
>
> But other close methods mention using a LEAVE
> phaser to avoid exceptions. I end up with kludgey
> code like this to fight against Perl 6 thinking it
> knows better than I do when something failed:
>
> subtest {
> my $proc = run $*EXECUTABLE, $program, '-k', :err;
> my $message = try { $proc.err.slurp-rest };
> LEAVE { quietly { $proc.err.close } }
>
> like $message, rx:i/invalid/, 'Invalid option warns';
> is $proc.exitcode, 2, 'exit code';
> }, "{$program} exits with false value with unknown switch";
>
> Now, indeed this returned a non-zero exit status.
> But, it did exactly what I wanted it to. This
> isn't a failure in my code and it shouldn't be
> exceptional.
>
> Beyond that, there are many programs that use a
> non-zero exit to mean something that isn't
> failure. grep(1), for instance, uses 1 to mean no
> lines matched. And so on. Perl 6 doesn't know
> these, and I don't think it should make decisions
> at this level.
>
> I wouldn't mind the ability to throw an exception
> if Proc was told to do that (say, like
> :raise-exception similar to DBI's RaiseError).
> But, it's easy enough for the programmer to make
> this call on their own.
Thank you for the report. However, I'm going to reject this ticket, as
the described issue is just a misunderstanding and does not exist:
- "IO::Handle::close shouldn't decide what's a failure"
- It doesn't. The explosion you show is due to a sunk Proc object.
- "The docs for IO::Handle::close say"
- Those are the wrong docs. The code you show calls .close on IO::Pipe.
While IO::Pipe is IO::Handle, it provides its own close method[^1]
that returns the Pipe's Proc object
- "But other close methods mention using a LEAVE phaser to avoid exceptions"
- The now-reworded[^2] docs meant you could use LEAVE phaser to close
a handle on scope leave, regardless of whether it's left normally or via
a thrown exception (in the latter case, a .close at the end of the block
wouldn't be reached). This isn't about *avoiding* any exceptions.
- "close shouldn't decide what's a failure"
- It doesn't. Your .close returns the Proc object, which throws when sunk,
if the process had non-zero status. There are no exceptions or failures
involved in .close itself, so to avoid the explosion simply ensure the
Proc doesn't get sunk
- "I end up with kludgey code"
- You can close the Pipe via an arg given to .slurp (or .slurp-rest
if you're on older Rakudos; will be deprecated in 6.d and removed in 6.e).
And since the .close doesn't throw and we don't sink any Procs, no
explosions happen and the code isn't kludgy:
use Test;
my $program = ('-e', 'die "invalid"', '--');
subtest {
with run :err, $*EXECUTABLE, |$program, '-y' {
like .err.slurp(:close), rx:i/invalid/, 'Invalid option warns';
is .exitcode, 1, 'exit code';
}
}, "{$program} exits with false value with unknown switch";
[1] https://docs.perl6.org/type/IO::Pipe#method_close
[2] https://github.com/perl6/doc/commit/2387ce3518aa29fb198e6c5bb77991f3b307f091
-- IO grant