1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-22 17:01:08 +01:00

Make the pager a logger wrapper

Rewrite the pager mechanism to make it a (parametrized) instance of `Logger`
rather than being a standalone thing.
The main interest of this is that we have more control over when to
actually start it and make the inner pager more quiet (only when
`writeToStdout` is called)
This commit is contained in:
Théophane Hufschmitt 2023-06-12 08:52:24 +02:00
parent 5c91f2e5d7
commit 52a4ccc1bd
14 changed files with 156 additions and 66 deletions

View file

@ -29,6 +29,7 @@ extern "C" {
#include "attr-path.hh" #include "attr-path.hh"
#include "store-api.hh" #include "store-api.hh"
#include "log-store.hh" #include "log-store.hh"
#include "loggers.hh"
#include "common-eval-args.hh" #include "common-eval-args.hh"
#include "get-drvs.hh" #include "get-drvs.hh"
#include "derivations.hh" #include "derivations.hh"

View file

@ -1,5 +1,6 @@
#include "loggers.hh" #include "loggers.hh"
#include "progress-bar.hh" #include "progress-bar.hh"
#include "paged-logger.hh"
#include "util.hh" #include "util.hh"
namespace nix { namespace nix {
@ -53,4 +54,14 @@ void createDefaultLogger() {
logger = makeDefaultLogger(); logger = makeDefaultLogger();
} }
RunPager::RunPager()
: previousLogger(logger)
{
logger = new PagedLogger(previousLogger);
}
RunPager::~RunPager() {
logger = previousLogger;
}
} }

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
///@file ///@file
#include "logging.hh"
#include "types.hh" #include "types.hh"
namespace nix { namespace nix {
@ -18,4 +19,13 @@ void setLogFormat(const LogFormat & logFormat);
void createDefaultLogger(); void createDefaultLogger();
class RunPager{
private:
Logger* previousLogger;
public:
RunPager();
~RunPager();
};
} }

View file

@ -0,0 +1,90 @@
#include "paged-logger.hh"
#include <iostream>
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<char> PagedLogger::ask(std::string_view s)
{ return innerLogger->ask(s); }
}

View file

@ -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<char> ask(std::string_view s) override;
};
}

View file

@ -10,7 +10,6 @@
#include <cctype> #include <cctype>
#include <exception> #include <exception>
#include <iostream> #include <iostream>
#include <cstdlib> #include <cstdlib>
#include <sys/time.h> #include <sys/time.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -351,55 +350,6 @@ int handleExceptions(const std::string & programName, std::function<void()> fun)
return 0; 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() PrintFreed::~PrintFreed()
{ {
if (show) if (show)

View file

@ -84,21 +84,6 @@ struct LegacyArgs : public MixCommonArgs
*/ */
void showManPage(const std::string & name); 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; extern volatile ::sig_atomic_t blockInt;

View file

@ -15,6 +15,7 @@
#include "value-to-json.hh" #include "value-to-json.hh"
#include "xml-writer.hh" #include "xml-writer.hh"
#include "legacy.hh" #include "legacy.hh"
#include "loggers.hh"
#include <cerrno> #include <cerrno>
#include <ctime> #include <ctime>

View file

@ -15,6 +15,7 @@
#include "graphml.hh" #include "graphml.hh"
#include "legacy.hh" #include "legacy.hh"
#include "path-with-outputs.hh" #include "path-with-outputs.hh"
#include "loggers.hh"
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>

View file

@ -6,6 +6,7 @@
#include "eval-inline.hh" #include "eval-inline.hh"
#include "flake/flake.hh" #include "flake/flake.hh"
#include "get-drvs.hh" #include "get-drvs.hh"
#include "loggers.hh"
#include "store-api.hh" #include "store-api.hh"
#include "derivations.hh" #include "derivations.hh"
#include "outputs-spec.hh" #include "outputs-spec.hh"
@ -1130,7 +1131,9 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
Activity act(*logger, lvlInfo, actUnknown, Activity act(*logger, lvlInfo, actUnknown,
fmt("evaluating '%s'", concatStringsSep(".", attrPathS))); fmt("evaluating '%s'", concatStringsSep(".", attrPathS)));
std::optional<RunPager> pager = json ? std::nullopt : std::optional<RunPager>(RunPager()); std::optional<RunPager> pager = json
? std::nullopt
: std::make_optional<RunPager>();
try { try {
auto recurse = [&]() auto recurse = [&]()
{ {

View file

@ -4,6 +4,7 @@
#include "store-api.hh" #include "store-api.hh"
#include "log-store.hh" #include "log-store.hh"
#include "progress-bar.hh" #include "progress-bar.hh"
#include "loggers.hh"
using namespace nix; using namespace nix;

View file

@ -2,6 +2,7 @@
#include "globals.hh" #include "globals.hh"
#include "command.hh" #include "command.hh"
#include "installable-value.hh" #include "installable-value.hh"
#include "loggers.hh"
#include "repl.hh" #include "repl.hh"
namespace nix { namespace nix {

View file

@ -9,6 +9,7 @@
#include "eval-cache.hh" #include "eval-cache.hh"
#include "attr-path.hh" #include "attr-path.hh"
#include "hilite.hh" #include "hilite.hh"
#include "loggers.hh"
#include <regex> #include <regex>
#include <fstream> #include <fstream>

View file

@ -3,6 +3,7 @@
#include "progress-bar.hh" #include "progress-bar.hh"
#include "fs-accessor.hh" #include "fs-accessor.hh"
#include "shared.hh" #include "shared.hh"
#include "loggers.cc"
#include <queue> #include <queue>