diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 340c20450..d1370691c 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -102,8 +102,7 @@ struct NixRepl unsigned int maxDepth = std::numeric_limits::max()) { // Hide the progress bar during printing because it might interfere - logger->pause(); - Finally resumeLoggerDefer([]() { logger->resume(); }); + auto suspension = logger->suspend(); ::nix::printValue(*state, str, v, PrintOptions { .ansiColors = true, .force = true, @@ -180,18 +179,20 @@ ReplExitStatus NixRepl::mainLoop() while (true) { // Hide the progress bar while waiting for user input, so that it won't interfere. - logger->pause(); - // When continuing input from previous lines, don't print a prompt, just align to the same - // number of chars as the prompt. - if (!interacter->getLine(input, input.empty() ? ReplPromptType::ReplPrompt : ReplPromptType::ContinuationPrompt)) { - // Ctrl-D should exit the debugger. - state->debugStop = false; - logger->cout(""); - // TODO: Should Ctrl-D exit just the current debugger session or - // the entire program? - return ReplExitStatus::QuitAll; + { + auto suspension = logger->suspend(); + // When continuing input from previous lines, don't print a prompt, just align to the same + // number of chars as the prompt. + if (!interacter->getLine(input, input.empty() ? ReplPromptType::ReplPrompt : ReplPromptType::ContinuationPrompt)) { + // Ctrl-D should exit the debugger. + state->debugStop = false; + logger->cout(""); + // TODO: Should Ctrl-D exit just the current debugger session or + // the entire program? + return ReplExitStatus::QuitAll; + } + // `suspension` resumes the logger } - logger->resume(); try { switch (processLine(input)) { case ProcessLineResult::Quit: @@ -694,10 +695,9 @@ ProcessLineResult NixRepl::processLine(std::string line) } else { Value v; evalString(line, v); - logger->pause(); + auto suspension = logger->suspend(); printValue(std::cout, v, 1); std::cout << std::endl; - logger->resume(); } } diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index 8d4d9abcc..f46334d30 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -351,8 +351,7 @@ struct GitInputScheme : InputScheme if (commitMsg) { // Pause the logger to allow for user input (such as a gpg passphrase) in `git commit` - logger->pause(); - Finally restoreLogger([]() { logger->resume(); }); + auto suspension = logger->suspend(); runProgram("git", true, { "-C", repoPath->string(), "--git-dir", repoInfo.gitDir, "commit", std::string(path.rel()), "-F", "-" }, *commitMsg); diff --git a/src/libstore/ssh.cc b/src/libstore/ssh.cc index f47cfbbec..70e6d5dfe 100644 --- a/src/libstore/ssh.cc +++ b/src/libstore/ssh.cc @@ -117,10 +117,10 @@ std::unique_ptr SSHMaster::startCommand( ProcessOptions options; options.dieWithParent = false; + std::unique_ptr loggerSuspension; if (!fakeSSH && !useMaster) { - logger->pause(); + loggerSuspension = std::make_unique(logger->suspend()); } - Finally cleanup = [&]() { logger->resume(); }; conn->sshPid = startProcess([&]() { restoreProcessContext(); @@ -199,8 +199,7 @@ Path SSHMaster::startMaster() ProcessOptions options; options.dieWithParent = false; - logger->pause(); - Finally cleanup = [&]() { logger->resume(); }; + auto suspension = logger->suspend(); if (isMasterRunning()) return state->socketPath; diff --git a/src/libutil/logging.cc b/src/libutil/logging.cc index deeae120a..406452738 100644 --- a/src/libutil/logging.cc +++ b/src/libutil/logging.cc @@ -43,6 +43,19 @@ void Logger::writeToStdout(std::string_view s) writeFull(standard_out, "\n"); } +Logger::Suspension Logger::suspend() +{ + pause(); + return Suspension { ._finalize = {[this](){this->resume();}} }; +} + +std::optional Logger::suspendIf(bool cond) +{ + if (cond) + return suspend(); + return {}; +} + class SimpleLogger : public Logger { public: diff --git a/src/libutil/logging.hh b/src/libutil/logging.hh index 474283894..e5a7a833f 100644 --- a/src/libutil/logging.hh +++ b/src/libutil/logging.hh @@ -4,6 +4,7 @@ #include "error.hh" #include "config.hh" #include "file-descriptor.hh" +#include "finally.hh" #include @@ -75,6 +76,17 @@ public: virtual void stop() { }; + /** + * Guard object to resume the logger when done. + */ + struct Suspension { + Finally> _finalize; + }; + + Suspension suspend(); + + std::optional suspendIf(bool cond); + virtual void pause() { }; virtual void resume() { }; diff --git a/src/libutil/unix/processes.cc b/src/libutil/unix/processes.cc index a9df1be60..da198bed4 100644 --- a/src/libutil/unix/processes.cc +++ b/src/libutil/unix/processes.cc @@ -306,15 +306,7 @@ void runProgram2(const RunOptions & options) // case), so we can't use it if we alter the environment processOptions.allowVfork = !options.environment; - std::optional>> resumeLoggerDefer; - if (options.isInteractive) { - logger->pause(); - resumeLoggerDefer.emplace( - []() { - logger->resume(); - } - ); - } + auto suspension = logger->suspendIf(options.isInteractive); /* Fork. */ Pid pid = startProcess([&] { diff --git a/src/libutil/windows/processes.cc b/src/libutil/windows/processes.cc index fd4d7c43a..90cb1f5f5 100644 --- a/src/libutil/windows/processes.cc +++ b/src/libutil/windows/processes.cc @@ -312,11 +312,7 @@ void runProgram2(const RunOptions & options) // TODO: Implement shebang / program interpreter lookup on Windows auto interpreter = getProgramInterpreter(realProgram); - std::optional>> resumeLoggerDefer; - if (options.isInteractive) { - logger->pause(); - resumeLoggerDefer.emplace([]() { logger->resume(); }); - } + auto suspension = logger->suspendIf(options.isInteractive); Pid pid = spawnProcess(interpreter.has_value() ? *interpreter : realProgram, options, out, in);