diff options
author | eldritch horrors <pennae@lix.systems> | 2024-03-08 08:10:05 +0100 |
---|---|---|
committer | eldritch horrors <pennae@lix.systems> | 2024-03-09 07:00:13 -0700 |
commit | b221a14f0a477db06f8ab705bd08404e431ec135 (patch) | |
tree | 33cab3bfa39ca17a070e1afca13e531052021eee /src | |
parent | 3d9c7fc1e72e3471ae35c96ec418e8ac0913b099 (diff) |
Merge pull request #9925 from 9999years/fmt-cleanup
Cleanup `fmt.hh`
(cherry picked from commit 47a1dbb4b8e7913cbb9b4d604728b912e76e4ca0)
Change-Id: Id076a45cb39652f437fe3f8bda10c310a9894777
Diffstat (limited to 'src')
29 files changed, 202 insertions, 151 deletions
diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc index 519e03242..118468477 100644 --- a/src/build-remote/build-remote.cc +++ b/src/build-remote/build-remote.cc @@ -202,7 +202,7 @@ static int main_build_remote(int argc, char * * argv) else drvstr = "<unknown>"; - auto error = hintformat(errorText); + auto error = HintFmt(errorText); error % drvstr % neededSystem diff --git a/src/libexpr/eval-error.cc b/src/libexpr/eval-error.cc index 250c59a19..f4cdeec5c 100644 --- a/src/libexpr/eval-error.cc +++ b/src/libexpr/eval-error.cc @@ -28,7 +28,7 @@ template<class T> EvalErrorBuilder<T> & EvalErrorBuilder<T>::withTrace(PosIdx pos, const std::string_view text) { error.err.traces.push_front( - Trace{.pos = error.state.positions[pos], .hint = hintfmt(std::string(text)), .frame = false}); + Trace{.pos = error.state.positions[pos], .hint = HintFmt(std::string(text)), .frame = false}); return *this; } @@ -36,7 +36,7 @@ template<class T> EvalErrorBuilder<T> & EvalErrorBuilder<T>::withFrameTrace(PosIdx pos, const std::string_view text) { error.err.traces.push_front( - Trace{.pos = error.state.positions[pos], .hint = hintformat(std::string(text)), .frame = true}); + Trace{.pos = error.state.positions[pos], .hint = HintFmt(std::string(text)), .frame = true}); return *this; } @@ -57,13 +57,13 @@ EvalErrorBuilder<T> & EvalErrorBuilder<T>::withFrame(const Env & env, const Expr .pos = error.state.positions[expr.getPos()], .expr = expr, .env = env, - .hint = hintformat("Fake frame for debugging purposes"), + .hint = HintFmt("Fake frame for debugging purposes"), .isError = true}); return *this; } template<class T> -EvalErrorBuilder<T> & EvalErrorBuilder<T>::addTrace(PosIdx pos, hintformat hint, bool frame) +EvalErrorBuilder<T> & EvalErrorBuilder<T>::addTrace(PosIdx pos, HintFmt hint, bool frame) { error.addTrace(error.state.positions[pos], hint, frame); return *this; @@ -75,7 +75,7 @@ EvalErrorBuilder<T> & EvalErrorBuilder<T>::addTrace(PosIdx pos, std::string_view formatString, const Args &... formatArgs) { - addTrace(error.state.positions[pos], hintfmt(std::string(formatString), formatArgs...)); + addTrace(error.state.positions[pos], HintFmt(std::string(formatString), formatArgs...)); return *this; } diff --git a/src/libexpr/eval-error.hh b/src/libexpr/eval-error.hh index e9076f28b..2bb607280 100644 --- a/src/libexpr/eval-error.hh +++ b/src/libexpr/eval-error.hh @@ -90,7 +90,7 @@ public: [[nodiscard, gnu::noinline]] EvalErrorBuilder<T> & withFrame(const Env & e, const Expr & ex); - [[nodiscard, gnu::noinline]] EvalErrorBuilder<T> & addTrace(PosIdx pos, hintformat hint, bool frame = false); + [[nodiscard, gnu::noinline]] EvalErrorBuilder<T> & addTrace(PosIdx pos, HintFmt hint, bool frame = false); template<typename... Args> [[nodiscard, gnu::noinline]] EvalErrorBuilder<T> & diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index fac67950b..ba9fe9c65 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -809,7 +809,7 @@ void EvalState::addErrorTrace(Error & e, const char * s, const std::string & s2) void EvalState::addErrorTrace(Error & e, const PosIdx pos, const char * s, const std::string & s2, bool frame) const { - e.addTrace(positions[pos], hintfmt(s, s2), frame); + e.addTrace(positions[pos], HintFmt(s, s2), frame); } template<typename... Args> @@ -825,7 +825,7 @@ static std::unique_ptr<DebugTraceStacker> makeDebugTraceStacker( .pos = std::move(pos), .expr = expr, .env = env, - .hint = hintfmt(formatArgs...), + .hint = HintFmt(formatArgs...), .isError = false }); } @@ -2782,7 +2782,7 @@ std::optional<std::string> EvalState::resolveSearchPathPath(const SearchPath::Pa res = { store->toRealPath(storePath) }; } catch (FileTransferError & e) { logWarning({ - .msg = hintfmt("Nix search path entry '%1%' cannot be downloaded, ignoring", value) + .msg = HintFmt("Nix search path entry '%1%' cannot be downloaded, ignoring", value) }); res = std::nullopt; } @@ -2802,7 +2802,7 @@ std::optional<std::string> EvalState::resolveSearchPathPath(const SearchPath::Pa res = { path }; else { logWarning({ - .msg = hintfmt("Nix search path entry '%1%' does not exist, ignoring", value) + .msg = HintFmt("Nix search path entry '%1%' does not exist, ignoring", value) }); res = std::nullopt; } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 325ae792c..135e5fecb 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -147,7 +147,7 @@ struct DebugTrace { std::shared_ptr<Pos> pos; const Expr & expr; const Env & env; - hintformat hint; + HintFmt hint; bool isError; }; diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index e45526a6c..305d84a68 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -148,7 +148,7 @@ static FlakeInput parseFlakeInput(EvalState & state, } catch (Error & e) { e.addTrace( state.positions[attr.pos], - hintfmt("while evaluating flake attribute '%s'", state.symbols[attr.name])); + HintFmt("while evaluating flake attribute '%s'", state.symbols[attr.name])); throw; } } @@ -157,7 +157,7 @@ static FlakeInput parseFlakeInput(EvalState & state, try { input.ref = FlakeRef::fromAttrs(attrs); } catch (Error & e) { - e.addTrace(state.positions[pos], hintfmt("while evaluating flake input")); + e.addTrace(state.positions[pos], HintFmt("while evaluating flake input")); throw; } else { diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l index fb06c3d69..adb9d9757 100644 --- a/src/libexpr/lexer.l +++ b/src/libexpr/lexer.l @@ -153,7 +153,7 @@ or { return OR_KW; } yylval->n = boost::lexical_cast<int64_t>(yytext); } catch (const boost::bad_lexical_cast &) { throw ParseError(ErrorInfo{ - .msg = hintfmt("invalid integer '%1%'", yytext), + .msg = HintFmt("invalid integer '%1%'", yytext), .pos = state->positions[CUR_POS], }); } @@ -163,7 +163,7 @@ or { return OR_KW; } yylval->nf = strtod(yytext, 0); if (errno != 0) throw ParseError(ErrorInfo{ - .msg = hintfmt("invalid float '%1%'", yytext), + .msg = HintFmt("invalid float '%1%'", yytext), .pos = state->positions[CUR_POS], }); return FLOAT; @@ -292,7 +292,7 @@ or { return OR_KW; } <INPATH_SLASH>{ANY} | <INPATH_SLASH><<EOF>> { throw ParseError(ErrorInfo{ - .msg = hintfmt("path has a trailing slash"), + .msg = HintFmt("path has a trailing slash"), .pos = state->positions[CUR_POS], }); } diff --git a/src/libexpr/parser-state.hh b/src/libexpr/parser-state.hh index 2fc072ca4..acadb676d 100644 --- a/src/libexpr/parser-state.hh +++ b/src/libexpr/parser-state.hh @@ -63,7 +63,7 @@ struct ParserState inline void ParserState::dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos) { throw ParseError({ - .msg = hintfmt("attribute '%1%' already defined at %2%", + .msg = HintFmt("attribute '%1%' already defined at %2%", showAttrPath(symbols, attrPath), positions[prevPos]), .pos = positions[pos] }); @@ -72,7 +72,7 @@ inline void ParserState::dupAttr(const AttrPath & attrPath, const PosIdx pos, co inline void ParserState::dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos) { throw ParseError({ - .msg = hintfmt("attribute '%1%' already defined at %2%", symbols[attr], positions[prevPos]), + .msg = HintFmt("attribute '%1%' already defined at %2%", symbols[attr], positions[prevPos]), .pos = positions[pos] }); } @@ -153,13 +153,13 @@ inline Formals * ParserState::validateFormals(Formals * formals, PosIdx pos, Sym } if (duplicate) throw ParseError({ - .msg = hintfmt("duplicate formal function argument '%1%'", symbols[duplicate->first]), + .msg = HintFmt("duplicate formal function argument '%1%'", symbols[duplicate->first]), .pos = positions[duplicate->second] }); if (arg && formals->has(arg)) throw ParseError({ - .msg = hintfmt("duplicate formal function argument '%1%'", symbols[arg]), + .msg = HintFmt("duplicate formal function argument '%1%'", symbols[arg]), .pos = positions[pos] }); diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index fc83ee2dd..447e4d61a 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -63,7 +63,7 @@ using namespace nix; void yyerror(YYLTYPE * loc, yyscan_t scanner, ParserState * state, const char * error) { throw ParseError({ - .msg = hintfmt(error), + .msg = HintFmt(error), .pos = state->positions[state->at(*loc)] }); } @@ -152,7 +152,7 @@ expr_function | LET binds IN expr_function { if (!$2->dynamicAttrs.empty()) throw ParseError({ - .msg = hintfmt("dynamic attributes not allowed in let"), + .msg = HintFmt("dynamic attributes not allowed in let"), .pos = state->positions[CUR_POS] }); $$ = new ExprLet($2, $4); @@ -242,7 +242,7 @@ expr_simple static bool noURLLiterals = experimentalFeatureSettings.isEnabled(Xp::NoUrlLiterals); if (noURLLiterals) throw ParseError({ - .msg = hintfmt("URL literals are disabled"), + .msg = HintFmt("URL literals are disabled"), .pos = state->positions[CUR_POS] }); $$ = new ExprString(std::string($1)); @@ -338,7 +338,7 @@ attrs delete str; } else throw ParseError({ - .msg = hintfmt("dynamic attributes not allowed in inherit"), + .msg = HintFmt("dynamic attributes not allowed in inherit"), .pos = state->positions[state->at(@2)] }); } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 8e06d55a1..86db527f6 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -748,7 +748,7 @@ static RegisterPrimOp primop_break({ if (state.debugRepl && !state.debugTraces.empty()) { auto error = Error(ErrorInfo { .level = lvlInfo, - .msg = hintfmt("breakpoint reached"), + .msg = HintFmt("breakpoint reached"), .pos = state.positions[pos], }); @@ -759,7 +759,7 @@ static RegisterPrimOp primop_break({ // If the user elects to quit the repl, throw an exception. throw Error(ErrorInfo{ .level = lvlInfo, - .msg = hintfmt("quit the debugger"), + .msg = HintFmt("quit the debugger"), .pos = nullptr, }); } @@ -814,7 +814,7 @@ static void prim_addErrorContext(EvalState & state, const PosIdx pos, Value * * auto message = state.coerceToString(pos, *args[0], context, "while evaluating the error message passed to builtins.addErrorContext", false, false).toOwned(); - e.addTrace(nullptr, hintfmt(message), true); + e.addTrace(nullptr, HintFmt(message), true); throw; } } @@ -1065,7 +1065,7 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * * often results from the composition of several functions * (derivationStrict, derivation, mkDerivation, mkPythonModule, etc.) */ - e.addTrace(nullptr, hintfmt( + e.addTrace(nullptr, HintFmt( "while evaluating derivation '%s'\n" " whose name attribute is located at %s", drvName, pos), true); @@ -1226,7 +1226,7 @@ drvName, Bindings * attrs, Value & v) } catch (Error & e) { e.addTrace(state.positions[i->pos], - hintfmt("while evaluating attribute '%1%' of derivation '%2%'", key, drvName), + HintFmt("while evaluating attribute '%1%' of derivation '%2%'", key, drvName), true); throw; } diff --git a/src/libexpr/primops/fetchClosure.cc b/src/libexpr/primops/fetchClosure.cc index ca2a3df9c..3804db6eb 100644 --- a/src/libexpr/primops/fetchClosure.cc +++ b/src/libexpr/primops/fetchClosure.cc @@ -22,7 +22,7 @@ static void runFetchClosureWithRewrite(EvalState & state, const PosIdx pos, Stor auto rewrittenPath = makeContentAddressed(fromStore, *state.store, fromPath); if (toPathMaybe && *toPathMaybe != rewrittenPath) throw Error({ - .msg = hintfmt("rewriting '%s' to content-addressed form yielded '%s', while '%s' was expected", + .msg = HintFmt("rewriting '%s' to content-addressed form yielded '%s', while '%s' was expected", state.store->printStorePath(fromPath), state.store->printStorePath(rewrittenPath), state.store->printStorePath(*toPathMaybe)), @@ -30,7 +30,7 @@ static void runFetchClosureWithRewrite(EvalState & state, const PosIdx pos, Stor }); if (!toPathMaybe) throw Error({ - .msg = hintfmt( + .msg = HintFmt( "rewriting '%s' to content-addressed form yielded '%s'\n" "Use this value for the 'toPath' attribute passed to 'fetchClosure'", state.store->printStorePath(fromPath), @@ -49,7 +49,7 @@ static void runFetchClosureWithRewrite(EvalState & state, const PosIdx pos, Stor // We don't perform the rewriting when outPath already exists, as an optimisation. // However, we can quickly detect a mistake if the toPath is input addressed. throw Error({ - .msg = hintfmt( + .msg = HintFmt( "The 'toPath' value '%s' is input-addressed, so it can't possibly be the result of rewriting to a content-addressed path.\n\n" "Set 'toPath' to an empty string to make Nix report the correct content-addressed path.", state.store->printStorePath(toPath)), @@ -72,7 +72,7 @@ static void runFetchClosureWithContentAddressedPath(EvalState & state, const Pos if (!info->isContentAddressed(*state.store)) { throw Error({ - .msg = hintfmt( + .msg = HintFmt( "The 'fromPath' value '%s' is input-addressed, but 'inputAddressed' is set to 'false' (default).\n\n" "If you do intend to fetch an input-addressed store path, add\n\n" " inputAddressed = true;\n\n" @@ -98,7 +98,7 @@ static void runFetchClosureWithInputAddressedPath(EvalState & state, const PosId if (info->isContentAddressed(*state.store)) { throw Error({ - .msg = hintfmt( + .msg = HintFmt( "The store object referred to by 'fromPath' at '%s' is not input-addressed, but 'inputAddressed' is set to 'true'.\n\n" "Remove the 'inputAddressed' attribute (it defaults to 'false') to expect 'fromPath' to be content-addressed", state.store->printStorePath(fromPath)), @@ -152,14 +152,14 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg else throw Error({ - .msg = hintfmt("attribute '%s' isn't supported in call to 'fetchClosure'", attrName), + .msg = HintFmt("attribute '%s' isn't supported in call to 'fetchClosure'", attrName), .pos = state.positions[pos] }); } if (!fromPath) throw Error({ - .msg = hintfmt("attribute '%s' is missing in call to 'fetchClosure'", "fromPath"), + .msg = HintFmt("attribute '%s' is missing in call to 'fetchClosure'", "fromPath"), .pos = state.positions[pos] }); @@ -168,7 +168,7 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg if (inputAddressed) { if (toPath) throw Error({ - .msg = hintfmt("attribute '%s' is set to true, but '%s' is also set. Please remove one of them", + .msg = HintFmt("attribute '%s' is set to true, but '%s' is also set. Please remove one of them", "inputAddressed", "toPath"), .pos = state.positions[pos] @@ -177,7 +177,7 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg if (!fromStoreUrl) throw Error({ - .msg = hintfmt("attribute '%s' is missing in call to 'fetchClosure'", "fromStore"), + .msg = HintFmt("attribute '%s' is missing in call to 'fetchClosure'", "fromStore"), .pos = state.positions[pos] }); @@ -187,13 +187,13 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg parsedURL.scheme != "https" && !(getEnv("_NIX_IN_TEST").has_value() && parsedURL.scheme == "file")) throw Error({ - .msg = hintfmt("'fetchClosure' only supports http:// and https:// stores"), + .msg = HintFmt("'fetchClosure' only supports http:// and https:// stores"), .pos = state.positions[pos] }); if (!parsedURL.query.empty()) throw Error({ - .msg = hintfmt("'fetchClosure' does not support URL query parameters (in '%s')", *fromStoreUrl), + .msg = HintFmt("'fetchClosure' does not support URL query parameters (in '%s')", *fromStoreUrl), .pos = state.positions[pos] }); diff --git a/src/libexpr/print.cc b/src/libexpr/print.cc index 86eadfb17..b792f657d 100644 --- a/src/libexpr/print.cc +++ b/src/libexpr/print.cc @@ -510,7 +510,7 @@ std::ostream & operator<<(std::ostream & output, const ValuePrinter & printer) } template<> -hintformat & hintformat::operator%(const ValuePrinter & value) +HintFmt & HintFmt::operator%(const ValuePrinter & value) { fmt % value; return *this; diff --git a/src/libexpr/print.hh b/src/libexpr/print.hh index a542bc7b1..7ddda81b8 100644 --- a/src/libexpr/print.hh +++ b/src/libexpr/print.hh @@ -86,6 +86,6 @@ std::ostream & operator<<(std::ostream & output, const ValuePrinter & printer); * magenta. */ template<> -hintformat & hintformat::operator%(const ValuePrinter & value); +HintFmt & HintFmt::operator%(const ValuePrinter & value); } diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc index ab479520b..787a46426 100644 --- a/src/libexpr/value-to-json.cc +++ b/src/libexpr/value-to-json.cc @@ -64,7 +64,7 @@ json printValueAsJSON(EvalState & state, bool strict, out[j] = printValueAsJSON(state, strict, *a.value, a.pos, context, copyToStore); } catch (Error & e) { e.addTrace(state.positions[a.pos], - hintfmt("while evaluating attribute '%1%'", j)); + HintFmt("while evaluating attribute '%1%'", j)); throw; } } @@ -81,7 +81,7 @@ json printValueAsJSON(EvalState & state, bool strict, out.push_back(printValueAsJSON(state, strict, *elem, pos, context, copyToStore)); } catch (Error & e) { e.addTrace(state.positions[pos], - hintfmt("while evaluating list element at index %1%", i)); + HintFmt("while evaluating list element at index %1%", i)); throw; } i++; diff --git a/src/libexpr/value/context.hh b/src/libexpr/value/context.hh index 9f1d59317..998b70e36 100644 --- a/src/libexpr/value/context.hh +++ b/src/libexpr/value/context.hh @@ -20,8 +20,8 @@ public: : Error("") { raw = raw_; - auto hf = hintfmt(args...); - err.msg = hintfmt("Bad String Context element: %1%: %2%", normaltxt(hf.str()), raw); + auto hf = HintFmt(args...); + err.msg = HintFmt("Bad String Context element: %1%: %2%", Uncolored(hf.str()), raw); } }; diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc index dadaccbcf..5de6d8d79 100644 --- a/src/libstore/build/derivation-goal.cc +++ b/src/libstore/build/derivation-goal.cc @@ -708,7 +708,7 @@ void DerivationGoal::tryToBuild() if (!outputLocks.lockPaths(lockFiles, "", false)) { if (!actLock) actLock = std::make_unique<Activity>(*logger, lvlWarn, actBuildWaiting, - fmt("waiting for lock on %s", magentatxt(showPaths(lockFiles)))); + fmt("waiting for lock on %s", Magenta(showPaths(lockFiles)))); worker.waitForAWhile(shared_from_this()); return; } @@ -762,7 +762,7 @@ void DerivationGoal::tryToBuild() the wake-up timeout expires. */ if (!actLock) actLock = std::make_unique<Activity>(*logger, lvlWarn, actBuildWaiting, - fmt("waiting for a machine to build '%s'", magentatxt(worker.store.printStorePath(drvPath)))); + fmt("waiting for a machine to build '%s'", Magenta(worker.store.printStorePath(drvPath)))); worker.waitForAWhile(shared_from_this()); outputLocks.unlock(); return; @@ -987,7 +987,7 @@ void DerivationGoal::buildDone() diskFull |= cleanupDecideWhetherDiskFull(); auto msg = fmt("builder for '%s' %s", - magentatxt(worker.store.printStorePath(drvPath)), + Magenta(worker.store.printStorePath(drvPath)), statusToString(status)); if (!logger->isVerbose() && !logTail.empty()) { @@ -1523,7 +1523,7 @@ void DerivationGoal::done( outputLocks.unlock(); buildResult.status = status; if (ex) - buildResult.errorMsg = fmt("%s", normaltxt(ex->info().msg)); + buildResult.errorMsg = fmt("%s", Uncolored(ex->info().msg)); if (buildResult.status == BuildResult::TimedOut) worker.timedOut = true; if (buildResult.status == BuildResult::PermanentFailure) diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc index 8e5ab7594..c4fae0eaa 100644 --- a/src/libstore/build/local-derivation-goal.cc +++ b/src/libstore/build/local-derivation-goal.cc @@ -87,7 +87,7 @@ void handleDiffHook( } catch (Error & error) { ErrorInfo ei = error.info(); // FIXME: wrap errors. - ei.msg = hintfmt("diff hook execution failed: %s", ei.msg.str()); + ei.msg = HintFmt("diff hook execution failed: %s", ei.msg.str()); logError(ei); } } @@ -227,7 +227,7 @@ void LocalDerivationGoal::tryLocalBuild() if (!buildUser) { if (!actLock) actLock = std::make_unique<Activity>(*logger, lvlWarn, actBuildWaiting, - fmt("waiting for a free build user ID for '%s'", magentatxt(worker.store.printStorePath(drvPath)))); + fmt("waiting for a free build user ID for '%s'", Magenta(worker.store.printStorePath(drvPath)))); worker.waitForAWhile(shared_from_this()); return; } diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc index a283af5a2..0d09fff98 100644 --- a/src/libstore/filetransfer.cc +++ b/src/libstore/filetransfer.cc @@ -881,12 +881,12 @@ template<typename... Args> FileTransferError::FileTransferError(FileTransfer::Error error, std::optional<std::string> response, const Args & ... args) : Error(args...), error(error), response(response) { - const auto hf = hintfmt(args...); + const auto hf = HintFmt(args...); // FIXME: Due to https://github.com/NixOS/nix/issues/3841 we don't know how // to print different messages for different verbosity levels. For now // we add some heuristics for detecting when we want to show the response. if (response && (response->size() < 1024 || response->find("<html>") != std::string::npos)) - err.msg = hintfmt("%1%\n\nresponse body:\n\n%2%", normaltxt(hf.str()), chomp(*response)); + err.msg = HintFmt("%1%\n\nresponse body:\n\n%2%", Uncolored(hf.str()), chomp(*response)); else err.msg = hf; } diff --git a/src/libstore/sqlite.cc b/src/libstore/sqlite.cc index 7c8decb74..365794bd3 100644 --- a/src/libstore/sqlite.cc +++ b/src/libstore/sqlite.cc @@ -9,19 +9,19 @@ namespace nix { -SQLiteError::SQLiteError(const char *path, const char *errMsg, int errNo, int extendedErrNo, int offset, hintformat && hf) +SQLiteError::SQLiteError(const char *path, const char *errMsg, int errNo, int extendedErrNo, int offset, HintFmt && hf) : Error(""), path(path), errMsg(errMsg), errNo(errNo), extendedErrNo(extendedErrNo), offset(offset) { auto offsetStr = (offset == -1) ? "" : "at offset " + std::to_string(offset) + ": "; - err.msg = hintfmt("%s: %s%s, %s (in '%s')", - normaltxt(hf.str()), + err.msg = HintFmt("%s: %s%s, %s (in '%s')", + Uncolored(hf.str()), offsetStr, sqlite3_errstr(extendedErrNo), errMsg, path ? path : "(in-memory)"); } -[[noreturn]] void SQLiteError::throw_(sqlite3 * db, hintformat && hf) +[[noreturn]] void SQLiteError::throw_(sqlite3 * db, HintFmt && hf) { int err = sqlite3_errcode(db); int exterr = sqlite3_extended_errcode(db); @@ -32,7 +32,7 @@ SQLiteError::SQLiteError(const char *path, const char *errMsg, int errNo, int ex if (err == SQLITE_BUSY || err == SQLITE_PROTOCOL) { auto exp = SQLiteBusy(path, errMsg, err, exterr, offset, std::move(hf)); - exp.err.msg = hintfmt( + exp.err.msg = HintFmt( err == SQLITE_PROTOCOL ? "SQLite database '%s' is busy (SQLITE_PROTOCOL)" : "SQLite database '%s' is busy", @@ -248,7 +248,7 @@ void handleSQLiteBusy(const SQLiteBusy & e, time_t & nextWarning) if (now > nextWarning) { nextWarning = now + 10; logWarning({ - .msg = hintfmt(e.what()) + .msg = HintFmt(e.what()) }); } diff --git a/src/libstore/sqlite.hh b/src/libstore/sqlite.hh index 0c08267f7..003e4d101 100644 --- a/src/libstore/sqlite.hh +++ b/src/libstore/sqlite.hh @@ -142,19 +142,19 @@ struct SQLiteError : Error template<typename... Args> [[noreturn]] static void throw_(sqlite3 * db, const std::string & fs, const Args & ... args) { - throw_(db, hintfmt(fs, args...)); + throw_(db, HintFmt(fs, args...)); } - SQLiteError(const char *path, const char *errMsg, int errNo, int extendedErrNo, int offset, hintformat && hf); + SQLiteError(const char *path, const char *errMsg, int errNo, int extendedErrNo, int offset, HintFmt && hf); protected: template<typename... Args> SQLiteError(const char *path, const char *errMsg, int errNo, int extendedErrNo, int offset, const std::string & fs, const Args & ... args) - : SQLiteError(path, errNo, extendedErrNo, offset, hintfmt(fs, args...)) + : SQLiteError(path, errMsg, errNo, extendedErrNo, offset, HintFmt(fs, args...)) { } - [[noreturn]] static void throw_(sqlite3 * db, hintformat && hf); + [[noreturn]] static void throw_(sqlite3 * db, HintFmt && hf); }; diff --git a/src/libutil/error.cc b/src/libutil/error.cc index 649caed86..49a18fa1c 100644 --- a/src/libutil/error.cc +++ b/src/libutil/error.cc @@ -10,7 +10,7 @@ namespace nix { const std::string nativeSystem = SYSTEM; -void BaseError::addTrace(std::shared_ptr<Pos> && e, hintformat hint, bool frame) +void BaseError::addTrace(std::shared_ptr<Pos> && e, HintFmt hint, bool frame) { err.traces.push_front(Trace { .pos = std::move(e), .hint = hint, .frame = frame }); } @@ -36,7 +36,7 @@ const std::string & BaseError::calcWhat() const std::optional<std::string> ErrorInfo::programName = std::nullopt; -std::ostream & operator <<(std::ostream & os, const hintformat & hf) +std::ostream & operator <<(std::ostream & os, const HintFmt & hf) { return os << hf.str(); } diff --git a/src/libutil/error.hh b/src/libutil/error.hh index d67b26e0f..0d978803e 100644 --- a/src/libutil/error.hh +++ b/src/libutil/error.hh @@ -63,7 +63,7 @@ void printCodeLines(std::ostream & out, struct Trace { std::shared_ptr<Pos> pos; - hintformat hint; + HintFmt hint; bool frame; }; @@ -74,7 +74,7 @@ inline bool operator>=(const Trace& lhs, const Trace& rhs); struct ErrorInfo { Verbosity level; - hintformat msg; + HintFmt msg; std::shared_ptr<Pos> pos; std::list<Trace> traces; @@ -113,20 +113,20 @@ public: template<typename... Args> BaseError(unsigned int status, const Args & ... args) - : err { .level = lvlError, .msg = hintfmt(args...), .status = status } + : err { .level = lvlError, .msg = HintFmt(args...), .status = status } { } template<typename... Args> explicit BaseError(const std::string & fs, const Args & ... args) - : err { .level = lvlError, .msg = hintfmt(fs, args...) } + : err { .level = lvlError, .msg = HintFmt(fs, args...) } { } template<typename... Args> BaseError(const Suggestions & sug, const Args & ... args) - : err { .level = lvlError, .msg = hintfmt(args...), .suggestions = sug } + : err { .level = lvlError, .msg = HintFmt(args...), .suggestions = sug } { } - BaseError(hintformat hint) + BaseError(HintFmt hint) : err { .level = lvlError, .msg = hint } { } @@ -159,10 +159,10 @@ public: template<typename... Args> void addTrace(std::shared_ptr<Pos> && e, std::string_view fs, const Args & ... args) { - addTrace(std::move(e), hintfmt(std::string(fs), args...)); + addTrace(std::move(e), HintFmt(std::string(fs), args...)); } - void addTrace(std::shared_ptr<Pos> && e, hintformat hint, bool frame = false); + void addTrace(std::shared_ptr<Pos> && e, HintFmt hint, bool frame = false); bool hasTrace() const { return !err.traces.empty(); } @@ -190,8 +190,8 @@ public: : Error("") { errNo = errNo_; - auto hf = hintfmt(args...); - err.msg = hintfmt("%1%: %2%", normaltxt(hf.str()), strerror(errNo)); + auto hf = HintFmt(args...); + err.msg = HintFmt("%1%: %2%", Uncolored(hf.str()), strerror(errNo)); } template<typename... Args> diff --git a/src/libutil/fmt.hh b/src/libutil/fmt.hh index f552a6b77..75354a07c 100644 --- a/src/libutil/fmt.hh +++ b/src/libutil/fmt.hh @@ -8,37 +8,64 @@ namespace nix { - -/** - * Inherit some names from other namespaces for convenience. - */ -using boost::format; - - -/** - * A variadic template that does nothing. Useful to call a function - * for all variadic arguments but ignoring the result. - */ -struct nop { template<typename... T> nop(T...) {} }; - - +namespace { /** - * A helper for formatting strings. ‘fmt(format, a_0, ..., a_n)’ is - * equivalent to ‘boost::format(format) % a_0 % ... % - * ... a_n’. However, ‘fmt(s)’ is equivalent to ‘s’ (so no %-expansion - * takes place). + * A helper for writing `boost::format` expressions. + * + * These are equivalent: + * + * ``` + * formatHelper(formatter, a_0, ..., a_n) + * formatter % a_0 % ... % a_n + * ``` + * + * With a single argument, `formatHelper(s)` is a no-op. */ template<class F> inline void formatHelper(F & f) -{ -} +{ } template<class F, typename T, typename... Args> inline void formatHelper(F & f, const T & x, const Args & ... args) { + // Interpolate one argument and then recurse. formatHelper(f % x, args...); } +/** + * Set the correct exceptions for `fmt`. + */ +void setExceptions(boost::format & fmt) +{ + fmt.exceptions( + boost::io::all_error_bits ^ + boost::io::too_many_args_bit ^ + boost::io::too_few_args_bit); +} +} + +/** + * A helper for writing a `boost::format` expression to a string. + * + * These are (roughly) equivalent: + * + * ``` + * fmt(formatString, a_0, ..., a_n) + * (boost::format(formatString) % a_0 % ... % a_n).str() + * ``` + * + * However, when called with a single argument, the string is returned + * unchanged. + * + * If you write code like this: + * + * ``` + * std::cout << boost::format(stringFromUserInput) << std::endl; + * ``` + * + * And `stringFromUserInput` contains formatting placeholders like `%s`, then + * the code will crash at runtime. `fmt` helps you avoid this pitfall. + */ inline std::string fmt(const std::string & s) { return s; @@ -53,66 +80,96 @@ template<typename... Args> inline std::string fmt(const std::string & fs, const Args & ... args) { boost::format f(fs); - f.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit); + setExceptions(f); formatHelper(f, args...); return f.str(); } -// format function for hints in errors. same as fmt, except templated values -// are always in magenta. +/** + * Values wrapped in this struct are printed in magenta. + * + * By default, arguments to `HintFmt` are printed in magenta. To avoid this, + * either wrap the argument in `Uncolored` or add a specialization of + * `HintFmt::operator%`. + */ template <class T> -struct magentatxt +struct Magenta { - magentatxt(const T &s) : value(s) {} + Magenta(const T &s) : value(s) {} const T & value; }; template <class T> -std::ostream & operator<<(std::ostream & out, const magentatxt<T> & y) +std::ostream & operator<<(std::ostream & out, const Magenta<T> & y) { return out << ANSI_WARNING << y.value << ANSI_NORMAL; } +/** + * Values wrapped in this class are printed without coloring. + * + * By default, arguments to `HintFmt` are printed in magenta (see `Magenta`). + */ template <class T> -struct normaltxt +struct Uncolored { - normaltxt(const T & s) : value(s) {} + Uncolored(const T & s) : value(s) {} const T & value; }; template <class T> -std::ostream & operator<<(std::ostream & out, const normaltxt<T> & y) +std::ostream & operator<<(std::ostream & out, const Uncolored<T> & y) { return out << ANSI_NORMAL << y.value; } -class hintformat +/** + * A wrapper around `boost::format` which colors interpolated arguments in + * magenta by default. + */ +class HintFmt { +private: + boost::format fmt; + public: - hintformat(const std::string & format) : fmt(format) - { - fmt.exceptions(boost::io::all_error_bits ^ - boost::io::too_many_args_bit ^ - boost::io::too_few_args_bit); - } + /** + * Format the given string literally, without interpolating format + * placeholders. + */ + HintFmt(const std::string & literal) + : HintFmt("%s", Uncolored(literal)) + { } + + /** + * Interpolate the given arguments into the format string. + */ + template<typename... Args> + HintFmt(const std::string & format, const Args & ... args) + : HintFmt(boost::format(format), args...) + { } - hintformat(const hintformat & hf) + HintFmt(const HintFmt & hf) : fmt(hf.fmt) { } - hintformat(format && fmt) + template<typename... Args> + HintFmt(boost::format && fmt, const Args & ... args) : fmt(std::move(fmt)) - { } + { + setExceptions(fmt); + formatHelper(*this, args...); + } template<class T> - hintformat & operator%(const T & value) + HintFmt & operator%(const T & value) { - fmt % magentatxt(value); + fmt % Magenta(value); return *this; } template<class T> - hintformat & operator%(const normaltxt<T> & value) + HintFmt & operator%(const Uncolored<T> & value) { fmt % value.value; return *this; @@ -122,25 +179,8 @@ public: { return fmt.str(); } - -private: - format fmt; }; -std::ostream & operator<<(std::ostream & os, const hintformat & hf); - -template<typename... Args> -inline hintformat hintfmt(const std::string & fs, const Args & ... args) -{ - hintformat f(fs); - formatHelper(f, args...); - return f; -} - -inline hintformat hintfmt(const std::string & plain_string) -{ - // we won't be receiving any args in this case, so just print the original string - return hintfmt("%s", normaltxt(plain_string)); -} +std::ostream & operator<<(std::ostream & os, const HintFmt & hf); } diff --git a/src/libutil/logging.hh b/src/libutil/logging.hh index 5aa6bee95..7a6341d70 100644 --- a/src/libutil/logging.hh +++ b/src/libutil/logging.hh @@ -118,6 +118,17 @@ public: { } }; +/** + * A variadic template that does nothing. + * + * Useful to call a function with each argument in a parameter pack. + */ +struct nop +{ + template<typename... T> nop(T...) + { } +}; + ActivityId getCurActivity(); void setCurActivity(const ActivityId activityId); diff --git a/src/libutil/serialise.cc b/src/libutil/serialise.cc index 6b0d87b03..3d9dcf728 100644 --- a/src/libutil/serialise.cc +++ b/src/libutil/serialise.cc @@ -444,7 +444,7 @@ Error readError(Source & source) auto msg = readString(source); ErrorInfo info { .level = level, - .msg = hintfmt(msg), + .msg = HintFmt(msg), }; auto havePos = readNum<size_t>(source); assert(havePos == 0); @@ -453,7 +453,7 @@ Error readError(Source & source) havePos = readNum<size_t>(source); assert(havePos == 0); info.traces.push_back(Trace { - .hint = hintfmt(readString(source)) + .hint = HintFmt(readString(source)) }); } return Error(std::move(info)); diff --git a/src/libutil/util.cc b/src/libutil/util.cc index ef2654a14..007ec8bef 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -1872,7 +1872,7 @@ void setStackSize(rlim_t stackSize) if (setrlimit(RLIMIT_STACK, &limit) != 0) { logger->log( lvlError, - hintfmt( + HintFmt( "Failed to increase stack size from %1% to %2% (maximum allowed stack size: %3%): %4%", savedStackSize, stackSize, diff --git a/src/nix/daemon.cc b/src/nix/daemon.cc index af428018a..f2eea2cf4 100644 --- a/src/nix/daemon.cc +++ b/src/nix/daemon.cc @@ -376,7 +376,7 @@ static void daemonLoop(std::optional<TrustedFlag> forceTrustClientOpt) } catch (Error & error) { auto ei = error.info(); // FIXME: add to trace? - ei.msg = hintfmt("error processing connection: %1%", ei.msg.str()); + ei.msg = HintFmt("error processing connection: %1%", ei.msg.str()); logError(ei); } } diff --git a/src/nix/eval.cc b/src/nix/eval.cc index 9ec861a89..2698a6de8 100644 --- a/src/nix/eval.cc +++ b/src/nix/eval.cc @@ -98,7 +98,7 @@ struct CmdEval : MixJSON, InstallableValueCommand, MixReadOnlyOption } catch (Error & e) { e.addTrace( state->positions[attr.pos], - hintfmt("while evaluating the attribute '%s'", name)); + HintFmt("while evaluating the attribute '%s'", name)); throw; } } diff --git a/src/nix/flake.cc b/src/nix/flake.cc index a11e39534..bbefff87a 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -370,7 +370,7 @@ struct CmdFlakeCheck : FlakeCommand return storePath; } } catch (Error & e) { - e.addTrace(resolve(pos), hintfmt("while checking the derivation '%s'", attrPath)); + e.addTrace(resolve(pos), HintFmt("while checking the derivation '%s'", attrPath)); reportError(e); } return std::nullopt; @@ -389,7 +389,7 @@ struct CmdFlakeCheck : FlakeCommand } #endif } catch (Error & e) { - e.addTrace(resolve(pos), hintfmt("while checking the app definition '%s'", attrPath)); + e.addTrace(resolve(pos), HintFmt("while checking the app definition '%s'", attrPath)); reportError(e); } }; @@ -413,7 +413,7 @@ struct CmdFlakeCheck : FlakeCommand // FIXME: if we have a 'nixpkgs' input, use it to // evaluate the overlay. } catch (Error & e) { - e.addTrace(resolve(pos), hintfmt("while checking the overlay '%s'", attrPath)); + e.addTrace(resolve(pos), HintFmt("while checking the overlay '%s'", attrPath)); reportError(e); } }; @@ -424,7 +424,7 @@ struct CmdFlakeCheck : FlakeCommand fmt("checking NixOS module '%s'", attrPath)); state->forceValue(v, pos); } catch (Error & e) { - e.addTrace(resolve(pos), hintfmt("while checking the NixOS module '%s'", attrPath)); + e.addTrace(resolve(pos), HintFmt("while checking the NixOS module '%s'", attrPath)); reportError(e); } }; @@ -452,7 +452,7 @@ struct CmdFlakeCheck : FlakeCommand } } catch (Error & e) { - e.addTrace(resolve(pos), hintfmt("while checking the Hydra jobset '%s'", attrPath)); + e.addTrace(resolve(pos), HintFmt("while checking the Hydra jobset '%s'", attrPath)); reportError(e); } }; @@ -467,7 +467,7 @@ struct CmdFlakeCheck : FlakeCommand if (!state->isDerivation(*vToplevel)) throw Error("attribute 'config.system.build.toplevel' is not a derivation"); } catch (Error & e) { - e.addTrace(resolve(pos), hintfmt("while checking the NixOS configuration '%s'", attrPath)); + e.addTrace(resolve(pos), HintFmt("while checking the NixOS configuration '%s'", attrPath)); reportError(e); } }; @@ -501,7 +501,7 @@ struct CmdFlakeCheck : FlakeCommand throw Error("template '%s' has unsupported attribute '%s'", attrPath, name); } } catch (Error & e) { - e.addTrace(resolve(pos), hintfmt("while checking the template '%s'", attrPath)); + e.addTrace(resolve(pos), HintFmt("while checking the template '%s'", attrPath)); reportError(e); } }; @@ -515,7 +515,7 @@ struct CmdFlakeCheck : FlakeCommand throw Error("bundler must be a function"); // TODO: check types of inputs/outputs? } catch (Error & e) { - e.addTrace(resolve(pos), hintfmt("while checking the template '%s'", attrPath)); + e.addTrace(resolve(pos), HintFmt("while checking the template '%s'", attrPath)); reportError(e); } }; @@ -735,7 +735,7 @@ struct CmdFlakeCheck : FlakeCommand warn("unknown flake output '%s'", name); } catch (Error & e) { - e.addTrace(resolve(pos), hintfmt("while checking flake output '%s'", name)); + e.addTrace(resolve(pos), HintFmt("while checking flake output '%s'", name)); reportError(e); } }); |