runtime: implement a bshell_command sub-class for calling native commands
This commit is contained in:
@@ -0,0 +1,232 @@
|
|||||||
|
#include <bshell/command/command.h>
|
||||||
|
#include <bshell/command/native-command.h>
|
||||||
|
#include <bshell/format.h>
|
||||||
|
#include <bshell/runtime/pipeline.h>
|
||||||
|
#include <bshell/status.h>
|
||||||
|
#include <fx/diagnostics/process.h>
|
||||||
|
#include <fx/reflection/function.h>
|
||||||
|
#include <fx/string.h>
|
||||||
|
#include <fx/vector.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
F_REDIRECT_STDIN = 0x01u,
|
||||||
|
F_REDIRECT_STDOUT = 0x02u,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bshell_native_command_p {
|
||||||
|
int cmd_flags;
|
||||||
|
fx_string *cmd_path;
|
||||||
|
fx_stringstream *cmd_tmp;
|
||||||
|
fx_process *cmd_proc;
|
||||||
|
struct bshell_value_writer cmd_writer;
|
||||||
|
bool cmd_writer_init;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void init(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
struct bshell_native_command_p *cmd_p = priv;
|
||||||
|
cmd_p->cmd_tmp = fx_stringstream_create();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fini(fx_object *obj, void *priv)
|
||||||
|
{
|
||||||
|
struct bshell_native_command_p *cmd_p = priv;
|
||||||
|
fx_stringstream_unref(cmd_p->cmd_tmp);
|
||||||
|
fx_string_unref(cmd_p->cmd_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status start_process(bshell_native_command *cmd, int flags)
|
||||||
|
{
|
||||||
|
struct bshell_native_command_p *cmd_p
|
||||||
|
= fx_object_get_private(cmd, BSHELL_TYPE_NATIVE_COMMAND);
|
||||||
|
fx_stringstream *tmp = fx_stringstream_create();
|
||||||
|
size_t argc = bshell_command_get_arg_count(cmd);
|
||||||
|
char **argv = calloc(argc, sizeof *argv);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < argc; i++) {
|
||||||
|
const fx_value *arg = bshell_command_get_arg(cmd, i);
|
||||||
|
|
||||||
|
fx_stringstream_reset(tmp);
|
||||||
|
fx_value_to_string(arg, tmp, NULL);
|
||||||
|
argv[i] = fx_stringstream_steal(tmp);
|
||||||
|
}
|
||||||
|
fx_stringstream_unref(tmp);
|
||||||
|
|
||||||
|
fx_process *self = fx_process_get_self();
|
||||||
|
|
||||||
|
fx_process_start_info info = {
|
||||||
|
.proc_args = (const char **)argv,
|
||||||
|
.proc_args_count = argc,
|
||||||
|
.proc_file_name = fx_string_get_cstr(cmd_p->cmd_path),
|
||||||
|
.proc_environment = fx_process_get_environment(self),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (flags & F_REDIRECT_STDIN) {
|
||||||
|
info.proc_redirect_stdin = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & F_REDIRECT_STDOUT) {
|
||||||
|
info.proc_redirect_stdout = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_p->cmd_flags = flags;
|
||||||
|
cmd_p->cmd_proc = fx_process_create(&info);
|
||||||
|
|
||||||
|
fx_status status = fx_process_start(cmd_p->cmd_proc);
|
||||||
|
for (size_t i = 0; i < argc; i++) {
|
||||||
|
free(argv[i]);
|
||||||
|
}
|
||||||
|
free(argv);
|
||||||
|
|
||||||
|
if (!FX_OK(status)) {
|
||||||
|
return BSHELL_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status begin_processing(
|
||||||
|
bshell_command *cmd,
|
||||||
|
enum bshell_command_position position)
|
||||||
|
{
|
||||||
|
struct bshell_native_command_p *cmd_p
|
||||||
|
= fx_object_get_private(cmd, BSHELL_TYPE_NATIVE_COMMAND);
|
||||||
|
printf("begin processing '%s'\n", fx_string_get_cstr(cmd_p->cmd_path));
|
||||||
|
int flags = 0;
|
||||||
|
switch (position) {
|
||||||
|
case BSHELL_COMMAND_POSITION_BEGINNING:
|
||||||
|
flags = F_REDIRECT_STDOUT;
|
||||||
|
break;
|
||||||
|
case BSHELL_COMMAND_POSITION_MIDDLE:
|
||||||
|
flags = F_REDIRECT_STDIN | F_REDIRECT_STDOUT;
|
||||||
|
break;
|
||||||
|
case BSHELL_COMMAND_POSITION_END:
|
||||||
|
flags = F_REDIRECT_STDIN;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return start_process(cmd, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status process_record(
|
||||||
|
bshell_command *cmd,
|
||||||
|
bshell_pipeline *pipeline,
|
||||||
|
struct bshell_runtime *rt)
|
||||||
|
{
|
||||||
|
struct bshell_native_command_p *cmd_p
|
||||||
|
= fx_object_get_private(cmd, BSHELL_TYPE_NATIVE_COMMAND);
|
||||||
|
printf("process record '%s'\n", fx_string_get_cstr(cmd_p->cmd_path));
|
||||||
|
|
||||||
|
if (cmd_p->cmd_flags & F_REDIRECT_STDIN) {
|
||||||
|
fx_value in = bshell_pipeline_read_value(pipeline);
|
||||||
|
if (!fx_value_is_set(&in)) {
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_stream *in_stream = fx_process_get_stdin(cmd_p->cmd_proc);
|
||||||
|
if (!cmd_p->cmd_writer_init) {
|
||||||
|
bshell_value_writer_init(&cmd_p->cmd_writer, in_stream);
|
||||||
|
cmd_p->cmd_writer_init = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_value_writer_write(&cmd_p->cmd_writer, &in);
|
||||||
|
fx_value_unset(&in);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd_p->cmd_flags & F_REDIRECT_STDOUT) {
|
||||||
|
fx_stream *out_stream = fx_process_get_stdout(cmd_p->cmd_proc);
|
||||||
|
fx_stringstream_reset(cmd_p->cmd_tmp);
|
||||||
|
fx_status status
|
||||||
|
= fx_stream_read_line_s(out_stream, cmd_p->cmd_tmp);
|
||||||
|
if (!FX_OK(status)) {
|
||||||
|
/* no more data available */
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
fx_string *record = fx_string_create_from_cstr(
|
||||||
|
fx_stringstream_ptr(cmd_p->cmd_tmp));
|
||||||
|
bshell_pipeline_write_value(
|
||||||
|
pipeline,
|
||||||
|
FX_VALUE_OBJECT(record),
|
||||||
|
false);
|
||||||
|
fx_string_unref(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status end_processing(bshell_command *cmd)
|
||||||
|
{
|
||||||
|
struct bshell_native_command_p *cmd_p
|
||||||
|
= fx_object_get_private(cmd, BSHELL_TYPE_NATIVE_COMMAND);
|
||||||
|
printf("end processing '%s'\n", fx_string_get_cstr(cmd_p->cmd_path));
|
||||||
|
if (cmd_p->cmd_writer_init) {
|
||||||
|
bshell_value_writer_cleanup(&cmd_p->cmd_writer);
|
||||||
|
cmd_p->cmd_writer_init = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd_p->cmd_proc) {
|
||||||
|
fx_process_close_stdin(cmd_p->cmd_proc);
|
||||||
|
fx_process_close_stdout(cmd_p->cmd_proc);
|
||||||
|
fx_process_close_stderr(cmd_p->cmd_proc);
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
fx_process_wait(cmd_p->cmd_proc, &result);
|
||||||
|
fx_process_unref(cmd_p->cmd_proc);
|
||||||
|
cmd_p->cmd_proc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum bshell_status get_callable_name(
|
||||||
|
const bshell_native_command *cmd,
|
||||||
|
fx_string *out)
|
||||||
|
{
|
||||||
|
struct bshell_native_command_p *cmd_p
|
||||||
|
= fx_object_get_private(cmd, BSHELL_TYPE_NATIVE_COMMAND);
|
||||||
|
fx_string_append_s(out, cmd_p->cmd_path);
|
||||||
|
return BSHELL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bshell_native_command *bshell_native_command_create(const char *path)
|
||||||
|
{
|
||||||
|
bshell_native_command *out
|
||||||
|
= fx_object_create(BSHELL_TYPE_NATIVE_COMMAND);
|
||||||
|
if (!out) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bshell_native_command_p *cmd
|
||||||
|
= fx_object_get_private(out, BSHELL_TYPE_NATIVE_COMMAND);
|
||||||
|
cmd->cmd_path = fx_string_create_from_cstr(path);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_BEGIN(bshell_native_command)
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT)
|
||||||
|
FX_INTERFACE_ENTRY(to_string) = NULL;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT)
|
||||||
|
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_BEGIN(bshell_command, BSHELL_TYPE_COMMAND)
|
||||||
|
FX_INTERFACE_ENTRY(c_command_type) = "Native-Command";
|
||||||
|
FX_INTERFACE_ENTRY(c_get_callable_name) = get_callable_name;
|
||||||
|
FX_INTERFACE_ENTRY(c_begin_processing) = begin_processing;
|
||||||
|
FX_INTERFACE_ENTRY(c_process_record) = process_record;
|
||||||
|
FX_INTERFACE_ENTRY(c_end_processing) = end_processing;
|
||||||
|
FX_TYPE_VTABLE_INTERFACE_END(bshell_command, BSHELL_TYPE_COMMAND)
|
||||||
|
FX_TYPE_CLASS_END(bshell_native_command)
|
||||||
|
|
||||||
|
FX_TYPE_DEFINITION_BEGIN(bshell_native_command)
|
||||||
|
FX_TYPE_ID(0x720ede87, 0xe586, 0x495a, 0xa229, 0x1505c01b5714);
|
||||||
|
FX_TYPE_FLAGS(FX_TYPE_F_ABSTRACT);
|
||||||
|
FX_TYPE_NAME("bshell.runtime.native_command");
|
||||||
|
FX_TYPE_EXTENDS(BSHELL_TYPE_COMMAND);
|
||||||
|
FX_TYPE_CLASS(bshell_native_command_class);
|
||||||
|
FX_TYPE_INSTANCE_INIT(init);
|
||||||
|
FX_TYPE_INSTANCE_FINI(fini);
|
||||||
|
FX_TYPE_INSTANCE_PRIVATE(struct bshell_native_command_p);
|
||||||
|
FX_TYPE_DEFINITION_END(bshell_native_command)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef BSHELL_COMMAND_NATIVE_COMMAND_H_
|
||||||
|
#define BSHELL_COMMAND_NATIVE_COMMAND_H_
|
||||||
|
|
||||||
|
#include <fx/macros.h>
|
||||||
|
|
||||||
|
FX_DECLS_BEGIN;
|
||||||
|
|
||||||
|
struct bshell_runtime;
|
||||||
|
|
||||||
|
#define BSHELL_TYPE_NATIVE_COMMAND (bshell_native_command_get_type())
|
||||||
|
|
||||||
|
FX_DECLARE_TYPE(bshell_native_command);
|
||||||
|
|
||||||
|
FX_TYPE_CLASS_DECLARATION_BEGIN(bshell_native_command)
|
||||||
|
FX_TYPE_CLASS_DECLARATION_END(bshell_native_command)
|
||||||
|
|
||||||
|
extern fx_type_id bshell_native_command_get_type(void);
|
||||||
|
|
||||||
|
extern bshell_native_command *bshell_native_command_create(const char *path);
|
||||||
|
|
||||||
|
FX_DECLS_END;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -10,6 +10,12 @@ struct bshell_runtime;
|
|||||||
|
|
||||||
enum bshell_command_position;
|
enum bshell_command_position;
|
||||||
|
|
||||||
|
enum bshell_cmdcall_type {
|
||||||
|
BSHELL_CMDCALL_NONE = 0,
|
||||||
|
BSHELL_CMDCALL_CMDLET,
|
||||||
|
BSHELL_CMDCALL_NATIVE,
|
||||||
|
};
|
||||||
|
|
||||||
#define BSHELL_TYPE_CMDCALL (bshell_cmdcall_get_type())
|
#define BSHELL_TYPE_CMDCALL (bshell_cmdcall_get_type())
|
||||||
|
|
||||||
FX_DECLARE_TYPE(bshell_cmdcall);
|
FX_DECLARE_TYPE(bshell_cmdcall);
|
||||||
@@ -21,6 +27,9 @@ extern fx_type_id bshell_cmdcall_get_type(void);
|
|||||||
|
|
||||||
FX_TYPE_DEFAULT_CONSTRUCTOR(bshell_cmdcall, BSHELL_TYPE_CMDCALL);
|
FX_TYPE_DEFAULT_CONSTRUCTOR(bshell_cmdcall, BSHELL_TYPE_CMDCALL);
|
||||||
|
|
||||||
|
extern enum bshell_cmdcall_type bshell_cmdcall_get_target_type(
|
||||||
|
const bshell_cmdcall *cmdcall);
|
||||||
|
|
||||||
extern enum bshell_status bshell_cmdcall_push_arg(
|
extern enum bshell_status bshell_cmdcall_push_arg(
|
||||||
bshell_cmdcall *cmdcall,
|
bshell_cmdcall *cmdcall,
|
||||||
fx_value arg);
|
fx_value arg);
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
#include <bshell/command/alias.h>
|
#include <bshell/command/alias.h>
|
||||||
#include <bshell/command/command.h>
|
#include <bshell/command/command.h>
|
||||||
|
#include <bshell/command/native-command.h>
|
||||||
#include <bshell/runtime/cmdcall.h>
|
#include <bshell/runtime/cmdcall.h>
|
||||||
#include <bshell/runtime/pipeline.h>
|
#include <bshell/runtime/pipeline.h>
|
||||||
#include <bshell/runtime/runtime.h>
|
#include <bshell/runtime/runtime.h>
|
||||||
#include <bshell/status.h>
|
#include <bshell/status.h>
|
||||||
#include <fx/collections/array.h>
|
#include <fx/collections/array.h>
|
||||||
|
#include <fx/collections/hashtable.h>
|
||||||
|
#include <fx/diagnostics/process.h>
|
||||||
|
#include <fx/io/path.h>
|
||||||
#include <fx/reflection/assembly.h>
|
#include <fx/reflection/assembly.h>
|
||||||
#include <fx/reflection/function.h>
|
#include <fx/reflection/function.h>
|
||||||
#include <fx/reflection/type.h>
|
#include <fx/reflection/type.h>
|
||||||
|
|||||||
Reference in New Issue
Block a user