From 4c35ede5479254ea3776876d40d3182fca03971d Mon Sep 17 00:00:00 2001 From: Rebecca Turner Date: Sat, 3 Feb 2024 16:18:00 -0800 Subject: [PATCH] Convert `--log-format` CLI argument to setting --- src/libmain/common-args.cc | 8 ------ src/libmain/shared.cc | 2 +- src/libutil/config-impl.hh | 56 ++++++++++++++++++++++++++++++++++++++ src/libutil/config.cc | 2 ++ src/libutil/json-utils.hh | 4 +++ src/libutil/logging.hh | 20 ++++++++++++++ src/nix/main.cc | 37 +++++++++++++++++-------- 7 files changed, 108 insertions(+), 21 deletions(-) diff --git a/src/libmain/common-args.cc b/src/libmain/common-args.cc index db6a5de3860..ff258112adf 100644 --- a/src/libmain/common-args.cc +++ b/src/libmain/common-args.cc @@ -55,14 +55,6 @@ MixCommonArgs::MixCommonArgs(const std::string & programName) } }); - addFlag({ - .longName = "log-format", - .description = "Set the format of log output; one of `raw`, `internal-json`, `bar` or `bar-with-logs`.", - .category = loggingCategory, - .labels = {"format"}, - .handler = {[](std::string format) { setLogFormat(format); }}, - }); - addFlag({ .longName = "max-jobs", .shortName = 'j', diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 5467ba26738..9cf9d8c4ad7 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -182,7 +182,7 @@ LegacyArgs::LegacyArgs(const std::string & programName, .longName = "no-build-output", .shortName = 'Q', .description = "Do not show build output.", - .handler = {[&]() {setLogFormat(LogFormat::raw); }}, + .handler = {[&]() {loggerSettings.logFormat.assign(LogFormat::raw); }}, }); addFlag({ diff --git a/src/libutil/config-impl.hh b/src/libutil/config-impl.hh index 6431ec1e0f2..aac7d40dff8 100644 --- a/src/libutil/config-impl.hh +++ b/src/libutil/config-impl.hh @@ -132,4 +132,60 @@ std::string Setting::to_string() const return std::to_string(value); } +template<> +LogFormat Setting::parse(const std::string & str) const +{ + auto format = parseLogFormat(str); + if (format.has_value()) { + return format.value(); + } else { + throw UsageError("setting '%s' has invalid value '%s'", name, str); + } +} + +template<> +std::string Setting::to_string() const +{ + return logFormatToString(value); +} + +template<> +void Setting::convertToArg(Args &args, const std::string &category) +{ + args.addFlag({ + .longName = name, + .description = fmt("Set the `%s` setting.", name), + .category = category, + .labels = {"format"}, + .handler = {[this](std::string format) { override(parse(format)); }}, + .experimentalFeature = experimentalFeature, + }); +} + +template<> +std::optional Setting>::parse(const std::string & str) const +{ + if (str.empty()) { + return std::nullopt; + } + + auto format = parseLogFormat(str); + if (format.has_value()) { + return format.value(); + } else { + throw UsageError("setting '%s' has invalid value '%s'", name, str); + } +} + +template<> +std::string Setting>::to_string() const +{ + if (value.has_value()) { + return logFormatToString(value.value()); + } else { + // TODO: Will returning the empty string here cause problems? + return ""; + } +} + } diff --git a/src/libutil/config.cc b/src/libutil/config.cc index 338b6ff0994..18acaf65ad9 100644 --- a/src/libutil/config.cc +++ b/src/libutil/config.cc @@ -387,6 +387,8 @@ template class Setting; template class Setting; template class Setting; template class Setting>; +template class Setting; +template class Setting>; static Path parsePath(const AbstractSetting & s, const std::string & str) { diff --git a/src/libutil/json-utils.hh b/src/libutil/json-utils.hh index 06dd80cf7d0..73f84cc5cf0 100644 --- a/src/libutil/json-utils.hh +++ b/src/libutil/json-utils.hh @@ -64,6 +64,10 @@ struct json_avoids_null> : std::true_type {}; template struct json_avoids_null> : std::true_type {}; +enum class LogFormat; +template<> +struct json_avoids_null : std::true_type {}; + } namespace nlohmann { diff --git a/src/libutil/logging.hh b/src/libutil/logging.hh index 54d7fa83911..97fcdb59744 100644 --- a/src/libutil/logging.hh +++ b/src/libutil/logging.hh @@ -83,6 +83,26 @@ struct LoggerSettings : Config Whether Nix should print out a stack trace in case of Nix expression evaluation errors. )"}; + + Setting logFormat{ + this, LogFormat::raw, "log-format", + R"( + The log format to use. + One of `raw`, `raw-with-logs`, `internal-json`, `bar`, or `bar-with-logs`. + )", + {}, + false, + std::nullopt, + {[](const LogFormat & value) { + setLogFormat(value); + }}}; + + Setting> logFormatLegacy{ + this, std::nullopt, "log-format-legacy", + R"( + The log format to use for legacy commands like `nix-build` and `nix-shell`. + One of `raw`, `raw-with-logs`, `internal-json`, `bar`, or `bar-with-logs`. + )"}; }; extern LoggerSettings loggerSettings; diff --git a/src/nix/main.cc b/src/nix/main.cc index 9cac407716d..46226acd2ad 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -322,6 +322,22 @@ void mainWrapped(int argc, char * * argv) return; } + programPath = argv[0]; + auto programName = std::string(baseNameOf(programPath)); + auto legacy = (*RegisterLegacyCommand::commands)[programName]; + + if (!legacy) { + // New-style commands default to `bar` logs. + // `initNix()` reads configuration files and will override this setting + // if it's set. + loggerSettings.logFormat.assign(LogFormat::bar); + } + + if (argc > 1 && std::string_view(argv[1]) == "__build-remote") { + programName = "build-remote"; + argv++; argc--; + } + initNix(); initGC(); @@ -337,22 +353,19 @@ void mainWrapped(int argc, char * * argv) Finally f([] { logger->stop(); }); - programPath = argv[0]; - auto programName = std::string(baseNameOf(programPath)); - - if (argc > 1 && std::string_view(argv[1]) == "__build-remote") { - programName = "build-remote"; - argv++; argc--; - } - - { - auto legacy = (*RegisterLegacyCommand::commands)[programName]; - if (legacy) return legacy(argc, argv); + if (legacy) { + // If we're in a legacy command and `logFormatLegacy` has a value, use + // that for the log format setting. + if (loggerSettings.logFormatLegacy.get().has_value()) { + loggerSettings.logFormat.assign( + loggerSettings.logFormatLegacy.get().value() + ); + } + return legacy(argc, argv); } evalSettings.pureEval = true; - setLogFormat("bar"); settings.verboseBuild = false; if (isatty(STDERR_FILENO)) { verbosity = lvlNotice;