Skip to content

Commit 5bd3973

Browse files
authored
@lute/process: implement stdin support for default and inherit stdio kinds. (#977)
I went on a wild goose chase for a few days thinking there was something wrong with `io.read` where it seemed like it was closing the file descriptor for `stdin` on the first read call, and subsequent calls would break. It turns out the actual underlying issue is that I'm always invoking my local version of `lute` by doing a `luthier run` call, and this revealed an issue with the process library itself: we were always setting `stdio` to `UV_IGNORE` meaning we were always closing out the stdin handle for subprocesses, regardless of stdio kind setting. This resulted in a simple program that takes an input giving EOF with any invocation through a `luthier` executed copy of `lute`. The fix is straightforward, we should set up the `0` fd, not just `1` and `2`, in our process library.
1 parent 612c647 commit 5bd3973

File tree

1 file changed

+17
-1
lines changed

1 file changed

+17
-1
lines changed

lute/process/src/process.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ void convertCRLFtoLF(std::string& str)
4242
struct ProcessHandle
4343
{
4444
uv_process_t process;
45+
uv_pipe_t stdinPipe;
4546
uv_pipe_t stdoutPipe;
4647
uv_pipe_t stderrPipe;
4748
uv_loop_t* loop = nullptr;
@@ -65,12 +66,20 @@ struct ProcessHandle
6566
}
6667
};
6768

69+
if (!uv_is_closing((uv_handle_t*)&stdinPipe))
70+
{
71+
pendingCloses++;
72+
uv_read_stop((uv_stream_t*)&stdinPipe);
73+
uv_close((uv_handle_t*)&stdinPipe, closeCb);
74+
}
75+
6876
if (!uv_is_closing((uv_handle_t*)&stdoutPipe))
6977
{
7078
pendingCloses++;
7179
uv_read_stop((uv_stream_t*)&stdoutPipe);
7280
uv_close((uv_handle_t*)&stdoutPipe, closeCb);
7381
}
82+
7483
if (!uv_is_closing((uv_handle_t*)&stderrPipe))
7584
{
7685
pendingCloses++;
@@ -106,6 +115,7 @@ struct ProcessHandle
106115
{
107116
int64_t finalExitCode = exitCode;
108117
int finalTermSignal = termSignal;
118+
// TODO: should we we put any leftover stdin data into the output here?
109119
std::string finalStdout = stdoutData;
110120
std::string finalStderr = stderrData;
111121
std::string finalSignalStr = finalTermSignal ? std::to_string(finalTermSignal) : "";
@@ -283,26 +293,31 @@ int executionHelper(lua_State* L, std::vector<std::string> args, ProcessOptions
283293
options.cwd = opts.cwd.c_str();
284294
}
285295

296+
uv_pipe_init(handle->loop, &handle->stdinPipe, 0);
286297
uv_pipe_init(handle->loop, &handle->stdoutPipe, 0);
287298
uv_pipe_init(handle->loop, &handle->stderrPipe, 0);
288299

289300
options.stdio_count = 3;
290301
uv_stdio_container_t stdio[3];
291-
stdio[0].flags = UV_IGNORE;
292302
if (opts.stdioKind == kStdioKindNone)
293303
{
304+
stdio[0].flags = UV_IGNORE;
294305
stdio[1].flags = UV_IGNORE;
295306
stdio[2].flags = UV_IGNORE;
296307
}
297308
else if (opts.stdioKind == kStdioKindInherit)
298309
{
310+
stdio[0].flags = UV_INHERIT_FD;
311+
stdio[0].data.fd = fileno(stdin);
299312
stdio[1].flags = UV_INHERIT_FD;
300313
stdio[1].data.fd = fileno(stdout);
301314
stdio[2].flags = UV_INHERIT_FD;
302315
stdio[2].data.fd = fileno(stderr);
303316
}
304317
else if (opts.stdioKind == kStdioKindDefault || opts.stdioKind.empty())
305318
{
319+
stdio[0].flags = static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_READABLE_PIPE);
320+
stdio[0].data.stream = (uv_stream_t*)&handle->stdinPipe;
306321
stdio[1].flags = static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
307322
stdio[1].data.stream = (uv_stream_t*)&handle->stdoutPipe;
308323
stdio[2].flags = static_cast<uv_stdio_flags>(UV_CREATE_PIPE | UV_WRITABLE_PIPE);
@@ -315,6 +330,7 @@ int executionHelper(lua_State* L, std::vector<std::string> args, ProcessOptions
315330
options.stdio = stdio;
316331

317332
handle->process.data = handle.get();
333+
handle->stdinPipe.data = handle.get();
318334
handle->stdoutPipe.data = handle.get();
319335
handle->stderrPipe.data = handle.get();
320336

0 commit comments

Comments
 (0)