PAX

 view release on metacpan or  search on metacpan

lib/PAX/StandaloneRuntime.pm  view on Meta::CPAN

            );
        };
        return _install_sub_impl($package, $name, $sub->{prototype}, $impl);
    }

    if (($sub->{op} // '') eq 'skill_dispatcher_dispatch') {
        my $command_spec_method = $sub->{command_spec_method} // die 'compiled sub command-spec method missing';
        my $execute_hooks_method = $sub->{execute_hooks_method} // die 'compiled sub execute-hooks method missing';
        my $skill_layers_method = $sub->{skill_layers_method} // die 'compiled sub skill-layers method missing';
        my $skill_env_method = $sub->{skill_env_method} // die 'compiled sub skill-env method missing';
        $impl = sub {
            my ($self, $skill_name, $command, @args) = @_;
            return { error => 'Missing skill name' } if !$skill_name;
            return { error => 'Missing command name' } if !$command;
            my $skill_path = $self->{manager}->get_skill_path($skill_name, include_disabled => 1);
            my $suggest = __PAX_RUNTIME_LEGACY_NAMESPACE__::CLI::Suggest->new(paths => $self->{manager}{paths}, manager => $self->{manager});
            return { error => $suggest->unknown_skill_command_message($skill_name, $command) } if !$skill_path;
            return { error => $suggest->unknown_skill_command_message($skill_name, $command) } if !$self->{manager}->is_enabled($skill_name);
            my $command_spec = _code_for($command_spec_method)->($self, $skill_name, $command);
            my $cmd_path = $command_spec ? $command_spec->{cmd_path} : undef;
            my $command_skill_path = $command_spec ? $command_spec->{skill_path} : undef;
            return { error => $suggest->unknown_skill_command_message($skill_name, $command) } if !$cmd_path;
            my $hook_result = _code_for($execute_hooks_method)->($self, $skill_name, $command, @args);
            return $hook_result if $hook_result->{error};
            my @skill_layers = $command_spec ? @{ $command_spec->{skill_layers} || [] } : _code_for($skill_layers_method)->($self, $skill_name);
            my %env = _code_for($skill_env_method)->(
                $self,
                skill_name   => $skill_name,
                skill_path   => $command_skill_path || $skill_path,
                skill_layers => \@skill_layers,
                command      => $command_spec ? $command_spec->{command_name} : $command,
                result_state => $hook_result->{result_state} || {},
            );
            my @command = __PAX_RUNTIME_LEGACY_NAMESPACE__::Platform::command_argv_for_path($cmd_path);
            my ($stdout, $stderr, $exit) = Capture::Tiny::capture {
                local %ENV = (%ENV, %env);
                __PAX_RUNTIME_LEGACY_NAMESPACE__::Runtime::Result::set_current($hook_result->{result_state} || {});
                if (ref($hook_result->{last_result}) eq 'HASH' && %{ $hook_result->{last_result} }) {
                    __PAX_RUNTIME_LEGACY_NAMESPACE__::Runtime::Result::set_last_result($hook_result->{last_result});
                } else {
                    __PAX_RUNTIME_LEGACY_NAMESPACE__::Runtime::Result::clear_last_result();
                }
                __PAX_RUNTIME_LEGACY_NAMESPACE__::EnvLoader->load_runtime_layers(paths => $self->{manager}{paths});
                __PAX_RUNTIME_LEGACY_NAMESPACE__::EnvLoader->load_skill_layers(skill_layers => \@skill_layers);
                system(@command, @args);
            };
            my $hook_stdout = join '', map { defined $_->{stdout} ? $_->{stdout} : '' } values %{ $hook_result->{hooks} || {} };
            my $hook_stderr = join '', map { defined $_->{stderr} ? $_->{stderr} : '' } values %{ $hook_result->{hooks} || {} };
            return {
                stdout    => $hook_stdout . $stdout,
                stderr    => $hook_stderr . $stderr,
                exit_code => $exit,
                hooks     => $hook_result->{hooks} || {},
            };
        };
        return _install_sub_impl($package, $name, $sub->{prototype}, $impl);
    }

    if (($sub->{op} // '') eq 'skill_dispatcher_exec_command') {
        my $command_spec_method = $sub->{command_spec_method} // die 'compiled sub command-spec method missing';
        my $execute_hooks_streaming_method = $sub->{execute_hooks_streaming_method} // die 'compiled sub execute-hooks-streaming method missing';
        my $skill_layers_method = $sub->{skill_layers_method} // die 'compiled sub skill-layers method missing';
        my $skill_env_method = $sub->{skill_env_method} // die 'compiled sub skill-env method missing';
        my $exec_resolved_method = $sub->{exec_resolved_method} // die 'compiled sub exec-resolved method missing';
        $impl = sub {
            my ($self, $skill_name, $command, @args) = @_;
            return { error => 'Missing skill name' } if !$skill_name;
            return { error => 'Missing command name' } if !$command;
            my $skill_path = $self->{manager}->get_skill_path($skill_name, include_disabled => 1);
            my $suggest = __PAX_RUNTIME_LEGACY_NAMESPACE__::CLI::Suggest->new(paths => $self->{manager}{paths}, manager => $self->{manager});
            return { error => $suggest->unknown_skill_command_message($skill_name, $command) } if !$skill_path;
            return { error => $suggest->unknown_skill_command_message($skill_name, $command) } if !$self->{manager}->is_enabled($skill_name);
            my $command_spec = _code_for($command_spec_method)->($self, $skill_name, $command);
            my $cmd_path = $command_spec ? $command_spec->{cmd_path} : undef;
            my $command_skill_path = $command_spec ? $command_spec->{skill_path} : undef;
            return { error => $suggest->unknown_skill_command_message($skill_name, $command) } if !$cmd_path;
            my @skill_layers = $command_spec ? @{ $command_spec->{skill_layers} || [] } : _code_for($skill_layers_method)->($self, $skill_name);
            my $hook_result = _code_for($execute_hooks_streaming_method)->($self, $skill_name, $command_spec ? $command_spec->{command_name} : $command, \@skill_layers, @args);
            return $hook_result if $hook_result->{error};
            my %env = _code_for($skill_env_method)->(
                $self,
                skill_name   => $skill_name,
                skill_path   => $command_skill_path || $skill_path,
                skill_layers => \@skill_layers,
                command      => $command_spec ? $command_spec->{command_name} : $command,
                result_state => $hook_result->{result_state} || {},
            );
            my @command = __PAX_RUNTIME_LEGACY_NAMESPACE__::Platform::command_argv_for_path($cmd_path);
            %ENV = (%ENV, %env);
            __PAX_RUNTIME_LEGACY_NAMESPACE__::Runtime::Result::set_current($hook_result->{result_state} || {});
            if (ref($hook_result->{last_result}) eq 'HASH' && %{ $hook_result->{last_result} }) {
                __PAX_RUNTIME_LEGACY_NAMESPACE__::Runtime::Result::set_last_result($hook_result->{last_result});
            } else {
                __PAX_RUNTIME_LEGACY_NAMESPACE__::Runtime::Result::clear_last_result();
            }
            __PAX_RUNTIME_LEGACY_NAMESPACE__::EnvLoader->load_runtime_layers(paths => $self->{manager}{paths});
            __PAX_RUNTIME_LEGACY_NAMESPACE__::EnvLoader->load_skill_layers(skill_layers => \@skill_layers);
            return _code_for($exec_resolved_method)->($self, $cmd_path, \@command, \@args);
        };
        return _install_sub_impl($package, $name, $sub->{prototype}, $impl);
    }

    if (($sub->{op} // '') eq 'skill_dispatcher_execute_hooks') {
        my $command_spec_method = $sub->{command_spec_method} // die 'compiled sub command-spec method missing';
        my $skill_layers_method = $sub->{skill_layers_method} // die 'compiled sub skill-layers method missing';
        my $skill_env_method = $sub->{skill_env_method} // die 'compiled sub skill-env method missing';
        $impl = sub {
            my ($self, $skill_name, $command, @args) = @_;
            return { hooks => {}, result_state => {} } if !$skill_name || !$command;
            my $skill_path = $self->{manager}->get_skill_path($skill_name, include_disabled => 1);
            return { hooks => {}, result_state => {} } if !$skill_path;
            return { hooks => {}, result_state => {} } if !$self->{manager}->is_enabled($skill_name);
            my $command_spec = _code_for($command_spec_method)->($self, $skill_name, $command);
            my @skill_layers = $command_spec ? @{ $command_spec->{skill_layers} || [] } : _code_for($skill_layers_method)->($self, $skill_name);
            return { hooks => {}, result_state => {} } if !@skill_layers;
            my $resolved_command = $command_spec ? $command_spec->{command_name} : $command;
            my %results;
            my $last_result = {};
            for my $layer_path (@skill_layers) {
                my $hooks_dir = File::Spec->catdir($layer_path, 'cli', "$resolved_command.d");
                next if !-d $hooks_dir;
                opendir(my $dh, $hooks_dir) or die "Unable to read $hooks_dir: $!";
                for my $entry (sort grep { $_ ne '.' && $_ ne '..' } readdir($dh)) {
                    my $hook_path = File::Spec->catfile($hooks_dir, $entry);
                    next unless __PAX_RUNTIME_LEGACY_NAMESPACE__::Platform::is_runnable_file($hook_path);
                    my %env = _code_for($skill_env_method)->(
                        $self,
                        skill_name   => $skill_name,
                        skill_path   => $layer_path,
                        skill_layers => \@skill_layers,
                        command      => $resolved_command,
                        result_state => \%results,
                    );
                    my @command = __PAX_RUNTIME_LEGACY_NAMESPACE__::Platform::command_argv_for_path($hook_path);
                    my ($stdout, $stderr, $exit) = Capture::Tiny::capture {
                        local %ENV = (%ENV, %env);
                        __PAX_RUNTIME_LEGACY_NAMESPACE__::Runtime::Result::set_current(\%results);
                        if (%{$last_result}) {
                            __PAX_RUNTIME_LEGACY_NAMESPACE__::Runtime::Result::set_last_result($last_result);
                        } else {
                            __PAX_RUNTIME_LEGACY_NAMESPACE__::Runtime::Result::clear_last_result();
                        }
                        __PAX_RUNTIME_LEGACY_NAMESPACE__::EnvLoader->load_runtime_layers(paths => $self->{manager}{paths});
                        __PAX_RUNTIME_LEGACY_NAMESPACE__::EnvLoader->load_skill_layers(skill_layers => \@skill_layers);
                        system(@command, @args);
                    };
                    my $result_key = $entry;
                    if (exists $results{$entry}) {
                        my $leaf = File::Basename::basename(File::Basename::dirname($hook_path));
                        $result_key = $leaf . '/' . File::Basename::basename($hook_path);
                    }
                    $results{$result_key} = { stdout => $stdout, stderr => $stderr, exit_code => $exit };
                    $last_result = { file => $hook_path, exit => $exit, STDOUT => $stdout, STDERR => $stderr };
                }
                closedir($dh);
            }
            my %payload = ( hooks => \%results, result_state => \%results );
            $payload{last_result} = $last_result if %{$last_result};
            return \%payload;
        };
        return _install_sub_impl($package, $name, $sub->{prototype}, $impl);
    }

    if (($sub->{op} // '') eq 'skill_dispatcher_execute_hooks_streaming') {
        my $arrayref_or_empty_method = $sub->{arrayref_or_empty_method} // die 'compiled sub arrayref-or-empty method missing';
        my $skill_env_method = $sub->{skill_env_method} // die 'compiled sub skill-env method missing';
        my $run_child_streaming_method = $sub->{run_child_streaming_method} // die 'compiled sub child-streaming method missing';
        $impl = sub {
            my ($self, $skill_name, $command, $skill_layers, @args) = @_;
            return { hooks => {}, result_state => {} } if !$skill_name || !$command;
            my @skill_layers = @{ _code_for($arrayref_or_empty_method)->($self, $skill_layers) };
            return { hooks => {}, result_state => {} } if !@skill_layers;
            my %results;
            my $last_result = {};
            for my $layer_path (@skill_layers) {
                my $hooks_dir = File::Spec->catdir($layer_path, 'cli', "$command.d");
                next if !-d $hooks_dir;
                opendir(my $dh, $hooks_dir) or die "Unable to read $hooks_dir: $!";
                for my $entry (sort grep { $_ ne '.' && $_ ne '..' } readdir($dh)) {
                    my $hook_path = File::Spec->catfile($hooks_dir, $entry);
                    next unless __PAX_RUNTIME_LEGACY_NAMESPACE__::Platform::is_runnable_file($hook_path);
                    my %env = _code_for($skill_env_method)->(
                        $self,
                        skill_name   => $skill_name,
                        skill_path   => $layer_path,
                        skill_layers => \@skill_layers,
                        command      => $command,
                        result_state => \%results,
                    );
                    my @hook_command = __PAX_RUNTIME_LEGACY_NAMESPACE__::Platform::command_argv_for_path($hook_path);
                    my $run = _code_for($run_child_streaming_method)->(
                        $self,
                        command      => \@hook_command,
                        args         => \@args,
                        env          => \%env,
                        skill_layers => \@skill_layers,
                        result_state => \%results,
                        last_result  => $last_result,
                        stdin_mode   => 'null',
                    );
                    my $result_key = $entry;
                    if (exists $results{$entry}) {
                        my $leaf = File::Basename::basename(File::Basename::dirname($hook_path));
                        $result_key = $leaf . '/' . File::Basename::basename($hook_path);
                    }
                    $results{$result_key} = {
                        stdout    => $run->{stdout},
                        stderr    => $run->{stderr},
                        exit_code => $run->{exit_code},
                    };
                    $last_result = {
                        file   => $hook_path,
                        exit   => $run->{exit_code},
                        STDOUT => $run->{stdout},
                        STDERR => $run->{stderr},
                    };
                }
                closedir($dh);
            }
            my %payload = ( hooks => \%results, result_state => \%results );
            $payload{last_result} = $last_result if %{$last_result};
            return \%payload;
        };
        return _install_sub_impl($package, $name, $sub->{prototype}, $impl);
    }

    if (($sub->{op} // '') eq 'skill_dispatcher_run_child_command_streaming') {
        my $arrayref_or_empty_method = $sub->{arrayref_or_empty_method} // die 'compiled sub arrayref-or-empty method missing';
        my $hashref_or_empty_method = $sub->{hashref_or_empty_method} // die 'compiled sub hashref-or-empty method missing';
        my $defined_or_default_method = $sub->{defined_or_default_method} // die 'compiled sub defined-or-default method missing';
        $impl = sub {
            my ($self, %args) = @_;
            my @command = @{ _code_for($arrayref_or_empty_method)->($self, $args{command}) };
            my @argv = @{ _code_for($arrayref_or_empty_method)->($self, $args{args}) };
            my %env = %{ _code_for($hashref_or_empty_method)->($self, $args{env}) };
            my @skill_layers = @{ _code_for($arrayref_or_empty_method)->($self, $args{skill_layers}) };
            my $result_state = _code_for($hashref_or_empty_method)->($self, $args{result_state});
            my $last_result = $args{last_result};
            my $stdin_mode = _code_for($defined_or_default_method)->($self, $args{stdin_mode}, 'inherit');
            my $stdin_spec = '<&STDIN';
            my $stdin_fh;
            if ($stdin_mode eq 'null') {
                open $stdin_fh, '<', File::Spec->devnull() or die "Unable to open " . File::Spec->devnull() . " for streaming skill hook stdin: $!";
                $stdin_spec = '<&' . fileno($stdin_fh);
            }
            my $stderr = Symbol::gensym();
            my $stdout;
            my ($stdout_text, $stderr_text) = ('', '');
            my $pid;
            {
                local %ENV = (%ENV, %env);
                __PAX_RUNTIME_LEGACY_NAMESPACE__::Runtime::Result::set_current($result_state);
                if (ref($last_result) eq 'HASH' && %{$last_result}) {
                    __PAX_RUNTIME_LEGACY_NAMESPACE__::Runtime::Result::set_last_result($last_result);
                } else {
                    __PAX_RUNTIME_LEGACY_NAMESPACE__::Runtime::Result::clear_last_result();
                }
                __PAX_RUNTIME_LEGACY_NAMESPACE__::EnvLoader->load_runtime_layers(paths => $self->{manager}{paths});
                __PAX_RUNTIME_LEGACY_NAMESPACE__::EnvLoader->load_skill_layers(skill_layers => \@skill_layers);
                $pid = IPC::Open3::open3($stdin_spec, $stdout, $stderr, @command, @argv);
            }
            close $stdin_fh if $stdin_fh;
            my $selector = IO::Select->new($stdout, $stderr);
            my $stdout_fd = fileno($stdout);
            my $stderr_fd = fileno($stderr);
            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;
                        $stdout_text .= $buffer;
                        next;
                    }
                    if (fileno($fh) == $stderr_fd) {
                        print STDERR $buffer;
                        $stderr_text .= $buffer;
                        next;
                    }
                }
            }
            waitpid($pid, 0);
            return { stdout => $stdout_text, stderr => $stderr_text, exit_code => $? >> 8 };
        };
        return _install_sub_impl($package, $name, $sub->{prototype}, $impl);
    }

    if (($sub->{op} // '') eq 'skill_dispatcher_exec_resolved_command') {
        my $arrayref_or_empty_method = $sub->{arrayref_or_empty_method} // die 'compiled sub arrayref-or-empty method missing';
        my $exec_replacement_method = $sub->{exec_replacement_method} // die 'compiled sub exec-replacement method missing';
        $impl = sub {
            my ($self, $cmd_path, $command, $args) = @_;
            my @command = @{ _code_for($arrayref_or_empty_method)->($self, $command) };
            my @args = @{ _code_for($arrayref_or_empty_method)->($self, $args) };
            my $error = _code_for($exec_replacement_method)->($self, \@command, \@args);



( run in 0.551 second using v1.01-cache-2.11-cpan-140bd7fdf52 )