diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index b8bfc25eb..c4dc1d29f 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -251,7 +251,7 @@ void runNix(Path program, const Strings & args) .program = settings.nixBinDir+ "/" + program, .args = args, .environment = subprocessEnv, - }).wait(); + }).waitAndCheck(); return; } @@ -650,7 +650,7 @@ ProcessLineResult NixRepl::processLine(std::string line) // runProgram redirects stdout to a StringSink, // using runProgram2 to allow editors to display their UI - runProgram2(RunOptions { .program = editor, .searchPath = true, .args = args }).wait(); + runProgram2(RunOptions { .program = editor, .searchPath = true, .args = args }).waitAndCheck(); // Reload right after exiting the editor if path is not in store // Store is immutable, so there could be no changes, so there's no need to reload diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index 7d16d3f57..29eaf8b78 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -690,7 +690,7 @@ struct GitInputScheme : InputScheme .args = { "-C", repoDir, "--git-dir", gitDir, "archive", input.getRev()->gitRev() }, .captureStdout = true, }); - Finally const _wait([&] { proc.wait(); }); + Finally const _wait([&] { proc.waitAndCheck(); }); unpackTarfile(*proc.getStdout(), tmpDir); } diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc index aa89f9e7d..4180654ab 100644 --- a/src/libstore/build/derivation-goal.cc +++ b/src/libstore/build/derivation-goal.cc @@ -919,7 +919,7 @@ void runPostBuildHook( .captureStdout = true, .mergeStderrToStdout = true, }); - Finally const _wait([&] { proc.wait(); }); + Finally const _wait([&] { proc.waitAndCheck(); }); // FIXME just process the data, without a wrapper sink class proc.getStdout()->drainInto(sink); diff --git a/src/libutil/processes.cc b/src/libutil/processes.cc index 61e1ad556..46cbb66da 100644 --- a/src/libutil/processes.cc +++ b/src/libutil/processes.cc @@ -248,7 +248,7 @@ std::pair runProgram(RunOptions && options) try { auto proc = runProgram2(options); - Finally const _wait([&] { proc.wait(); }); + Finally const _wait([&] { proc.waitAndCheck(); }); stdout = proc.getStdout()->drain(); } catch (ExecError & e) { status = e.status; @@ -276,7 +276,22 @@ RunningProgram::~RunningProgram() } } -void RunningProgram::wait() +std::tuple, int> RunningProgram::release() +{ + return {pid.release(), std::move(stdoutSource), stdout_.release()}; +} + +int RunningProgram::kill() +{ + return pid.kill(); +} + +int RunningProgram::wait() +{ + return pid.wait(); +} + +void RunningProgram::waitAndCheck() { if (std::uncaught_exceptions() == 0) { int status = pid.wait(); diff --git a/src/libutil/processes.hh b/src/libutil/processes.hh index dc09a9ba4..3566aa3cf 100644 --- a/src/libutil/processes.hh +++ b/src/libutil/processes.hh @@ -102,9 +102,23 @@ private: public: RunningProgram() = default; + RunningProgram(RunningProgram &&) = default; + RunningProgram & operator=(RunningProgram &&) = default; ~RunningProgram(); - void wait(); + explicit operator bool() const { return bool(pid); } + + std::tuple, int> release(); + + int kill(); + [[nodiscard]] + int wait(); + void waitAndCheck(); + + std::optional getStdoutFD() const + { + return stdout_ ? std::optional(stdout_.get()) : std::nullopt; + } Source * getStdout() const { return stdoutSource.get(); }; };