Developer-Dashboard
view release on metacpan or search on metacpan
lib/Developer/Dashboard/ActionRunner.pm view on Meta::CPAN
# Output: normalized exit status integer.
sub _wait_status_exit_code {
my ( $self, $raw_status ) = @_;
my $status = $raw_status >> 8;
$status = 128 + ( $raw_status & 127 ) if !$status && ( $raw_status & 127 );
return $status;
}
# _background_child_exit_status($command_pid)
# Polls one detached background command child and returns the supervisor exit
# code when that child has already exited.
# Input: direct child process id integer.
# Output: normalized exit status integer when reaped, otherwise undef.
sub _background_child_exit_status {
my ( $self, $command_pid ) = @_;
my $reaped = waitpid( $command_pid, WNOHANG );
return if $reaped != $command_pid;
return $self->_wait_status_exit_code($?);
}
# _reap_child_process($pid)
# Reaps one direct background action child when it has already exited so
# callers do not observe wrapper zombies during lifecycle checks.
# Input: process id integer.
# Output: boolean true when waitpid reaped the child.
sub _reap_child_process {
my ( $self, $pid ) = @_;
return 0 if !defined $pid || $pid !~ /^\d+$/ || $pid < 1;
my $waited = waitpid( $pid, WNOHANG );
return $waited == $pid ? 1 : 0;
}
# _read_process_state($pid)
# Reads the current process state so zombie background action wrappers can be
# treated as stopped even when signal 0 still succeeds.
# Input: process id integer.
# Output: one-letter process state string or undef.
sub _read_process_state {
my ( $self, $pid ) = @_;
my $proc = "/proc/$pid/stat";
if ( -r $proc ) {
open my $fh, '<', $proc or return; # uncoverable branch true
local $/;
my $stat = scalar <$fh>;
if ( defined $stat ) { # uncoverable branch false
return $1 if $stat =~ /^\d+\s+\(.*\)\s+(\S)/s; # uncoverable branch false
}
}
my ( $stdout, undef, $exit_code ) = capture {
system 'ps', '-o', 'stat=', '-p', $pid;
return $? >> 8;
};
return if $exit_code != 0;
$stdout =~ s/^\s+|\s+$//g if defined $stdout;
return if !defined $stdout || $stdout eq '';
return substr( $stdout, 0, 1 );
}
# _pid_is_running($pid)
# Determines whether one background action pid is still alive after
# opportunistic reaping and zombie-state checks.
# Input: process id integer.
# Output: boolean true when the process still appears to be running.
sub _pid_is_running {
my ( $self, $pid ) = @_;
return 0 if !defined $pid || $pid !~ /^\d+$/ || $pid < 1;
return 0 if $self->_reap_child_process($pid);
return 0 if ( $self->_read_process_state($pid) || '' ) eq 'Z';
return kill( 0, $pid ) ? 1 : 0;
}
# _run_builtin_action(%args)
# Executes one of the built-in safe dashboard actions.
# Input: action hash, page document, and optional params hash.
# Output: structured result hash reference.
sub _run_builtin_action {
my ( $self, %args ) = @_;
my $action = $args{action};
my $page = $args{page};
my $id = $action->{builtin} || $action->{id} || '';
if ( $id eq 'page.source' ) {
return {
kind => 'builtin',
content_type => 'text/plain; charset=utf-8',
body => $page->canonical_instruction,
};
}
if ( $id eq 'page.state' ) {
return {
kind => 'builtin',
content_type => 'application/json; charset=utf-8',
body => json_encode( $page->as_hash->{state} || {} ),
};
}
if ( $id eq 'paths.list' ) {
return {
kind => 'builtin',
content_type => 'application/json; charset=utf-8',
body => json_encode(
{
home => $self->{paths}->home,
runtime => $self->{paths}->runtime_root,
dashboards => $self->{paths}->dashboards_root,
config => $self->{paths}->config_root,
cli => $self->{paths}->cli_root,
}
),
};
}
die "Unsupported builtin action '$id'\n";
}
# _is_action_trusted(%args)
# Determines whether a page action may execute for the given source.
# Input: page document, action hash, and source string.
# Output: boolean trust flag.
( run in 1.120 second using v1.01-cache-2.11-cpan-14f38c9f855 )