feat: make log-format a setting
Vaguely one half of #186. Fixes #827. Change-Id: Ie6a296465beb089bf812ea27091648ca6a6a6964
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#include "lix/libmain/common-args.hh"
|
||||
#include "lix/libutil/args/root.hh"
|
||||
#include "lix/libutil/config-impl.hh" // IWYU pragma: keep
|
||||
#include "lix/libutil/error.hh"
|
||||
#include "lix/libstore/globals.hh"
|
||||
#include "lix/libmain/loggers.hh"
|
||||
#include "lix/libutil/logging.hh"
|
||||
|
||||
namespace nix {
|
||||
@@ -62,7 +62,9 @@ MixCommonArgs::MixCommonArgs(const std::string & programName)
|
||||
.description = "Set the format of log output; one of `raw`, `internal-json`, `bar`, `bar-with-logs`, `multiline` or `multiline-with-logs`.",
|
||||
.category = loggingCategory,
|
||||
.labels = {"format"},
|
||||
.handler = {[](std::string format) { setLogFormat(format); }},
|
||||
.handler = {[&](std::string format) {
|
||||
loggerSettings.logFormat.set(format);
|
||||
}},
|
||||
});
|
||||
|
||||
addFlag({
|
||||
|
||||
+6
-18
@@ -1,29 +1,17 @@
|
||||
#include "lix/libutil/environment-variables.hh"
|
||||
#include "lix/libmain/loggers.hh"
|
||||
#include "lix/libmain/progress-bar.hh"
|
||||
#include "lix/libutil/log-format.hh"
|
||||
#include "lix/libutil/config-impl.hh" // IWYU pragma: keep
|
||||
|
||||
namespace nix {
|
||||
|
||||
LogFormat defaultLogFormat = LogFormat::Auto;
|
||||
|
||||
[[deprecated]]
|
||||
LogFormat parseLogFormat(const std::string & logFormatStr) {
|
||||
if (auto const parsed = LogFormat::parse(logFormatStr)) {
|
||||
return *parsed;
|
||||
}
|
||||
throw Error("setting 'log-format' has an invalid value '%s'", logFormatStr);
|
||||
}
|
||||
|
||||
Logger * makeDefaultLogger() {
|
||||
return getLoggerByFormat(defaultLogFormat);
|
||||
}
|
||||
|
||||
void setLogFormat(const std::string & logFormatStr) {
|
||||
setLogFormat(parseLogFormat(logFormatStr));
|
||||
static Logger * makeDefaultLogger() {
|
||||
return getLoggerByFormat(loggerSettings.logFormat);
|
||||
}
|
||||
|
||||
void setLogFormat(const LogFormat & logFormat) {
|
||||
defaultLogFormat = logFormat;
|
||||
loggerSettings.logFormat.override(logFormat);
|
||||
createDefaultLogger();
|
||||
}
|
||||
|
||||
@@ -36,7 +24,7 @@ Logger * getLoggerByFormat(LogFormat logFormat)
|
||||
using enum LogFormatValue;
|
||||
switch (logFormat) {
|
||||
case LogFormat::Auto:
|
||||
return getLoggerByFormat(defaultLogFormat);
|
||||
return getLoggerByFormat(loggerSettings.logFormat.autoValue);
|
||||
case LogFormat::Raw:
|
||||
return makeSimpleLogger(false);
|
||||
case LogFormat::RawWithLogs:
|
||||
|
||||
@@ -8,9 +8,7 @@ namespace nix {
|
||||
|
||||
class Logger;
|
||||
|
||||
[[deprecated]]
|
||||
void setLogFormat(const std::string & logFormatStr);
|
||||
[[deprecated]]
|
||||
/** Overrides the current log format, and re-creates the current logger. */
|
||||
void setLogFormat(const LogFormat & logFormat);
|
||||
|
||||
void createDefaultLogger();
|
||||
|
||||
@@ -200,7 +200,10 @@ LegacyArgs::LegacyArgs(AsyncIoRoot & aio, const std::string & programName,
|
||||
.longName = "no-build-output",
|
||||
.shortName = 'Q',
|
||||
.description = "Do not show build output.",
|
||||
.handler = {[&]() {setLogFormat(LogFormat::Raw); }},
|
||||
.handler = {[&]() {
|
||||
loggerSettings.logFormat.setDefault(loggerSettings.logFormat.get().withoutLogs());
|
||||
loggerSettings.logFormat.autoValue = loggerSettings.logFormat.get().withoutLogs();
|
||||
}},
|
||||
});
|
||||
|
||||
addFlag({
|
||||
|
||||
@@ -133,6 +133,7 @@ DECLARE_CONFIG_SERIALISER(StringSet)
|
||||
DECLARE_CONFIG_SERIALISER(StringMap)
|
||||
DECLARE_CONFIG_SERIALISER(ExperimentalFeatures)
|
||||
DECLARE_CONFIG_SERIALISER(DeprecatedFeatures)
|
||||
DECLARE_CONFIG_SERIALISER(LogFormat)
|
||||
|
||||
template<typename T>
|
||||
T BaseSetting<T>::parse(const std::string & str, const ApplyConfigOptions & options) const
|
||||
|
||||
@@ -1,4 +1,48 @@
|
||||
#include "lix/libutil/log-format.hh"
|
||||
|
||||
#include "lix/libutil/abstract-setting-to-json.hh" // IWYU pragma: keep
|
||||
#include "lix/libutil/json.hh"
|
||||
#include "lix/libutil/log-format.hh"
|
||||
|
||||
#include <format>
|
||||
|
||||
namespace nix {
|
||||
template<>
|
||||
std::string BaseSetting<LogFormat>::to_string() const
|
||||
{
|
||||
return std::format("{}", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
LogFormat
|
||||
BaseSetting<LogFormat>::parse(const std::string & str, const ApplyConfigOptions & options) const
|
||||
{
|
||||
if (auto const parsed = LogFormat::parse(str)) {
|
||||
return *parsed;
|
||||
}
|
||||
throw UsageError("setting '%s' has invalid value '%s'", name, str);
|
||||
}
|
||||
|
||||
void to_json(JSON & j, const LogFormat & self)
|
||||
{
|
||||
j = std::format("{}", self);
|
||||
}
|
||||
|
||||
void from_json(const JSON & j, LogFormat & self)
|
||||
{
|
||||
std::string asStr = ensureType(j, JSON::value_t::string);
|
||||
auto const parsed = LogFormat::parse(asStr);
|
||||
if (!parsed) {
|
||||
throw Error("invalid json for 'log-format': %s", j);
|
||||
}
|
||||
self = *parsed;
|
||||
}
|
||||
|
||||
// Explicitly instantiate the non-specialized templates.
|
||||
// `abstract-setting-to-json.hh` is IWYU-kept so this line also instantiates that template.
|
||||
template class BaseSetting<LogFormat>;
|
||||
|
||||
}
|
||||
|
||||
static_assert(std::formattable<nix::LogFormat, char>);
|
||||
static_assert(std::formattable<nix::LogFormatValue, char>);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "lix/libutil/config.hh"
|
||||
#include "lix/libutil/fmt.hh"
|
||||
#include "lix/libutil/json-fwd.hh"
|
||||
|
||||
@@ -156,6 +157,30 @@ struct json::is_integral_enum<nix::LogFormat> : std::true_type {};
|
||||
template<>
|
||||
struct json::is_integral_enum<nix::LogFormatValue> : std::true_type {};
|
||||
|
||||
/** Note: you'll have to include `config-impl.hh` when you want to use methods from this type. */
|
||||
struct LogFormatSetting : public BaseSetting<LogFormat>
|
||||
{
|
||||
// I hate global state, man.
|
||||
LogFormat autoValue = LogFormat::RawWithLogs;
|
||||
|
||||
LogFormatSetting(
|
||||
Config * options,
|
||||
const LogFormat & def,
|
||||
const std::string & name,
|
||||
const std::string & description,
|
||||
const std::set<std::string> & aliases = {},
|
||||
bool documentDefault = true,
|
||||
std::optional<ExperimentalFeature> experimentalFeature = std::nullopt,
|
||||
bool deprecated = false
|
||||
) : BaseSetting<LogFormat>(def, true, name, description, aliases, experimentalFeature, deprecated)
|
||||
{
|
||||
options->addSetting(this);
|
||||
}
|
||||
};
|
||||
|
||||
void to_json(JSON & j, const LogFormat & self);
|
||||
void from_json(const JSON & j, LogFormat & self);
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: log-format
|
||||
internalName: logFormat
|
||||
settingType: LogFormatSetting
|
||||
defaultExpr: 'LogFormat::Auto'
|
||||
defaultText: auto
|
||||
---
|
||||
Set the format of log output; one of `raw`, `internal-json`, `bar`, `bar-with-logs`, `multiline` or `multiline-with-logs`.
|
||||
|
||||
For legacy reasons, the default value "auto" makes the actual log format depend on which command you're using.
|
||||
The legacy `nix-` CLI will use `raw-with-logs` (or `raw` with `-Q`/`--no-build-output`), and `nix3` commands will use `bar-with-logs`.
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "c-calls.hh"
|
||||
#include "lix/libutil/config-impl.hh"
|
||||
#include "lix/libutil/environment-variables.hh"
|
||||
#include "lix/libutil/file-descriptor.hh"
|
||||
#include "lix/libutil/logging.hh"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "lix/libutil/types.hh"
|
||||
#include "lix/libutil/error.hh"
|
||||
#include "lix/libutil/config.hh"
|
||||
#include "lix/libutil/log-format.hh"
|
||||
#include "lix/libutil/log-format.hh" // IWYU pragma: keep
|
||||
#include "result.hh"
|
||||
#include "serialise.hh"
|
||||
#include <kj/async.h>
|
||||
|
||||
@@ -282,7 +282,10 @@ libutil_settings_headers += custom_target(
|
||||
)
|
||||
|
||||
logging_setting_definitions = files(
|
||||
# keep-sorted start
|
||||
'logging-settings/log-format.md',
|
||||
'logging-settings/show-trace.md',
|
||||
# keep-sorted end
|
||||
)
|
||||
libutil_settings_headers += custom_target(
|
||||
command : [
|
||||
|
||||
+7
-2
@@ -228,7 +228,9 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs, virtual RootArgs
|
||||
.shortName = 'L',
|
||||
.description = "Print full build logs on standard error.",
|
||||
.category = loggingCategory,
|
||||
.handler = {[&]() { logger->setPrintBuildLogs(true); }},
|
||||
.handler = {[&]() {
|
||||
loggerSettings.logFormat.setDefault(loggerSettings.logFormat.get().withLogs());
|
||||
}},
|
||||
.experimentalFeature = Xp::NixCommand,
|
||||
});
|
||||
|
||||
@@ -500,7 +502,7 @@ int mainWrapped(AsyncIoRoot & aio, int argc, char ** argv)
|
||||
|
||||
evalSettings.pureEval.setDefault(true);
|
||||
|
||||
setLogFormat(LogFormat::BarWithLogs);
|
||||
loggerSettings.logFormat.autoValue = LogFormat::BarWithLogs;
|
||||
|
||||
// FIXME: stop messing about with log verbosity depending on if it is interactive use
|
||||
if (isatty(STDERR_FILENO)) {
|
||||
@@ -578,6 +580,9 @@ int mainWrapped(AsyncIoRoot & aio, int argc, char ** argv)
|
||||
if (!args.helpRequested && !args.completions) throw;
|
||||
}
|
||||
|
||||
// HACK: after args.parseCmdline() we re-create the default logger, to apply --option flags.
|
||||
createDefaultLogger();
|
||||
|
||||
if (args.completions) {
|
||||
switch (args.completions->type) {
|
||||
case Completions::Type::Normal:
|
||||
|
||||
+3
-2
@@ -188,8 +188,9 @@ static int main_nix_prefetch_url(AsyncIoRoot & aio, std::string programName, Str
|
||||
if (args.size() > 2)
|
||||
throw UsageError("too many arguments");
|
||||
|
||||
if (isOutputARealTerminal(StandardOutputStream::Stderr))
|
||||
setLogFormat(LogFormat::Bar);
|
||||
if (isOutputARealTerminal(StandardOutputStream::Stderr)) {
|
||||
loggerSettings.logFormat.autoValue = LogFormat::Bar;
|
||||
}
|
||||
|
||||
auto store = aio.blockOn(openStore());
|
||||
auto evaluator = std::make_unique<Evaluator>(aio, myArgs.searchPath, store);
|
||||
|
||||
@@ -131,9 +131,9 @@ def test_completions_flake_update(nix: Nix, files: Path):
|
||||
|
||||
def test_flag_completion(nix: Nix):
|
||||
nix.env["NIX_GET_COMPLETIONS"] = "2"
|
||||
res = nix.nix(["build", "--log-form"]).run().ok()
|
||||
assert "--log-format" in res.stdout_plain
|
||||
assert "Set the format of log output; one of" in res.stdout_plain
|
||||
res = nix.nix(["build", "--dry"]).run().ok()
|
||||
assert "--dry-run" in res.stdout_plain
|
||||
assert "Show what this command would do without doing it" in res.stdout_plain
|
||||
|
||||
|
||||
def test_option_completion(nix: Nix):
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "lix/libexpr/eval.hh"
|
||||
#include "lix/libmain/progress-bar.hh"
|
||||
#include "lix/libmain/loggers.hh"
|
||||
#include "lix/libutil/config-impl.hh"
|
||||
#include "lix/libutil/logging.hh"
|
||||
#include "lix/libmain/shared.hh"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user