more fixes for external command error handling
[scpubgit/System-Introspector.git] / lib / System / Introspector / Util.pm
CommitLineData
f79a227c 1use strictures 1;
2
3package System::Introspector::Util;
4use Exporter 'import';
db5ba31f 5use IPC::Run qw( run );
9c3e454c 6use IPC::Open2;
7use File::Spec;
8use Scalar::Util qw( blessed );
23b83532 9use Capture::Tiny qw( capture_stderr );
f79a227c 10
11our @EXPORT_OK = qw(
12 handle_from_command
db5ba31f 13 handle_from_file
db5ba31f 14 output_from_command
15 output_from_file
91c60940 16 lines_from_command
17 files_from_dir
f79a227c 18 transform_exceptions
19);
20
c23ab973 21do {
65e569ee 22 package System::Introspector::_Exception;
c23ab973 23 use Moo;
24 has message => (is => 'ro');
25};
26
65e569ee 27sub fail { die System::Introspector::_Exception->new(message => shift) }
28sub is_report_exception { ref(shift) eq 'System::Introspector::_Exception' }
c23ab973 29
db5ba31f 30sub files_from_dir {
31 my ($dir) = @_;
32 my $dh;
33 opendir $dh, $dir
c23ab973 34 or fail "Unable to read directory $dir: $!";
db5ba31f 35 my @files;
36 while (defined( my $item = readdir $dh )) {
37 next if -d "$dir/$item";
38 push @files, $item;
39 }
40 return @files;
41}
42
f79a227c 43sub transform_exceptions (&) {
44 my ($code) = @_;
f79a227c 45 my $result = eval { $code->() };
c23ab973 46 if (my $error = $@) {
47 return { error => $error->message }
48 if is_report_exception $error;
49 die $@;
50 }
f79a227c 51 return $result;
52}
53
db5ba31f 54sub output_from_command {
55 my ($command, $in) = @_;
56 $in = ''
57 unless defined $in;
58 my ($out, $err) = ('', '');
59 my $ok = run($command, \$in, \$out, \$err);
60 return $out, $err, $ok
61 if wantarray;
62 $command = join ' ', @$command
63 if ref $command;
c23ab973 64 fail "Error running command ($command): $err"
db5ba31f 65 unless $ok;
66 return $out;
67}
68
91c60940 69sub lines_from_command {
70 my ($command) = @_;
71 my $output = output_from_command $command;
72 chomp $output;
73 return split m{\n}, $output;
74}
75
f79a227c 76sub handle_from_command {
77 my ($command) = @_;
9c3e454c 78 my $pipe;
79 local $@;
80 my $ok = eval {
81 my $out;
23b83532 82 my $child_pid;
83 my @lines;
84 my ($err) = capture_stderr {
85 $child_pid = open2($out, File::Spec->devnull, $command);
86 @lines = <$out>;
87 close $out;
88 waitpid $child_pid, 0;
89 };
9c3e454c 90 my $content = join '', @lines;
91 my $status = $? >> 8;
23b83532 92 $err = "Unknown error"
93 unless defined $err;
94 fail "Command error ($command): $err\n"
95 if $status;
9c3e454c 96 open $pipe, '<', \$content;
97 1;
98 };
99 unless ($ok) {
100 my $err = $@;
101 die $err
102 if blessed($err) and $err->isa('System::Introspector::_Exception');
103 fail "Error from command '$command': $err";
104 }
f79a227c 105 return $pipe;
106}
107
db5ba31f 108sub handle_from_file {
109 my ($file) = @_;
110 open my $fh, '<', $file
c23ab973 111 or fail "Unable to read $file: $!";
db5ba31f 112 return $fh;
113}
114
115sub output_from_file {
116 my ($file) = @_;
117 my $fh = handle_from_file $file;
118 return <$fh>
119 if wantarray;
120 return do { local $/; <$fh> };
121}
122
f79a227c 1231;