diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 4b160a100..1d269d08d 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -29,6 +29,7 @@ extern "C" { #include "attr-path.hh" #include "store-api.hh" #include "log-store.hh" +#include "loggers.hh" #include "common-eval-args.hh" #include "get-drvs.hh" #include "derivations.hh" diff --git a/src/libmain/loggers.cc b/src/libmain/loggers.cc index cda5cb939..ca2e5272d 100644 --- a/src/libmain/loggers.cc +++ b/src/libmain/loggers.cc @@ -1,5 +1,6 @@ #include "loggers.hh" #include "progress-bar.hh" +#include "paged-logger.hh" #include "util.hh" namespace nix { @@ -53,4 +54,14 @@ void createDefaultLogger() { logger = makeDefaultLogger(); } +RunPager::RunPager() + : previousLogger(logger) +{ + logger = new PagedLogger(previousLogger); +} + +RunPager::~RunPager() { + logger = previousLogger; +} + } diff --git a/src/libmain/loggers.hh b/src/libmain/loggers.hh index e5721420c..bf85e9629 100644 --- a/src/libmain/loggers.hh +++ b/src/libmain/loggers.hh @@ -1,6 +1,7 @@ #pragma once ///@file +#include "logging.hh" #include "types.hh" namespace nix { @@ -18,4 +19,13 @@ void setLogFormat(const LogFormat & logFormat); void createDefaultLogger(); +class RunPager{ +private: + Logger* previousLogger; + +public: + RunPager(); + ~RunPager(); +}; + } diff --git a/src/libmain/paged-logger.cc b/src/libmain/paged-logger.cc new file mode 100644 index 000000000..8085dd300 --- /dev/null +++ b/src/libmain/paged-logger.cc @@ -0,0 +1,90 @@ +#include "paged-logger.hh" + +#include + +namespace nix { + +PagedLogger::PagedLogger(Logger * previousLogger) + : innerLogger(previousLogger) +{ +} + +PagedLogger::~PagedLogger() +{ + try { + if (pid != -1) { + std::cout.flush(); + dup2(stdout, STDOUT_FILENO); + pid.wait(); + } + } catch (...) { + ignoreException(); + } +} + +void PagedLogger::startPager() { + if (pagerStarted) { + return; + } + innerLogger = makeSimpleLogger(false); + pagerStarted = true; + if (!isatty(STDOUT_FILENO)) return; + char * pager = getenv("NIX_PAGER"); + if (!pager) pager = getenv("PAGER"); + if (pager && ((std::string) pager == "" || (std::string) pager == "cat")) return; + + Pipe toPager; + toPager.create(); + + pid = startProcess([&]() { + if (dup2(toPager.readSide.get(), STDIN_FILENO) == -1) + throw SysError("dupping stdin"); + if (!getenv("LESS")) + setenv("LESS", "FRSXMK", 1); + restoreProcessContext(); + if (pager) + execl("/bin/sh", "sh", "-c", pager, nullptr); + execlp("pager", "pager", nullptr); + execlp("less", "less", nullptr); + execlp("more", "more", nullptr); + throw SysError("executing '%1%'", pager); + }); + + pid.setKillSignal(SIGINT); + + pid.setKillSignal(SIGINT); + stdout = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0); + if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1) + throw SysError("dupping stdout"); +} + +void PagedLogger::writeToStdout(std::string_view s) +{ + startPager(); + innerLogger->writeToStdout(s); +} + + +void PagedLogger::stop() { return innerLogger->stop(); } +bool PagedLogger::isVerbose() { return false; } +void PagedLogger::log(Verbosity lvl, const std::string_view s) +{ innerLogger->log(lvl, s); } +void PagedLogger::logEI(const ErrorInfo & ei) { innerLogger->logEI(ei); } +void PagedLogger::warn(const std::string & msg) +{ innerLogger->warn(msg); } +void PagedLogger::startActivity( + ActivityId act, + Verbosity lvl, + ActivityType type, + const std::string & s, + const Fields & fields, + ActivityId parent) +{ innerLogger->startActivity(act, lvl, type, s, fields, parent); } +void PagedLogger::stopActivity(ActivityId act) +{ innerLogger->stopActivity(act); } +void PagedLogger::result(ActivityId act, ResultType type, const Fields & fields) +{ innerLogger->result(act, type, fields); } +std::optional PagedLogger::ask(std::string_view s) +{ return innerLogger->ask(s); } + +} diff --git a/src/libmain/paged-logger.hh b/src/libmain/paged-logger.hh new file mode 100644 index 000000000..976ff0abf --- /dev/null +++ b/src/libmain/paged-logger.hh @@ -0,0 +1,34 @@ +#include "logging.hh" +#include "util.hh" + +namespace nix { + +class PagedLogger : public Logger { + Logger * innerLogger; + bool pagerStarted = false; + Pid pid; + int stdout; + + void startPager(); + +public: + PagedLogger(Logger * previousLogger); + + ~PagedLogger(); + + void writeToStdout(std::string_view s) override; + + // All these methods are just forwarded to the inner logger + + void stop() override; + bool isVerbose() override; + void log(Verbosity lvl, std::string_view s) override; + void logEI(const ErrorInfo &ei) override; + void warn(const std::string &msg) override; + void startActivity(ActivityId act, Verbosity lvl, ActivityType type, const std::string &s, const Fields &fields, ActivityId parent) override; + void stopActivity(ActivityId act) override; + void result(ActivityId act, ResultType type, const Fields &fields) override; + std::optional ask(std::string_view s) override; +}; + +} diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 5d450e8ea..3802a8128 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -10,7 +10,6 @@ #include #include #include - #include #include #include @@ -351,55 +350,6 @@ int handleExceptions(const std::string & programName, std::function fun) return 0; } - -RunPager::RunPager() -{ - if (!isatty(STDOUT_FILENO)) return; - char * pager = getenv("NIX_PAGER"); - if (!pager) pager = getenv("PAGER"); - if (pager && ((std::string) pager == "" || (std::string) pager == "cat")) return; - - stopProgressBar(); - - Pipe toPager; - toPager.create(); - - pid = startProcess([&]() { - if (dup2(toPager.readSide.get(), STDIN_FILENO) == -1) - throw SysError("dupping stdin"); - if (!getenv("LESS")) - setenv("LESS", "FRSXMK", 1); - restoreProcessContext(); - if (pager) - execl("/bin/sh", "sh", "-c", pager, nullptr); - execlp("pager", "pager", nullptr); - execlp("less", "less", nullptr); - execlp("more", "more", nullptr); - throw SysError("executing '%1%'", pager); - }); - - pid.setKillSignal(SIGINT); - stdout = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0); - if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1) - throw SysError("dupping stdout"); - setLogFormat(LogFormat::raw); -} - - -RunPager::~RunPager() -{ - try { - if (pid != -1) { - std::cout.flush(); - dup2(stdout, STDOUT_FILENO); - pid.wait(); - } - } catch (...) { - ignoreException(); - } -} - - PrintFreed::~PrintFreed() { if (show) diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh index 7a9e83c6c..b2d6d4a5e 100644 --- a/src/libmain/shared.hh +++ b/src/libmain/shared.hh @@ -84,21 +84,6 @@ struct LegacyArgs : public MixCommonArgs */ void showManPage(const std::string & name); -/** - * The constructor of this class starts a pager if stdout is a - * terminal and $PAGER is set. Stdout is redirected to the pager. - */ -class RunPager -{ -public: - RunPager(); - ~RunPager(); - -private: - Pid pid; - int stdout; -}; - extern volatile ::sig_atomic_t blockInt; diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 5e94f2d14..b2aebd41e 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -15,6 +15,7 @@ #include "value-to-json.hh" #include "xml-writer.hh" #include "legacy.hh" +#include "loggers.hh" #include #include diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index 61c189efb..4972879d1 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -15,6 +15,7 @@ #include "graphml.hh" #include "legacy.hh" #include "path-with-outputs.hh" +#include "loggers.hh" #include #include diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 6d225043f..ae4266460 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -6,6 +6,7 @@ #include "eval-inline.hh" #include "flake/flake.hh" #include "get-drvs.hh" +#include "loggers.hh" #include "store-api.hh" #include "derivations.hh" #include "outputs-spec.hh" @@ -1130,7 +1131,9 @@ struct CmdFlakeShow : FlakeCommand, MixJSON Activity act(*logger, lvlInfo, actUnknown, fmt("evaluating '%s'", concatStringsSep(".", attrPathS))); - std::optional pager = json ? std::nullopt : std::optional(RunPager()); + std::optional pager = json + ? std::nullopt + : std::make_optional(); try { auto recurse = [&]() { diff --git a/src/nix/log.cc b/src/nix/log.cc index aaf829764..9e3cd493f 100644 --- a/src/nix/log.cc +++ b/src/nix/log.cc @@ -4,6 +4,7 @@ #include "store-api.hh" #include "log-store.hh" #include "progress-bar.hh" +#include "loggers.hh" using namespace nix; diff --git a/src/nix/repl.cc b/src/nix/repl.cc index bb14f3f99..980363c74 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -2,6 +2,7 @@ #include "globals.hh" #include "command.hh" #include "installable-value.hh" +#include "loggers.hh" #include "repl.hh" namespace nix { diff --git a/src/nix/search.cc b/src/nix/search.cc index cc437c9cb..fa1073928 100644 --- a/src/nix/search.cc +++ b/src/nix/search.cc @@ -9,6 +9,7 @@ #include "eval-cache.hh" #include "attr-path.hh" #include "hilite.hh" +#include "loggers.hh" #include #include diff --git a/src/nix/why-depends.cc b/src/nix/why-depends.cc index a3a9dc698..d191ea8b1 100644 --- a/src/nix/why-depends.cc +++ b/src/nix/why-depends.cc @@ -3,6 +3,7 @@ #include "progress-bar.hh" #include "fs-accessor.hh" #include "shared.hh" +#include "loggers.cc" #include