Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
use v6;
BEGIN {
class X::Shell::CommandNotFound is Exception {
has $.cmd;
method message { 'The shell command ⟨' ~ $.cmd ~ '⟩ was not found.' }
}
class X::Shell::NoAccess is Exception {
has $.cmd;
method message { 'The shell command ⟨' ~ $.cmd ~ '⟩ is not accessible.' }
}
package Shell {}
sub shell-command(IO() $cmd-path) {
my $cmd-name = $cmd-path.basename;
X::Shell::CommandNotFound.new(:cmd($cmd-name)).throw if !$cmd-path.e;
X::Shell::NoAccess.new(:cmd($cmd-name)).throw if !$cmd-path.x;
my $Exception = Metamodel::ClassHOW.new_type(:name($cmd-name));
$Exception.HOW.add_parent($Exception, Exception);
$Exception.HOW.add_attribute($Exception, Attribute.new(:name<$.exitcode>, :type(Int), :package($Exception), :has_accessor));
$Exception.HOW.add_attribute($Exception, Attribute.new(:name<$.stderr>, :type(Str), :package($Exception), :has_accessor));
$Exception.HOW.add_method($Exception, 'message', my method { 'Shell command ⟨' ~ self.^name ~ '⟩ finished with non-zero exitcode of ' ~ self.exitcode ~ '.' } );
$Exception.HOW.compose($Exception);
X::Shell::<ls> := $Exception;
Shell::«$cmd-name» := sub (|c) {
my $proc = run $cmd-name, |c, :out, :err;
if $proc.exitcode != 0 { # this makes the exception resumeable
my $e = X::Shell::«$cmd-name»;
$e.new(:exitcode($proc.exitcode), :stderr($proc.err.slurp)).throw
} else {
$proc.out.slurp
}
}
}
my \e = shell-command('/bin/ls');
}
Shell::ls('/home/not there', '-l');
Shell::ls('/home/dex').lines.tail(10).say;
CATCH {
when X::Shell::ls { warn .stderr, .backtrace; .resume }
when X::Shell { warn .^name, ': ', .message; .resume }
}
# say $e.^attributes;
# dd $e.new(:exitcode(1)).message;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.