package System::Introspector::Util;
use Exporter 'import';
use IPC::Run qw( run );
+use IPC::Open2;
+use File::Spec;
+use Scalar::Util qw( blessed );
+use Capture::Tiny qw( capture_stderr );
our @EXPORT_OK = qw(
handle_from_command
handle_from_file
- files_from_dir
output_from_command
output_from_file
+ lines_from_command
+ files_from_dir
transform_exceptions
);
+do {
+ package System::Introspector::_Exception;
+ use Moo;
+ has message => (is => 'ro');
+};
+
+sub fail { die System::Introspector::_Exception->new(message => shift) }
+sub is_report_exception { ref(shift) eq 'System::Introspector::_Exception' }
+
sub files_from_dir {
my ($dir) = @_;
my $dh;
opendir $dh, $dir
- or die "Unable to read directory $dir: $!\n";
+ or fail "Unable to read directory $dir: $!";
my @files;
while (defined( my $item = readdir $dh )) {
next if -d "$dir/$item";
sub transform_exceptions (&) {
my ($code) = @_;
- local $@;
my $result = eval { $code->() };
- return { error => "$@" }
- if $@;
+ if (my $error = $@) {
+ return { __error__ => $error->message }
+ if is_report_exception $error;
+ die $@;
+ }
return $result;
}
if wantarray;
$command = join ' ', @$command
if ref $command;
- die "Error running command ($command): $err\n"
+ fail "Error running command ($command): $err"
unless $ok;
return $out;
}
+sub lines_from_command {
+ my ($command) = @_;
+ my $output = output_from_command $command;
+ chomp $output;
+ return split m{\n}, $output;
+}
+
sub handle_from_command {
my ($command) = @_;
- open my $pipe, '-|', $command
- or die "Unable to read from command '$command': $!\n";
+ my $pipe;
+ local $@;
+ my $ok = eval {
+ my $out;
+ my $child_pid;
+ my @lines;
+ my ($err) = capture_stderr {
+ $child_pid = open2($out, File::Spec->devnull, $command);
+ @lines = <$out>;
+ close $out;
+ waitpid $child_pid, 0;
+ };
+ my $content = join '', @lines;
+ my $status = $? >> 8;
+ $err = "Unknown error"
+ unless defined $err;
+ fail "Command error ($command): $err\n"
+ if $status;
+ open $pipe, '<', \$content;
+ 1;
+ };
+ unless ($ok) {
+ my $err = $@;
+ die $err
+ if blessed($err) and $err->isa('System::Introspector::_Exception');
+ fail "Error from command '$command': $err";
+ }
return $pipe;
}
sub handle_from_file {
my ($file) = @_;
open my $fh, '<', $file
- or die "Unable to read $file: $!\n";
+ or fail "Unable to read $file: $!";
return $fh;
}