Developer-Dashboard
view release on metacpan or search on metacpan
bin/dashboard view on Meta::CPAN
pod2usage(
-exitval => 0,
-verbose => 99,
);
}
if ( $cmd eq 'version' ) {
require Developer::Dashboard;
print $Developer::Dashboard::VERSION, "\n";
exit 0;
}
if ( my $helper_path = _builtin_helper_path($cmd) ) {
_exec_switchboard_command( $helper_path, @ARGV );
}
if ( my $custom_path = _custom_command_path($cmd) ) {
_exec_switchboard_command( $custom_path, @ARGV );
}
if ( my ( $skill_name, $skill_command ) = _skill_dotted_command_parts($cmd) ) {
my $helper_path = _builtin_helper_path('skills');
_exec_switchboard_command( $helper_path, '_exec', $skill_name, $skill_command, @ARGV );
}
if ( $cmd ne '' ) {
print STDERR Developer::Dashboard::CLI::Suggest->new()->unknown_command_message($cmd);
}
pod2usage(
-exitval => 1,
-verbose => 99,
-sections => [qw(NAME SYNOPSIS)],
);
# _prime_command_result_env($cmd, @argv)
# Runs executable per-command hook files from every DD-OOP-LAYERS CLI root and
# exposes their captured output through RESULT JSON for later hooks and the
# final command target.
# Input: top-level command name plus the remaining argv list.
# Output: true value after hook execution completes.
sub _prime_command_result_env {
my ( $cmd, @argv ) = @_;
Developer::Dashboard::Runtime::Result::clear_current();
Developer::Dashboard::Runtime::Result::clear_last_result();
$ENV{DEVELOPER_DASHBOARD_COMMAND} = $cmd if defined $cmd && $cmd ne '';
return 1 if !defined $cmd || $cmd eq '';
my @hook_roots = _command_hook_roots($cmd);
return 1 if !@hook_roots;
my $stream = $cmd eq 'doctor' ? 0 : 1;
my %results;
for my $hook_root (@hook_roots) {
opendir my $dh, $hook_root or next;
for my $entry ( sort grep { $_ ne '.' && $_ ne '..' } readdir $dh ) {
my $path = File::Spec->catfile( $hook_root, $entry );
next if !is_runnable_file($path);
next if $entry eq 'run';
my $hook_result = _run_command_hook_streaming(
$path,
stream => $stream,
argv => \@argv,
);
my $result_key = exists $results{$entry} ? _command_hook_result_key($path) : $entry;
$results{$result_key} = {
stdout => $hook_result->{stdout},
stderr => $hook_result->{stderr},
};
$results{$result_key}{exit_code} = $hook_result->{exit_code} if defined $hook_result->{exit_code};
Developer::Dashboard::Runtime::Result::set_current( \%results );
Developer::Dashboard::Runtime::Result::set_last_result(
{
file => $path,
exit => $hook_result->{exit_code},
STDOUT => $hook_result->{stdout},
STDERR => $hook_result->{stderr},
}
);
return 1 if Developer::Dashboard::Runtime::Result::stop_requested( $hook_result->{stderr} );
}
closedir $dh;
}
if ( !%results ) {
Developer::Dashboard::Runtime::Result::clear_current();
Developer::Dashboard::Runtime::Result::clear_last_result();
}
return 1;
}
# _load_runtime_env()
# Loads the participating DD-OOP-LAYERS plain-directory and runtime-layer env
# files into the current process before command resolution and helper exec.
# Input: none.
# Output: true value.
sub _load_runtime_env {
require Developer::Dashboard::PathRegistry;
Developer::Dashboard::EnvAudit->clear();
my $paths = Developer::Dashboard::PathRegistry->new(
home => $ENV{HOME},
workspace_roots => [],
project_roots => [],
);
Developer::Dashboard::EnvLoader->load_runtime_layers( paths => $paths );
return 1;
}
# _run_command_hook_streaming($path, %args)
# Executes one hook file, streams its output live, and captures stdout/stderr so
# later hooks and the final command can inspect RESULT JSON.
# Input: executable hook path plus an optional stream flag and argv array ref.
# Output: hash reference containing stdout, stderr, and exit_code.
sub _run_command_hook_streaming {
my ( $path, %args ) = @_;
my $stream = exists $args{stream} ? $args{stream} : 1;
my @argv = @{ $args{argv} || [] };
open my $stdin, '<', File::Spec->devnull() or die "Unable to open " . File::Spec->devnull() . " for hook stdin: $!";
my $stderr = gensym();
my $stdout;
my @command = command_argv_for_path($path);
my $pid = open3( $stdin, $stdout, $stderr, @command, @argv );
close $stdin;
my $selector = IO::Select->new( $stdout, $stderr );
my $stdout_fd = fileno($stdout);
my $stderr_fd = fileno($stderr);
my $stdout_text = '';
my $stderr_text = '';
local $| = 1;
STDOUT->autoflush(1);
STDERR->autoflush(1);
while ( my @ready = $selector->can_read ) {
for my $fh (@ready) {
my $buffer = '';
my $read = sysread( $fh, $buffer, 8192 );
if ( !defined $read || $read == 0 ) {
$selector->remove($fh);
close $fh;
next;
}
if ( fileno($fh) == $stdout_fd ) {
print STDOUT $buffer if $stream;
$stdout_text .= $buffer;
next;
}
if ( fileno($fh) == $stderr_fd ) {
print STDERR $buffer if $stream;
$stderr_text .= $buffer;
next;
}
}
}
waitpid( $pid, 0 );
return {
stdout => $stdout_text,
stderr => $stderr_text,
exit_code => $? >> 8,
};
}
# _command_hook_roots($cmd)
# Resolves every per-command hook directory across DD-OOP-LAYERS from home to
# the deepest participating layer.
# Input: top-level command name string.
# Output: ordered list of hook directory paths.
sub _command_hook_roots {
my ($cmd) = @_;
return () if !defined $cmd || $cmd eq '';
my @roots;
( run in 0.628 second using v1.01-cache-2.11-cpan-39bf76dae61 )