7 triggerexec - description
11 triggerexec [I<EVENT> I<ACTION> [I<EVENT> I<ACTION> [...]]] [--] I<COMMAND> [I<ARGS>]
15 Run I<COMMAND> and execute specific actions depending on
18 Supported I<EVENT> events:
22 =item B<stdout>:I<PATTERN>
24 =item B<stderr>:I<PATTERN>
26 Match I<PATTERN> regex pattern to B<stdout>/B<stderr> line-wise.
30 Supported I<ACTION> actions:
36 Evaluate perl expression in triggerexec(1)'s own context.
38 B<$COMMAND_PID> is the I<COMMAND>'s PID.
39 B<$PARAM> is a hash ref containing event parameters,
40 for example B<$PARAM->{line}> is the text triggered the action - if applicable (B<stdout:>/B<stderr:> events).
53 use constant
{ STAT_DEV
=>0, STAT_INODE
=>1, STAT_PERM
=>2, STAT_NLINKS
=>3, STAT_UID
=>4, STAT_GID
=>5, STAT_RDEV
=>6, STAT_SIZE
=>7, STAT_ATIME
=>8, STAT_MTIME
=>9, STAT_CTIME
=>10, STAT_BLOCKSIZE
=>11, STAT_BLOCKS
=>12, };
54 use Cwd qw
/getcwd realpath/;
57 use DateTime
::Format
::Strptime
;
58 use Encode qw
/decode encode decode_utf8 encode_utf8/;
60 use Fcntl qw
/:flock :seek F_GETFL F_SETFL O_NONBLOCK F_GETFD F_SETFD FD_CLOEXEC/;
62 use File
::Temp qw
/tempfile/;
63 use Getopt
::Long qw
/:config no_ignore_case no_bundling no_getopt_compat no_auto_abbrev require_order/;
64 use IPC
::Run qw
/run start finish/;
65 use List
::MoreUtils qw
/all any none/;
68 no if ($] >= 5.018), 'warnings' => 'experimental::smartmatch';
72 'help' => sub { pod2usage
(-exitval
=>0, -verbose
=>99); },
73 '<>' => sub { unshift @ARGV, @_[0]; die '!FINISH'; },
74 ) or pod2usage
(-exitval
=>2, -verbose
=>99);
78 while(my $arg = shift @ARGV)
85 while(my $param = shift @Param)
87 my $action = shift @Param;
88 push @Trigger, {event
=>$param, action
=>$action,};
95 if($action =~ /^perl:(.*)$/)
100 # else {} TODO validate action expressions at start
103 sub process_output_line
105 my $stream_name = shift;
108 for my $trig (@Trigger)
110 if($trig->{event
} =~ /^(stdout|stderr):(.*)/)
112 my $event_stream_name = $1;
114 if($event_stream_name eq $stream_name)
116 if($line =~ /$pattern/)
118 do_action
($trig->{action
}, {line
=>$line});
122 # else {} # TODO validate event expressions at start
128 my $buffer_ref = shift;
129 my $last_call = shift;
130 my $func_ref = shift;
131 my $args_ref = shift;
135 my $eolpos = index $$buffer_ref, "\n";
137 $eolpos++; # include the trailing linefeed
138 my $line = substr($$buffer_ref, 0, $eolpos);
139 $func_ref->(@
$args_ref, $line);
140 $$buffer_ref = substr($$buffer_ref, $eolpos);
142 if($last_call and $$buffer_ref ne '')
144 # process the last incomplete line, if any
145 $func_ref->(@
$args_ref, $$buffer_ref);
152 $stdout_buffer .= $chunk;
153 process_buffer
(\
$stdout_buffer, 0, \
&process_output_line
, ['stdout']);
160 $stderr_buffer .= $chunk;
161 process_buffer
(\
$stderr_buffer, 0, \
&process_output_line
, ['stderr']);
168 $ipc = start
[@ARGV], \
*STDIN
, \
&read_stdout
, \
&read_stderr
;
169 $COMMAND_PID = $ipc->{KIDS
}->[0]->{PID
};
173 process_buffer
(\
$stdout_buffer, 1, \
&process_output_line
, ['stdout']);
174 process_buffer
(\
$stderr_buffer, 1, \
&process_output_line
, ['stderr']);
176 $exitcode = WEXITSTATUS
($status);
177 $exitcode = 128 + WTERMSIG
($status) if WIFSIGNALED
($status);