diff --git a/lix/libfetchers/git.cc b/lix/libfetchers/git.cc index f8de4c37a..fc5f9af84 100644 --- a/lix/libfetchers/git.cc +++ b/lix/libfetchers/git.cc @@ -21,6 +21,7 @@ #include "lix/libfetchers/fetch-settings.hh" +#include #include #include #include @@ -70,15 +71,13 @@ Path getCachePath(std::string_view key) // ... static kj::Promise>> readHead(const Path & path) try { - auto [status, output] = TRY_AWAIT(runProgram(RunOptions{ - .program = "git", + auto output = TRY_AWAIT(runProgram( + "git", + true, // FIXME: use 'HEAD' to avoid returning all refs - .args = {"ls-remote", "--symref", path}, - .isInteractive = true, - })); - if (status != 0) { - co_return std::nullopt; - } + {"ls-remote", "--symref", path}, + true + )); std::string_view line = output; line = line.substr(0, line.find("\n")); @@ -94,6 +93,8 @@ try { co_return parseResult->target; } co_return std::nullopt; +} catch (ExecError &) { + co_return std::nullopt; } catch (...) { co_return result::current_exception(); } diff --git a/lix/libutil/processes.cc b/lix/libutil/processes.cc index 6a833d3ad..0eea7c3c5 100644 --- a/lix/libutil/processes.cc +++ b/lix/libutil/processes.cc @@ -8,6 +8,8 @@ #include "lix/libutil/strings.hh" #include "lix/libutil/serialise.hh" #include "lix/libutil/signals.hh" +#include "manually-drop.hh" +#include "sync.hh" #include #include @@ -19,6 +21,7 @@ #include #include #include +#include #ifdef __APPLE__ # include @@ -233,8 +236,27 @@ Pid startProcess(std::function fun, const ProcessOptions & options) kj::Promise> runProgram(Path program, bool searchPath, const Strings args, bool isInteractive) try { + // allow only one interactive program per unit time so they don't mess with each other. + // + // see https://git.lix.systems/lix-project/lix/issues/702 for why this is ManuallyDrop. + static ManuallyDrop> interactiveMutex{std::in_place, 0}; + + std::optional::Lock> interactiveLock; + KJ_DEFER({ + if (interactiveLock) { + logger->resume(); + } + }); + + if (isInteractive) { + interactiveLock = co_await interactiveMutex->lock(); + logger->pause(); + } + auto res = TRY_AWAIT(runProgram(RunOptions{ - .program = program, .searchPath = searchPath, .args = args, .isInteractive = isInteractive + .program = program, + .searchPath = searchPath, + .args = args, })); if (!statusOk(res.first)) { @@ -324,16 +346,6 @@ RunningProgram runProgram2(const RunOptions & options) .dieWithParent = options.dieWithParent, }; - std::optional>> resumeLoggerDefer; - if (options.isInteractive) { - logger->pause(); - resumeLoggerDefer.emplace( - []() { - logger->resume(); - } - ); - } - printMsg(lvlChatty, "running command: %s", concatMapStringsSep(" ", options.args, shellEscape)); /* Fork. */ diff --git a/lix/libutil/processes.hh b/lix/libutil/processes.hh index f3a193b76..97e9c25b9 100644 --- a/lix/libutil/processes.hh +++ b/lix/libutil/processes.hh @@ -96,7 +96,6 @@ struct RunOptions std::optional> environment = {}; bool dieWithParent = true; bool captureStdout = false; - bool isInteractive = false; std::vector redirections; #if __linux__ std::set caps;