Change commands interface so it can either run or get result
This commit is contained in:
parent
31af868b5d
commit
454cb1ce1d
@ -16,7 +16,7 @@
|
|||||||
#define READ_END 0
|
#define READ_END 0
|
||||||
#define WRITE_END 1
|
#define WRITE_END 1
|
||||||
int run_command(Text_t exe, Array_t arg_array, Table_t env_table,
|
int run_command(Text_t exe, Array_t arg_array, Table_t env_table,
|
||||||
Array_t input_bytes, Array_t *output_bytes, Array_t *error_bytes)
|
OptionalArray_t input_bytes, Array_t *output_bytes, Array_t *error_bytes)
|
||||||
{
|
{
|
||||||
pthread_testcancel();
|
pthread_testcancel();
|
||||||
|
|
||||||
@ -36,18 +36,24 @@ int run_command(Text_t exe, Array_t arg_array, Table_t env_table,
|
|||||||
posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK);
|
posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK);
|
||||||
|
|
||||||
int child_inpipe[2], child_outpipe[2], child_errpipe[2];
|
int child_inpipe[2], child_outpipe[2], child_errpipe[2];
|
||||||
pipe(child_inpipe);
|
if (input_bytes.length >= 0) pipe(child_inpipe);
|
||||||
pipe(child_outpipe);
|
if (output_bytes) pipe(child_outpipe);
|
||||||
pipe(child_errpipe);
|
if (error_bytes) pipe(child_errpipe);
|
||||||
|
|
||||||
posix_spawn_file_actions_t actions;
|
posix_spawn_file_actions_t actions;
|
||||||
posix_spawn_file_actions_init(&actions);
|
posix_spawn_file_actions_init(&actions);
|
||||||
posix_spawn_file_actions_adddup2(&actions, child_inpipe[READ_END], STDIN_FILENO);
|
if (input_bytes.length >= 0) {
|
||||||
posix_spawn_file_actions_addclose(&actions, child_inpipe[WRITE_END]);
|
posix_spawn_file_actions_adddup2(&actions, child_inpipe[READ_END], STDIN_FILENO);
|
||||||
posix_spawn_file_actions_adddup2(&actions, child_outpipe[WRITE_END], STDOUT_FILENO);
|
posix_spawn_file_actions_addclose(&actions, child_inpipe[WRITE_END]);
|
||||||
posix_spawn_file_actions_addclose(&actions, child_outpipe[READ_END]);
|
}
|
||||||
posix_spawn_file_actions_adddup2(&actions, child_errpipe[WRITE_END], STDERR_FILENO);
|
if (output_bytes) {
|
||||||
posix_spawn_file_actions_addclose(&actions, child_errpipe[READ_END]);
|
posix_spawn_file_actions_adddup2(&actions, child_outpipe[WRITE_END], STDOUT_FILENO);
|
||||||
|
posix_spawn_file_actions_addclose(&actions, child_outpipe[READ_END]);
|
||||||
|
}
|
||||||
|
if (error_bytes) {
|
||||||
|
posix_spawn_file_actions_adddup2(&actions, child_errpipe[WRITE_END], STDERR_FILENO);
|
||||||
|
posix_spawn_file_actions_addclose(&actions, child_errpipe[READ_END]);
|
||||||
|
}
|
||||||
|
|
||||||
const char *exe_str = Text$as_c_string(exe);
|
const char *exe_str = Text$as_c_string(exe);
|
||||||
|
|
||||||
@ -85,15 +91,14 @@ int run_command(Text_t exe, Array_t arg_array, Table_t env_table,
|
|||||||
posix_spawnattr_destroy(&attr);
|
posix_spawnattr_destroy(&attr);
|
||||||
posix_spawn_file_actions_destroy(&actions);
|
posix_spawn_file_actions_destroy(&actions);
|
||||||
|
|
||||||
close(child_inpipe[READ_END]);
|
if (input_bytes.length >= 0) close(child_inpipe[READ_END]);
|
||||||
close(child_outpipe[WRITE_END]);
|
if (output_bytes) close(child_outpipe[WRITE_END]);
|
||||||
close(child_errpipe[WRITE_END]);
|
if (error_bytes) close(child_errpipe[WRITE_END]);
|
||||||
|
|
||||||
struct pollfd pollfds[3] = {
|
struct pollfd pollfds[3] = {};
|
||||||
{.fd=child_inpipe[WRITE_END], .events=POLLOUT},
|
if (input_bytes.length >= 0) pollfds[0] = (struct pollfd){.fd=child_inpipe[WRITE_END], .events=POLLOUT};
|
||||||
{.fd=child_outpipe[WRITE_END], .events=POLLIN},
|
if (output_bytes) pollfds[1] = (struct pollfd){.fd=child_outpipe[WRITE_END], .events=POLLIN};
|
||||||
{.fd=child_errpipe[WRITE_END], .events=POLLIN},
|
if (error_bytes) pollfds[2] = (struct pollfd){.fd=child_errpipe[WRITE_END], .events=POLLIN};
|
||||||
};
|
|
||||||
|
|
||||||
if (input_bytes.length > 0 && input_bytes.stride != 1)
|
if (input_bytes.length > 0 && input_bytes.stride != 1)
|
||||||
Array$compact(&input_bytes, sizeof(char));
|
Array$compact(&input_bytes, sizeof(char));
|
||||||
@ -102,10 +107,10 @@ int run_command(Text_t exe, Array_t arg_array, Table_t env_table,
|
|||||||
if (error_bytes)
|
if (error_bytes)
|
||||||
*error_bytes = (Array_t){.atomic=1, .stride=1, .length=0};
|
*error_bytes = (Array_t){.atomic=1, .stride=1, .length=0};
|
||||||
|
|
||||||
for (;;) {
|
while (input_bytes.length > 0 || output_bytes || error_bytes) {
|
||||||
(void)poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), -1); // Wait for data or readiness
|
(void)poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), -1); // Wait for data or readiness
|
||||||
bool did_something = false;
|
bool did_something = false;
|
||||||
if (pollfds[0].revents) {
|
if (input_bytes.length >= 0 && pollfds[0].revents) {
|
||||||
if (input_bytes.length > 0) {
|
if (input_bytes.length > 0) {
|
||||||
ssize_t written = write(child_inpipe[WRITE_END], input_bytes.data, (size_t)input_bytes.length);
|
ssize_t written = write(child_inpipe[WRITE_END], input_bytes.data, (size_t)input_bytes.length);
|
||||||
if (written > 0) {
|
if (written > 0) {
|
||||||
@ -123,13 +128,13 @@ int run_command(Text_t exe, Array_t arg_array, Table_t env_table,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
char buf[256];
|
char buf[256];
|
||||||
if (pollfds[1].revents) {
|
if (output_bytes && pollfds[1].revents) {
|
||||||
ssize_t n = read(child_outpipe[READ_END], buf, sizeof(buf));
|
ssize_t n = read(child_outpipe[READ_END], buf, sizeof(buf));
|
||||||
did_something = did_something || (n > 0);
|
did_something = did_something || (n > 0);
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
close(child_outpipe[READ_END]);
|
close(child_outpipe[READ_END]);
|
||||||
pollfds[1].events = 0;
|
pollfds[1].events = 0;
|
||||||
} else if (n > 0 && output_bytes) {
|
} else if (n > 0) {
|
||||||
if (output_bytes->free < n) {
|
if (output_bytes->free < n) {
|
||||||
output_bytes->data = GC_REALLOC(output_bytes->data, (size_t)(output_bytes->length + n));
|
output_bytes->data = GC_REALLOC(output_bytes->data, (size_t)(output_bytes->length + n));
|
||||||
output_bytes->free = 0;
|
output_bytes->free = 0;
|
||||||
@ -138,13 +143,13 @@ int run_command(Text_t exe, Array_t arg_array, Table_t env_table,
|
|||||||
output_bytes->length += n;
|
output_bytes->length += n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pollfds[2].revents) {
|
if (error_bytes && pollfds[2].revents) {
|
||||||
ssize_t n = read(child_errpipe[READ_END], buf, sizeof(buf));
|
ssize_t n = read(child_errpipe[READ_END], buf, sizeof(buf));
|
||||||
did_something = did_something || (n > 0);
|
did_something = did_something || (n > 0);
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
close(child_errpipe[READ_END]);
|
close(child_errpipe[READ_END]);
|
||||||
pollfds[2].events = 0;
|
pollfds[2].events = 0;
|
||||||
} else if (n > 0 && error_bytes) {
|
} else if (n > 0) {
|
||||||
if (error_bytes->free < n) {
|
if (error_bytes->free < n) {
|
||||||
error_bytes->data = GC_REALLOC(error_bytes->data, (size_t)(error_bytes->length + n));
|
error_bytes->data = GC_REALLOC(error_bytes->data, (size_t)(error_bytes->length + n));
|
||||||
error_bytes->free = 0;
|
error_bytes->free = 0;
|
||||||
@ -166,6 +171,10 @@ int run_command(Text_t exe, Array_t arg_array, Table_t env_table,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (input_bytes.length >= 0) close(child_inpipe[WRITE_END]);
|
||||||
|
if (output_bytes) close(child_outpipe[READ_END]);
|
||||||
|
if (error_bytes) close(child_errpipe[READ_END]);
|
||||||
|
|
||||||
sigaction(SIGINT, &oldint, NULL);
|
sigaction(SIGINT, &oldint, NULL);
|
||||||
sigaction(SIGQUIT, &oldquit, NULL);
|
sigaction(SIGQUIT, &oldquit, NULL);
|
||||||
sigprocmask(SIG_SETMASK, &old, NULL);
|
sigprocmask(SIG_SETMASK, &old, NULL);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
use ./commands.c
|
use ./commands.c
|
||||||
use libunistring.so
|
use libunistring.so
|
||||||
|
|
||||||
extern run_command:func(exe:Text, args:[Text], env:{Text,Text}, input:[Byte], output:&[Byte], error:&[Byte] -> Int32)
|
extern run_command:func(exe:Text, args:[Text], env:{Text,Text}, input:[Byte]?, output:&[Byte]?, error:&[Byte]? -> Int32)
|
||||||
extern command_by_line:func(exe:Text, args:[Text], env:{Text,Text} -> func(->Text?)?)
|
extern command_by_line:func(exe:Text, args:[Text], env:{Text,Text} -> func(->Text?)?)
|
||||||
|
|
||||||
enum ExitType(Exited(status:Int32), Signaled(signal:Int32), Failed)
|
enum ExitType(Exited(status:Int32), Signaled(signal:Int32), Failed)
|
||||||
@ -43,7 +43,7 @@ struct Command(command:Text, args=[:Text], env={:Text,Text}):
|
|||||||
func from_path(path:Path, args=[:Text], env={:Text,Text} -> Command):
|
func from_path(path:Path, args=[:Text], env={:Text,Text} -> Command):
|
||||||
return Command(Text(path), args, env)
|
return Command(Text(path), args, env)
|
||||||
|
|
||||||
func run(command:Command, input="", input_bytes=[:Byte] -> ProgramResult):
|
func result(command:Command, input="", input_bytes=[:Byte] -> ProgramResult):
|
||||||
if input.length > 0:
|
if input.length > 0:
|
||||||
(&input_bytes):insert_all(input:bytes())
|
(&input_bytes):insert_all(input:bytes())
|
||||||
|
|
||||||
@ -59,11 +59,22 @@ struct Command(command:Text, args=[:Text], env={:Text,Text}):
|
|||||||
|
|
||||||
return ProgramResult(stdout, stderr, ExitType.Failed)
|
return ProgramResult(stdout, stderr, ExitType.Failed)
|
||||||
|
|
||||||
|
func run(command:Command, -> ExitType):
|
||||||
|
status := run_command(command.command, command.args, command.env, none, none, none)
|
||||||
|
|
||||||
|
if inline C : Bool { WIFEXITED(_$status) }:
|
||||||
|
return ExitType.Exited(inline C : Int32 { WEXITSTATUS(_$status) })
|
||||||
|
|
||||||
|
if inline C : Bool { WIFSIGNALED(_$status) }:
|
||||||
|
return ExitType.Signaled(inline C : Int32 { WTERMSIG(_$status) })
|
||||||
|
|
||||||
|
return ExitType.Failed
|
||||||
|
|
||||||
func get_output(command:Command, input="", trim_newline=yes -> Text?):
|
func get_output(command:Command, input="", trim_newline=yes -> Text?):
|
||||||
return command:run(input=input):output_text(trim_newline=trim_newline)
|
return command:result(input=input):output_text(trim_newline=trim_newline)
|
||||||
|
|
||||||
func get_output_bytes(command:Command, input="", input_bytes=[:Byte] -> [Byte]?):
|
func get_output_bytes(command:Command, input="", input_bytes=[:Byte] -> [Byte]?):
|
||||||
result := command:run(input=input, input_bytes=input_bytes)
|
result := command:result(input=input, input_bytes=input_bytes)
|
||||||
when result.exit_type is Exited(status):
|
when result.exit_type is Exited(status):
|
||||||
if status == 0: return result.stdout
|
if status == 0: return result.stdout
|
||||||
return none
|
return none
|
||||||
@ -71,7 +82,3 @@ struct Command(command:Text, args=[:Text], env={:Text,Text}):
|
|||||||
|
|
||||||
func by_line(command:Command -> func(->Text?)?):
|
func by_line(command:Command -> func(->Text?)?):
|
||||||
return command_by_line(command.command, command.args, command.env)
|
return command_by_line(command.command, command.args, command.env)
|
||||||
|
|
||||||
func main(command:Text, args:[Text], input=""):
|
|
||||||
cmd := Command(command, args)
|
|
||||||
say(cmd:get_output(input=input)!)
|
|
||||||
|
@ -24,8 +24,11 @@ lang Shell:
|
|||||||
func command(shell:Shell -> Command):
|
func command(shell:Shell -> Command):
|
||||||
return Command("sh", ["-c", shell.text])
|
return Command("sh", ["-c", shell.text])
|
||||||
|
|
||||||
func run(shell:Shell, input="", input_bytes=[:Byte] -> ProgramResult):
|
func result(shell:Shell, input="", input_bytes=[:Byte] -> ProgramResult):
|
||||||
return shell:command():run(input=input, input_bytes=input_bytes)
|
return shell:command():result(input=input, input_bytes=input_bytes)
|
||||||
|
|
||||||
|
func run(shell:Shell -> ExitType):
|
||||||
|
return shell:command():run()
|
||||||
|
|
||||||
func get_output(shell:Shell, input="", trim_newline=yes -> Text?):
|
func get_output(shell:Shell, input="", trim_newline=yes -> Text?):
|
||||||
return shell:command():get_output(input=input, trim_newline=trim_newline)
|
return shell:command():get_output(input=input, trim_newline=trim_newline)
|
||||||
|
Loading…
Reference in New Issue
Block a user