mirror of
https://github.com/janet-lang/janet
synced 2025-04-11 01:36:38 +00:00
Add {:err :out}
option to os/spawn.
This special case in the os/spawn interface allows easily redirecting both stderr and stdout to the same pipe.
This commit is contained in:
parent
a9ff8b388f
commit
bdab93c999
@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
## Unreleased - ???
|
||||
- Make `ffi/write` append to a buffer instead of insert at 0 by default.
|
||||
- Add `os/getpid` to get the current process id.
|
||||
- Add `:out` option to `os/spawn` to be able to redirect stderr to stdout with pipes.
|
||||
|
||||
## 1.38.0 - 2025-03-18
|
||||
- Add `bundle/replace`
|
||||
|
@ -816,6 +816,7 @@ JANET_CORE_FN(os_proc_close,
|
||||
JANET_CORE_FN(os_proc_getpid,
|
||||
"(os/getpid)",
|
||||
"Get the process ID of the current process.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_SUBPROCESS);
|
||||
janet_fixarity(argc, 0);
|
||||
(void) argv;
|
||||
#ifdef JANET_WINDOWS
|
||||
@ -1149,6 +1150,7 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) {
|
||||
JanetAbstract orig_in = NULL, orig_out = NULL, orig_err = NULL;
|
||||
JanetHandle new_in = JANET_HANDLE_NONE, new_out = JANET_HANDLE_NONE, new_err = JANET_HANDLE_NONE;
|
||||
JanetHandle pipe_in = JANET_HANDLE_NONE, pipe_out = JANET_HANDLE_NONE, pipe_err = JANET_HANDLE_NONE;
|
||||
int stderr_is_stdout = 0;
|
||||
int pipe_errflag = 0; /* Track errors setting up pipes */
|
||||
int pipe_owner_flags = (is_spawn && (flags & 0x8)) ? JANET_PROC_ALLOW_ZOMBIE : 0;
|
||||
|
||||
@ -1173,6 +1175,8 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) {
|
||||
if (is_spawn && janet_keyeq(maybe_stderr, "pipe")) {
|
||||
new_err = make_pipes(&pipe_err, 0, &pipe_errflag);
|
||||
pipe_owner_flags |= JANET_PROC_OWNS_STDERR;
|
||||
} else if (is_spawn && janet_keyeq(maybe_stderr, "out")) {
|
||||
stderr_is_stdout = 1;
|
||||
} else if (!janet_checktype(maybe_stderr, JANET_NIL)) {
|
||||
new_err = janet_getjstream(&maybe_stderr, 0, &orig_err);
|
||||
}
|
||||
@ -1230,6 +1234,8 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) {
|
||||
startupInfo.hStdError = pipe_err;
|
||||
} else if (new_err != NULL) {
|
||||
startupInfo.hStdError = new_err;
|
||||
} else if (stderr_is_stdout) {
|
||||
startupInfo.hStdError = startupInfo.hStdOut;
|
||||
} else {
|
||||
startupInfo.hStdError = (HANDLE) _get_osfhandle(2);
|
||||
}
|
||||
@ -1321,6 +1327,8 @@ static Janet os_execute_impl(int32_t argc, Janet *argv, JanetExecuteMode mode) {
|
||||
} else if (new_err != JANET_HANDLE_NONE && new_err != 2) {
|
||||
posix_spawn_file_actions_adddup2(&actions, new_err, 2);
|
||||
posix_spawn_file_actions_addclose(&actions, new_err);
|
||||
} else if (stderr_is_stdout) {
|
||||
posix_spawn_file_actions_adddup2(&actions, 1, 2);
|
||||
}
|
||||
|
||||
pid_t pid;
|
||||
@ -1426,7 +1434,8 @@ JANET_CORE_FN(os_spawn,
|
||||
"`:pipe` may fail if there are too many active file descriptors. The caller is "
|
||||
"responsible for closing pipes created by `:pipe` (either individually or using "
|
||||
"`os/proc-close`). Similar to `os/execute`, the caller is responsible for ensuring "
|
||||
"pipes do not cause the program to block and deadlock.") {
|
||||
"pipes do not cause the program to block and deadlock. As a special case, the stream passed to `:err` "
|
||||
"can be the keyword `:out` to redirect stderr to stdout in the subprocess.") {
|
||||
return os_execute_impl(argc, argv, JANET_EXECUTE_SPAWN);
|
||||
}
|
||||
|
||||
|
@ -556,4 +556,20 @@
|
||||
(ev/deadline 0.01 nil f true)
|
||||
(assert-error "deadline expired" (resume f)))
|
||||
|
||||
# Use :err :stdout
|
||||
(def- subproc-code '(do (eprint "hi") (eflush) (print "there") (flush)))
|
||||
(defn ev/slurp
|
||||
[f &opt buf]
|
||||
(default buf @"")
|
||||
(if (ev/read f 0x10000 buf)
|
||||
(ev/slurp f buf)
|
||||
buf))
|
||||
(def p (os/spawn [;run janet "-e" (string/format "%j" subproc-code)] :px {:out :pipe :err :out}))
|
||||
(def [exit-code data]
|
||||
(ev/gather
|
||||
(os/proc-wait p)
|
||||
(ev/slurp (p :out))))
|
||||
(assert (zero? exit-code) "subprocess ran")
|
||||
(assert (deep= data @"hi\nthere\n") "output is correct")
|
||||
|
||||
(end-suite)
|
||||
|
Loading…
x
Reference in New Issue
Block a user