Improve error formatting

Changes:

* The divider lines are gone. These were in practice a bit confusing,
  in particular with --show-trace or --keep-going, since then there
  were multiple lines, suggesting a start/end which wasn't the case.

* Instead, multi-line error messages are now indented to align with
  the prefix (e.g. "error: ").

* The 'description' field is gone since we weren't really using it.

* 'hint' is renamed to 'msg' since it really wasn't a hint.

* The error is now printed *before* the location info.

* The 'name' field is no longer printed since most of the time it
  wasn't very useful since it was just the name of the exception (like
  EvalError). Ideally in the future this would be a unique, easily
  googleable error ID (like rustc).

* "trace:" is now just "…". This assumes error contexts start with
  something like "while doing X".

Example before:

  error: --- AssertionError ---------------------------------------------------------------------------------------- nix
  at: (7:7) in file: /home/eelco/Dev/nixpkgs/pkgs/applications/misc/hello/default.nix

       6|
       7|   x = assert false; 1;
        |       ^
       8|

  assertion 'false' failed
  ----------------------------------------------------- show-trace -----------------------------------------------------
  trace: while evaluating the attribute 'x' of the derivation 'hello-2.10'
  at: (192:11) in file: /home/eelco/Dev/nixpkgs/pkgs/stdenv/generic/make-derivation.nix

     191|         // (lib.optionalAttrs (!(attrs ? name) && attrs ? pname && attrs ? version)) {
     192|           name = "${attrs.pname}-${attrs.version}";
        |           ^
     193|         } // (lib.optionalAttrs (stdenv.hostPlatform != stdenv.buildPlatform && !dontAddHostSuffix && (attrs ? name || (attrs ? pname && attrs ? version)))) {

Example after:

  error: assertion 'false' failed

         at: (7:7) in file: /home/eelco/Dev/nixpkgs/pkgs/applications/misc/hello/default.nix

              6|
              7|   x = assert false; 1;
               |       ^
              8|

         … while evaluating the attribute 'x' of the derivation 'hello-2.10'

         at: (192:11) in file: /home/eelco/Dev/nixpkgs/pkgs/stdenv/generic/make-derivation.nix

            191|         // (lib.optionalAttrs (!(attrs ? name) && attrs ? pname && attrs ? version)) {
            192|           name = "${attrs.pname}-${attrs.version}";
               |           ^
            193|         } // (lib.optionalAttrs (stdenv.hostPlatform != stdenv.buildPlatform && !dontAddHostSuffix && (attrs ? name || (attrs ? pname && attrs ? version)))) {
This commit is contained in:
Eelco Dolstra 2021-01-21 00:27:36 +01:00
parent 259100332f
commit 8d4268d190
31 changed files with 249 additions and 422 deletions

View file

@ -172,13 +172,14 @@ static int main_build_remote(int argc, char * * argv)
else else
{ {
// build the hint template. // build the hint template.
string hintstring = "derivation: %s\nrequired (system, features): (%s, %s)"; string errorText =
hintstring += "\n%s available machines:"; "Failed to find a machine for remote build!\n"
hintstring += "\n(systems, maxjobs, supportedFeatures, mandatoryFeatures)"; "derivation: %s\nrequired (system, features): (%s, %s)";
errorText += "\n%s available machines:";
errorText += "\n(systems, maxjobs, supportedFeatures, mandatoryFeatures)";
for (unsigned int i = 0; i < machines.size(); ++i) { for (unsigned int i = 0; i < machines.size(); ++i)
hintstring += "\n(%s, %s, %s, %s)"; errorText += "\n(%s, %s, %s, %s)";
}
// add the template values. // add the template values.
string drvstr; string drvstr;
@ -187,25 +188,21 @@ static int main_build_remote(int argc, char * * argv)
else else
drvstr = "<unknown>"; drvstr = "<unknown>";
auto hint = hintformat(hintstring); auto error = hintformat(errorText);
hint error
% drvstr % drvstr
% neededSystem % neededSystem
% concatStringsSep<StringSet>(", ", requiredFeatures) % concatStringsSep<StringSet>(", ", requiredFeatures)
% machines.size(); % machines.size();
for (auto & m : machines) { for (auto & m : machines)
hint % concatStringsSep<vector<string>>(", ", m.systemTypes) error
% concatStringsSep<vector<string>>(", ", m.systemTypes)
% m.maxJobs % m.maxJobs
% concatStringsSep<StringSet>(", ", m.supportedFeatures) % concatStringsSep<StringSet>(", ", m.supportedFeatures)
% concatStringsSep<StringSet>(", ", m.mandatoryFeatures); % concatStringsSep<StringSet>(", ", m.mandatoryFeatures);
}
logErrorInfo(canBuildLocally ? lvlChatty : lvlWarn, { printMsg(canBuildLocally ? lvlChatty : lvlWarn, error);
.name = "Remote build",
.description = "Failed to find a machine for remote build!",
.hint = hint
});
std::cerr << "# decline\n"; std::cerr << "# decline\n";
} }
@ -230,12 +227,9 @@ static int main_build_remote(int argc, char * * argv)
} catch (std::exception & e) { } catch (std::exception & e) {
auto msg = chomp(drainFD(5, false)); auto msg = chomp(drainFD(5, false));
logError({ printError("cannot build on '%s': %s%s",
.name = "Remote build",
.hint = hintfmt("cannot build on '%s': %s%s",
bestMachine->storeUri, e.what(), bestMachine->storeUri, e.what(),
(msg.empty() ? "" : ": " + msg)) msg.empty() ? "" : ": " + msg);
});
bestMachine->enabled = false; bestMachine->enabled = false;
continue; continue;
} }

View file

@ -77,7 +77,7 @@ public:
auto a = get(name); auto a = get(name);
if (!a) if (!a)
throw Error({ throw Error({
.hint = hintfmt("attribute '%s' missing", name), .msg = hintfmt("attribute '%s' missing", name),
.errPos = pos .errPos = pos
}); });

View file

@ -10,7 +10,7 @@ namespace nix {
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s)) LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s))
{ {
throw EvalError({ throw EvalError({
.hint = hintfmt(s), .msg = hintfmt(s),
.errPos = pos .errPos = pos
}); });
} }
@ -24,7 +24,7 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const Value & v))
LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v)) LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const Value & v))
{ {
throw TypeError({ throw TypeError({
.hint = hintfmt(s, showType(v)), .msg = hintfmt(s, showType(v)),
.errPos = pos .errPos = pos
}); });
} }

View file

@ -622,7 +622,7 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2))
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2)) LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2))
{ {
throw EvalError({ throw EvalError({
.hint = hintfmt(s, s2), .msg = hintfmt(s, s2),
.errPos = pos .errPos = pos
}); });
} }
@ -635,7 +635,7 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2, con
LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, const string & s3)) LocalNoInlineNoReturn(void throwEvalError(const Pos & pos, const char * s, const string & s2, const string & s3))
{ {
throw EvalError({ throw EvalError({
.hint = hintfmt(s, s2, s3), .msg = hintfmt(s, s2, s3),
.errPos = pos .errPos = pos
}); });
} }
@ -644,7 +644,7 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const
{ {
// p1 is where the error occurred; p2 is a position mentioned in the message. // p1 is where the error occurred; p2 is a position mentioned in the message.
throw EvalError({ throw EvalError({
.hint = hintfmt(s, sym, p2), .msg = hintfmt(s, sym, p2),
.errPos = p1 .errPos = p1
}); });
} }
@ -652,7 +652,7 @@ LocalNoInlineNoReturn(void throwEvalError(const Pos & p1, const char * s, const
LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s)) LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s))
{ {
throw TypeError({ throw TypeError({
.hint = hintfmt(s), .msg = hintfmt(s),
.errPos = pos .errPos = pos
}); });
} }
@ -660,7 +660,7 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s))
LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2)) LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2))
{ {
throw TypeError({ throw TypeError({
.hint = hintfmt(s, fun.showNamePos(), s2), .msg = hintfmt(s, fun.showNamePos(), s2),
.errPos = pos .errPos = pos
}); });
} }
@ -668,7 +668,7 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const
LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1)) LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s, const string & s1))
{ {
throw AssertionError({ throw AssertionError({
.hint = hintfmt(s, s1), .msg = hintfmt(s, s1),
.errPos = pos .errPos = pos
}); });
} }
@ -676,7 +676,7 @@ LocalNoInlineNoReturn(void throwAssertionError(const Pos & pos, const char * s,
LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1)) LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char * s, const string & s1))
{ {
throw UndefinedVarError({ throw UndefinedVarError({
.hint = hintfmt(s, s1), .msg = hintfmt(s, s1),
.errPos = pos .errPos = pos
}); });
} }
@ -684,7 +684,7 @@ LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char *
LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1)) LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1))
{ {
throw MissingArgumentError({ throw MissingArgumentError({
.hint = hintfmt(s, s1), .msg = hintfmt(s, s1),
.errPos = pos .errPos = pos
}); });
} }
@ -2057,7 +2057,7 @@ void EvalState::printStats()
string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const
{ {
throw TypeError({ throw TypeError({
.hint = hintfmt("cannot coerce %1% to a string", showType()), .msg = hintfmt("cannot coerce %1% to a string", showType()),
.errPos = pos .errPos = pos
}); });
} }

View file

@ -284,7 +284,7 @@ void ExprVar::bindVars(const StaticEnv & env)
"undefined variable" error now. */ "undefined variable" error now. */
if (withLevel == -1) if (withLevel == -1)
throw UndefinedVarError({ throw UndefinedVarError({
.hint = hintfmt("undefined variable '%1%'", name), .msg = hintfmt("undefined variable '%1%'", name),
.errPos = pos .errPos = pos
}); });
fromWith = true; fromWith = true;

View file

@ -239,7 +239,7 @@ struct ExprLambda : Expr
{ {
if (!arg.empty() && formals && formals->argNames.find(arg) != formals->argNames.end()) if (!arg.empty() && formals && formals->argNames.find(arg) != formals->argNames.end())
throw ParseError({ throw ParseError({
.hint = hintfmt("duplicate formal function argument '%1%'", arg), .msg = hintfmt("duplicate formal function argument '%1%'", arg),
.errPos = pos .errPos = pos
}); });
}; };

View file

@ -32,7 +32,7 @@ namespace nix {
Path basePath; Path basePath;
Symbol file; Symbol file;
FileOrigin origin; FileOrigin origin;
ErrorInfo error; std::optional<ErrorInfo> error;
Symbol sLetBody; Symbol sLetBody;
ParseData(EvalState & state) ParseData(EvalState & state)
: state(state) : state(state)
@ -66,7 +66,7 @@ namespace nix {
static void dupAttr(const AttrPath & attrPath, const Pos & pos, const Pos & prevPos) static void dupAttr(const AttrPath & attrPath, const Pos & pos, const Pos & prevPos)
{ {
throw ParseError({ throw ParseError({
.hint = hintfmt("attribute '%1%' already defined at %2%", .msg = hintfmt("attribute '%1%' already defined at %2%",
showAttrPath(attrPath), prevPos), showAttrPath(attrPath), prevPos),
.errPos = pos .errPos = pos
}); });
@ -75,7 +75,7 @@ static void dupAttr(const AttrPath & attrPath, const Pos & pos, const Pos & prev
static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos) static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos)
{ {
throw ParseError({ throw ParseError({
.hint = hintfmt("attribute '%1%' already defined at %2%", attr, prevPos), .msg = hintfmt("attribute '%1%' already defined at %2%", attr, prevPos),
.errPos = pos .errPos = pos
}); });
} }
@ -146,7 +146,7 @@ static void addFormal(const Pos & pos, Formals * formals, const Formal & formal)
{ {
if (!formals->argNames.insert(formal.name).second) if (!formals->argNames.insert(formal.name).second)
throw ParseError({ throw ParseError({
.hint = hintfmt("duplicate formal function argument '%1%'", .msg = hintfmt("duplicate formal function argument '%1%'",
formal.name), formal.name),
.errPos = pos .errPos = pos
}); });
@ -258,7 +258,7 @@ static inline Pos makeCurPos(const YYLTYPE & loc, ParseData * data)
void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * error) void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * error)
{ {
data->error = { data->error = {
.hint = hintfmt(error), .msg = hintfmt(error),
.errPos = makeCurPos(*loc, data) .errPos = makeCurPos(*loc, data)
}; };
} }
@ -338,7 +338,7 @@ expr_function
| LET binds IN expr_function | LET binds IN expr_function
{ if (!$2->dynamicAttrs.empty()) { if (!$2->dynamicAttrs.empty())
throw ParseError({ throw ParseError({
.hint = hintfmt("dynamic attributes not allowed in let"), .msg = hintfmt("dynamic attributes not allowed in let"),
.errPos = CUR_POS .errPos = CUR_POS
}); });
$$ = new ExprLet($2, $4); $$ = new ExprLet($2, $4);
@ -418,7 +418,7 @@ expr_simple
static bool noURLLiterals = settings.isExperimentalFeatureEnabled("no-url-literals"); static bool noURLLiterals = settings.isExperimentalFeatureEnabled("no-url-literals");
if (noURLLiterals) if (noURLLiterals)
throw ParseError({ throw ParseError({
.hint = hintfmt("URL literals are disabled"), .msg = hintfmt("URL literals are disabled"),
.errPos = CUR_POS .errPos = CUR_POS
}); });
$$ = new ExprString(data->symbols.create($1)); $$ = new ExprString(data->symbols.create($1));
@ -491,7 +491,7 @@ attrs
delete str; delete str;
} else } else
throw ParseError({ throw ParseError({
.hint = hintfmt("dynamic attributes not allowed in inherit"), .msg = hintfmt("dynamic attributes not allowed in inherit"),
.errPos = makeCurPos(@2, data) .errPos = makeCurPos(@2, data)
}); });
} }
@ -593,7 +593,7 @@ Expr * EvalState::parse(const char * text, FileOrigin origin,
int res = yyparse(scanner, &data); int res = yyparse(scanner, &data);
yylex_destroy(scanner); yylex_destroy(scanner);
if (res) throw ParseError(data.error); if (res) throw ParseError(data.error.value());
data.result->bindVars(staticEnv); data.result->bindVars(staticEnv);
@ -703,7 +703,7 @@ Path EvalState::findFile(SearchPath & searchPath, const string & path, const Pos
return corepkgsPrefix + path.substr(4); return corepkgsPrefix + path.substr(4);
throw ThrownError({ throw ThrownError({
.hint = hintfmt(evalSettings.pureEval .msg = hintfmt(evalSettings.pureEval
? "cannot look up '<%s>' in pure evaluation mode (use '--impure' to override)" ? "cannot look up '<%s>' in pure evaluation mode (use '--impure' to override)"
: "file '%s' was not found in the Nix search path (add it using $NIX_PATH or -I)", : "file '%s' was not found in the Nix search path (add it using $NIX_PATH or -I)",
path), path),
@ -725,8 +725,7 @@ std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathEl
store, resolveUri(elem.second), "source", false).first.storePath) }; store, resolveUri(elem.second), "source", false).first.storePath) };
} catch (FileTransferError & e) { } catch (FileTransferError & e) {
logWarning({ logWarning({
.name = "Entry download", .msg = hintfmt("Nix search path entry '%1%' cannot be downloaded, ignoring", elem.second)
.hint = hintfmt("Nix search path entry '%1%' cannot be downloaded, ignoring", elem.second)
}); });
res = { false, "" }; res = { false, "" };
} }
@ -736,8 +735,7 @@ std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathEl
res = { true, path }; res = { true, path };
else { else {
logWarning({ logWarning({
.name = "Entry not found", .msg = hintfmt("warning: Nix search path entry '%1%' does not exist, ignoring", elem.second)
.hint = hintfmt("warning: Nix search path entry '%1%' does not exist, ignoring", elem.second)
}); });
res = { false, "" }; res = { false, "" };
} }

View file

@ -115,7 +115,7 @@ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vS
state.realiseContext(context); state.realiseContext(context);
} catch (InvalidPathError & e) { } catch (InvalidPathError & e) {
throw EvalError({ throw EvalError({
.hint = hintfmt("cannot import '%1%', since path '%2%' is not valid", path, e.path), .msg = hintfmt("cannot import '%1%', since path '%2%' is not valid", path, e.path),
.errPos = pos .errPos = pos
}); });
} }
@ -282,7 +282,7 @@ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value
state.realiseContext(context); state.realiseContext(context);
} catch (InvalidPathError & e) { } catch (InvalidPathError & e) {
throw EvalError({ throw EvalError({
.hint = hintfmt( .msg = hintfmt(
"cannot import '%1%', since path '%2%' is not valid", "cannot import '%1%', since path '%2%' is not valid",
path, e.path), path, e.path),
.errPos = pos .errPos = pos
@ -322,7 +322,7 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
auto count = args[0]->listSize(); auto count = args[0]->listSize();
if (count == 0) { if (count == 0) {
throw EvalError({ throw EvalError({
.hint = hintfmt("at least one argument to 'exec' required"), .msg = hintfmt("at least one argument to 'exec' required"),
.errPos = pos .errPos = pos
}); });
} }
@ -336,7 +336,7 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
state.realiseContext(context); state.realiseContext(context);
} catch (InvalidPathError & e) { } catch (InvalidPathError & e) {
throw EvalError({ throw EvalError({
.hint = hintfmt("cannot execute '%1%', since path '%2%' is not valid", .msg = hintfmt("cannot execute '%1%', since path '%2%' is not valid",
program, e.path), program, e.path),
.errPos = pos .errPos = pos
}); });
@ -551,7 +551,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
args[0]->attrs->find(state.symbols.create("startSet")); args[0]->attrs->find(state.symbols.create("startSet"));
if (startSet == args[0]->attrs->end()) if (startSet == args[0]->attrs->end())
throw EvalError({ throw EvalError({
.hint = hintfmt("attribute 'startSet' required"), .msg = hintfmt("attribute 'startSet' required"),
.errPos = pos .errPos = pos
}); });
state.forceList(*startSet->value, pos); state.forceList(*startSet->value, pos);
@ -565,7 +565,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
args[0]->attrs->find(state.symbols.create("operator")); args[0]->attrs->find(state.symbols.create("operator"));
if (op == args[0]->attrs->end()) if (op == args[0]->attrs->end())
throw EvalError({ throw EvalError({
.hint = hintfmt("attribute 'operator' required"), .msg = hintfmt("attribute 'operator' required"),
.errPos = pos .errPos = pos
}); });
state.forceValue(*op->value, pos); state.forceValue(*op->value, pos);
@ -587,7 +587,7 @@ static void prim_genericClosure(EvalState & state, const Pos & pos, Value * * ar
e->attrs->find(state.symbols.create("key")); e->attrs->find(state.symbols.create("key"));
if (key == e->attrs->end()) if (key == e->attrs->end())
throw EvalError({ throw EvalError({
.hint = hintfmt("attribute 'key' required"), .msg = hintfmt("attribute 'key' required"),
.errPos = pos .errPos = pos
}); });
state.forceValue(*key->value, pos); state.forceValue(*key->value, pos);
@ -810,7 +810,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
Bindings::iterator attr = args[0]->attrs->find(state.sName); Bindings::iterator attr = args[0]->attrs->find(state.sName);
if (attr == args[0]->attrs->end()) if (attr == args[0]->attrs->end())
throw EvalError({ throw EvalError({
.hint = hintfmt("required attribute 'name' missing"), .msg = hintfmt("required attribute 'name' missing"),
.errPos = pos .errPos = pos
}); });
string drvName; string drvName;
@ -859,7 +859,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
else if (s == "flat") ingestionMethod = FileIngestionMethod::Flat; else if (s == "flat") ingestionMethod = FileIngestionMethod::Flat;
else else
throw EvalError({ throw EvalError({
.hint = hintfmt("invalid value '%s' for 'outputHashMode' attribute", s), .msg = hintfmt("invalid value '%s' for 'outputHashMode' attribute", s),
.errPos = posDrvName .errPos = posDrvName
}); });
}; };
@ -869,7 +869,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
for (auto & j : ss) { for (auto & j : ss) {
if (outputs.find(j) != outputs.end()) if (outputs.find(j) != outputs.end())
throw EvalError({ throw EvalError({
.hint = hintfmt("duplicate derivation output '%1%'", j), .msg = hintfmt("duplicate derivation output '%1%'", j),
.errPos = posDrvName .errPos = posDrvName
}); });
/* !!! Check whether j is a valid attribute /* !!! Check whether j is a valid attribute
@ -879,14 +879,14 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
the resulting set. */ the resulting set. */
if (j == "drv") if (j == "drv")
throw EvalError({ throw EvalError({
.hint = hintfmt("invalid derivation output name 'drv'" ), .msg = hintfmt("invalid derivation output name 'drv'" ),
.errPos = posDrvName .errPos = posDrvName
}); });
outputs.insert(j); outputs.insert(j);
} }
if (outputs.empty()) if (outputs.empty())
throw EvalError({ throw EvalError({
.hint = hintfmt("derivation cannot have an empty set of outputs"), .msg = hintfmt("derivation cannot have an empty set of outputs"),
.errPos = posDrvName .errPos = posDrvName
}); });
}; };
@ -1007,20 +1007,20 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
/* Do we have all required attributes? */ /* Do we have all required attributes? */
if (drv.builder == "") if (drv.builder == "")
throw EvalError({ throw EvalError({
.hint = hintfmt("required attribute 'builder' missing"), .msg = hintfmt("required attribute 'builder' missing"),
.errPos = posDrvName .errPos = posDrvName
}); });
if (drv.platform == "") if (drv.platform == "")
throw EvalError({ throw EvalError({
.hint = hintfmt("required attribute 'system' missing"), .msg = hintfmt("required attribute 'system' missing"),
.errPos = posDrvName .errPos = posDrvName
}); });
/* Check whether the derivation name is valid. */ /* Check whether the derivation name is valid. */
if (isDerivation(drvName)) if (isDerivation(drvName))
throw EvalError({ throw EvalError({
.hint = hintfmt("derivation names are not allowed to end in '%s'", drvExtension), .msg = hintfmt("derivation names are not allowed to end in '%s'", drvExtension),
.errPos = posDrvName .errPos = posDrvName
}); });
@ -1031,7 +1031,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
already content addressed. */ already content addressed. */
if (outputs.size() != 1 || *(outputs.begin()) != "out") if (outputs.size() != 1 || *(outputs.begin()) != "out")
throw Error({ throw Error({
.hint = hintfmt("multiple outputs are not supported in fixed-output derivations"), .msg = hintfmt("multiple outputs are not supported in fixed-output derivations"),
.errPos = posDrvName .errPos = posDrvName
}); });
@ -1211,7 +1211,7 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V
if (!state.store->isStorePath(path)) path = canonPath(path, true); if (!state.store->isStorePath(path)) path = canonPath(path, true);
if (!state.store->isInStore(path)) if (!state.store->isInStore(path))
throw EvalError({ throw EvalError({
.hint = hintfmt("path '%1%' is not in the Nix store", path), .msg = hintfmt("path '%1%' is not in the Nix store", path),
.errPos = pos .errPos = pos
}); });
auto path2 = state.store->toStorePath(path).first; auto path2 = state.store->toStorePath(path).first;
@ -1247,7 +1247,7 @@ static void prim_pathExists(EvalState & state, const Pos & pos, Value * * args,
state.realiseContext(context); state.realiseContext(context);
} catch (InvalidPathError & e) { } catch (InvalidPathError & e) {
throw EvalError({ throw EvalError({
.hint = hintfmt( .msg = hintfmt(
"cannot check the existence of '%1%', since path '%2%' is not valid", "cannot check the existence of '%1%', since path '%2%' is not valid",
path, e.path), path, e.path),
.errPos = pos .errPos = pos
@ -1324,7 +1324,7 @@ static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Va
state.realiseContext(context); state.realiseContext(context);
} catch (InvalidPathError & e) { } catch (InvalidPathError & e) {
throw EvalError({ throw EvalError({
.hint = hintfmt("cannot read '%1%', since path '%2%' is not valid", path, e.path), .msg = hintfmt("cannot read '%1%', since path '%2%' is not valid", path, e.path),
.errPos = pos .errPos = pos
}); });
} }
@ -1363,7 +1363,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
i = v2.attrs->find(state.symbols.create("path")); i = v2.attrs->find(state.symbols.create("path"));
if (i == v2.attrs->end()) if (i == v2.attrs->end())
throw EvalError({ throw EvalError({
.hint = hintfmt("attribute 'path' missing"), .msg = hintfmt("attribute 'path' missing"),
.errPos = pos .errPos = pos
}); });
@ -1374,7 +1374,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
state.realiseContext(context); state.realiseContext(context);
} catch (InvalidPathError & e) { } catch (InvalidPathError & e) {
throw EvalError({ throw EvalError({
.hint = hintfmt("cannot find '%1%', since path '%2%' is not valid", path, e.path), .msg = hintfmt("cannot find '%1%', since path '%2%' is not valid", path, e.path),
.errPos = pos .errPos = pos
}); });
} }
@ -1400,7 +1400,7 @@ static void prim_hashFile(EvalState & state, const Pos & pos, Value * * args, Va
std::optional<HashType> ht = parseHashType(type); std::optional<HashType> ht = parseHashType(type);
if (!ht) if (!ht)
throw Error({ throw Error({
.hint = hintfmt("unknown hash type '%1%'", type), .msg = hintfmt("unknown hash type '%1%'", type),
.errPos = pos .errPos = pos
}); });
@ -1430,7 +1430,7 @@ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Val
state.realiseContext(ctx); state.realiseContext(ctx);
} catch (InvalidPathError & e) { } catch (InvalidPathError & e) {
throw EvalError({ throw EvalError({
.hint = hintfmt("cannot read '%1%', since path '%2%' is not valid", path, e.path), .msg = hintfmt("cannot read '%1%', since path '%2%' is not valid", path, e.path),
.errPos = pos .errPos = pos
}); });
} }
@ -1650,7 +1650,7 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu
for (auto path : context) { for (auto path : context) {
if (path.at(0) != '/') if (path.at(0) != '/')
throw EvalError( { throw EvalError( {
.hint = hintfmt( .msg = hintfmt(
"in 'toFile': the file named '%1%' must not contain a reference " "in 'toFile': the file named '%1%' must not contain a reference "
"to a derivation but contains (%2%)", "to a derivation but contains (%2%)",
name, path), name, path),
@ -1801,14 +1801,14 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args
Path path = state.coerceToPath(pos, *args[1], context); Path path = state.coerceToPath(pos, *args[1], context);
if (!context.empty()) if (!context.empty())
throw EvalError({ throw EvalError({
.hint = hintfmt("string '%1%' cannot refer to other paths", path), .msg = hintfmt("string '%1%' cannot refer to other paths", path),
.errPos = pos .errPos = pos
}); });
state.forceValue(*args[0], pos); state.forceValue(*args[0], pos);
if (args[0]->type() != nFunction) if (args[0]->type() != nFunction)
throw TypeError({ throw TypeError({
.hint = hintfmt( .msg = hintfmt(
"first argument in call to 'filterSource' is not a function but %1%", "first argument in call to 'filterSource' is not a function but %1%",
showType(*args[0])), showType(*args[0])),
.errPos = pos .errPos = pos
@ -1875,7 +1875,7 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value
path = state.coerceToPath(*attr.pos, *attr.value, context); path = state.coerceToPath(*attr.pos, *attr.value, context);
if (!context.empty()) if (!context.empty())
throw EvalError({ throw EvalError({
.hint = hintfmt("string '%1%' cannot refer to other paths", path), .msg = hintfmt("string '%1%' cannot refer to other paths", path),
.errPos = *attr.pos .errPos = *attr.pos
}); });
} else if (attr.name == state.sName) } else if (attr.name == state.sName)
@ -1889,13 +1889,13 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value
expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256); expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, *attr.pos), htSHA256);
else else
throw EvalError({ throw EvalError({
.hint = hintfmt("unsupported argument '%1%' to 'addPath'", attr.name), .msg = hintfmt("unsupported argument '%1%' to 'addPath'", attr.name),
.errPos = *attr.pos .errPos = *attr.pos
}); });
} }
if (path.empty()) if (path.empty())
throw EvalError({ throw EvalError({
.hint = hintfmt("'path' required"), .msg = hintfmt("'path' required"),
.errPos = pos .errPos = pos
}); });
if (name.empty()) if (name.empty())
@ -2010,7 +2010,7 @@ void prim_getAttr(EvalState & state, const Pos & pos, Value * * args, Value & v)
Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr)); Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr));
if (i == args[1]->attrs->end()) if (i == args[1]->attrs->end())
throw EvalError({ throw EvalError({
.hint = hintfmt("attribute '%1%' missing", attr), .msg = hintfmt("attribute '%1%' missing", attr),
.errPos = pos .errPos = pos
}); });
// !!! add to stack trace? // !!! add to stack trace?
@ -2142,7 +2142,7 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
Bindings::iterator j = v2.attrs->find(state.sName); Bindings::iterator j = v2.attrs->find(state.sName);
if (j == v2.attrs->end()) if (j == v2.attrs->end())
throw TypeError({ throw TypeError({
.hint = hintfmt("'name' attribute missing in a call to 'listToAttrs'"), .msg = hintfmt("'name' attribute missing in a call to 'listToAttrs'"),
.errPos = pos .errPos = pos
}); });
string name = state.forceStringNoCtx(*j->value, pos); string name = state.forceStringNoCtx(*j->value, pos);
@ -2152,7 +2152,7 @@ static void prim_listToAttrs(EvalState & state, const Pos & pos, Value * * args,
Bindings::iterator j2 = v2.attrs->find(state.symbols.create(state.sValue)); Bindings::iterator j2 = v2.attrs->find(state.symbols.create(state.sValue));
if (j2 == v2.attrs->end()) if (j2 == v2.attrs->end())
throw TypeError({ throw TypeError({
.hint = hintfmt("'value' attribute missing in a call to 'listToAttrs'"), .msg = hintfmt("'value' attribute missing in a call to 'listToAttrs'"),
.errPos = pos .errPos = pos
}); });
v.attrs->push_back(Attr(sym, j2->value, j2->pos)); v.attrs->push_back(Attr(sym, j2->value, j2->pos));
@ -2258,7 +2258,7 @@ static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args
} }
if (!args[0]->isLambda()) if (!args[0]->isLambda())
throw TypeError({ throw TypeError({
.hint = hintfmt("'functionArgs' requires a function"), .msg = hintfmt("'functionArgs' requires a function"),
.errPos = pos .errPos = pos
}); });
@ -2352,7 +2352,7 @@ static void elemAt(EvalState & state, const Pos & pos, Value & list, int n, Valu
state.forceList(list, pos); state.forceList(list, pos);
if (n < 0 || (unsigned int) n >= list.listSize()) if (n < 0 || (unsigned int) n >= list.listSize())
throw Error({ throw Error({
.hint = hintfmt("list index %1% is out of bounds", n), .msg = hintfmt("list index %1% is out of bounds", n),
.errPos = pos .errPos = pos
}); });
state.forceValue(*list.listElems()[n], pos); state.forceValue(*list.listElems()[n], pos);
@ -2400,7 +2400,7 @@ static void prim_tail(EvalState & state, const Pos & pos, Value * * args, Value
state.forceList(*args[0], pos); state.forceList(*args[0], pos);
if (args[0]->listSize() == 0) if (args[0]->listSize() == 0)
throw Error({ throw Error({
.hint = hintfmt("'tail' called on an empty list"), .msg = hintfmt("'tail' called on an empty list"),
.errPos = pos .errPos = pos
}); });
@ -2639,7 +2639,7 @@ static void prim_genList(EvalState & state, const Pos & pos, Value * * args, Val
if (len < 0) if (len < 0)
throw EvalError({ throw EvalError({
.hint = hintfmt("cannot create list of size %1%", len), .msg = hintfmt("cannot create list of size %1%", len),
.errPos = pos .errPos = pos
}); });
@ -2890,7 +2890,7 @@ static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value &
NixFloat f2 = state.forceFloat(*args[1], pos); NixFloat f2 = state.forceFloat(*args[1], pos);
if (f2 == 0) if (f2 == 0)
throw EvalError({ throw EvalError({
.hint = hintfmt("division by zero"), .msg = hintfmt("division by zero"),
.errPos = pos .errPos = pos
}); });
@ -2902,7 +2902,7 @@ static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value &
/* Avoid division overflow as it might raise SIGFPE. */ /* Avoid division overflow as it might raise SIGFPE. */
if (i1 == std::numeric_limits<NixInt>::min() && i2 == -1) if (i1 == std::numeric_limits<NixInt>::min() && i2 == -1)
throw EvalError({ throw EvalError({
.hint = hintfmt("overflow in integer division"), .msg = hintfmt("overflow in integer division"),
.errPos = pos .errPos = pos
}); });
@ -3033,7 +3033,7 @@ static void prim_substring(EvalState & state, const Pos & pos, Value * * args, V
if (start < 0) if (start < 0)
throw EvalError({ throw EvalError({
.hint = hintfmt("negative start position in 'substring'"), .msg = hintfmt("negative start position in 'substring'"),
.errPos = pos .errPos = pos
}); });
@ -3084,7 +3084,7 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args,
std::optional<HashType> ht = parseHashType(type); std::optional<HashType> ht = parseHashType(type);
if (!ht) if (!ht)
throw Error({ throw Error({
.hint = hintfmt("unknown hash type '%1%'", type), .msg = hintfmt("unknown hash type '%1%'", type),
.errPos = pos .errPos = pos
}); });
@ -3148,12 +3148,12 @@ void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v)
if (e.code() == std::regex_constants::error_space) { if (e.code() == std::regex_constants::error_space) {
// limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++
throw EvalError({ throw EvalError({
.hint = hintfmt("memory limit exceeded by regular expression '%s'", re), .msg = hintfmt("memory limit exceeded by regular expression '%s'", re),
.errPos = pos .errPos = pos
}); });
} else { } else {
throw EvalError({ throw EvalError({
.hint = hintfmt("invalid regular expression '%s'", re), .msg = hintfmt("invalid regular expression '%s'", re),
.errPos = pos .errPos = pos
}); });
} }
@ -3256,12 +3256,12 @@ static void prim_split(EvalState & state, const Pos & pos, Value * * args, Value
if (e.code() == std::regex_constants::error_space) { if (e.code() == std::regex_constants::error_space) {
// limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++
throw EvalError({ throw EvalError({
.hint = hintfmt("memory limit exceeded by regular expression '%s'", re), .msg = hintfmt("memory limit exceeded by regular expression '%s'", re),
.errPos = pos .errPos = pos
}); });
} else { } else {
throw EvalError({ throw EvalError({
.hint = hintfmt("invalid regular expression '%s'", re), .msg = hintfmt("invalid regular expression '%s'", re),
.errPos = pos .errPos = pos
}); });
} }
@ -3341,7 +3341,7 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar
state.forceList(*args[1], pos); state.forceList(*args[1], pos);
if (args[0]->listSize() != args[1]->listSize()) if (args[0]->listSize() != args[1]->listSize())
throw EvalError({ throw EvalError({
.hint = hintfmt("'from' and 'to' arguments to 'replaceStrings' have different lengths"), .msg = hintfmt("'from' and 'to' arguments to 'replaceStrings' have different lengths"),
.errPos = pos .errPos = pos
}); });

View file

@ -147,7 +147,7 @@ static void prim_appendContext(EvalState & state, const Pos & pos, Value * * arg
for (auto & i : *args[1]->attrs) { for (auto & i : *args[1]->attrs) {
if (!state.store->isStorePath(i.name)) if (!state.store->isStorePath(i.name))
throw EvalError({ throw EvalError({
.hint = hintfmt("Context key '%s' is not a store path", i.name), .msg = hintfmt("Context key '%s' is not a store path", i.name),
.errPos = *i.pos .errPos = *i.pos
}); });
if (!settings.readOnlyMode) if (!settings.readOnlyMode)
@ -164,7 +164,7 @@ static void prim_appendContext(EvalState & state, const Pos & pos, Value * * arg
if (state.forceBool(*iter->value, *iter->pos)) { if (state.forceBool(*iter->value, *iter->pos)) {
if (!isDerivation(i.name)) { if (!isDerivation(i.name)) {
throw EvalError({ throw EvalError({
.hint = hintfmt("Tried to add all-outputs context of %s, which is not a derivation, to a string", i.name), .msg = hintfmt("Tried to add all-outputs context of %s, which is not a derivation, to a string", i.name),
.errPos = *i.pos .errPos = *i.pos
}); });
} }
@ -177,7 +177,7 @@ static void prim_appendContext(EvalState & state, const Pos & pos, Value * * arg
state.forceList(*iter->value, *iter->pos); state.forceList(*iter->value, *iter->pos);
if (iter->value->listSize() && !isDerivation(i.name)) { if (iter->value->listSize() && !isDerivation(i.name)) {
throw EvalError({ throw EvalError({
.hint = hintfmt("Tried to add derivation output context of %s, which is not a derivation, to a string", i.name), .msg = hintfmt("Tried to add derivation output context of %s, which is not a derivation, to a string", i.name),
.errPos = *i.pos .errPos = *i.pos
}); });
} }

View file

@ -38,14 +38,14 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
name = state.forceStringNoCtx(*attr.value, *attr.pos); name = state.forceStringNoCtx(*attr.value, *attr.pos);
else else
throw EvalError({ throw EvalError({
.hint = hintfmt("unsupported argument '%s' to 'fetchMercurial'", attr.name), .msg = hintfmt("unsupported argument '%s' to 'fetchMercurial'", attr.name),
.errPos = *attr.pos .errPos = *attr.pos
}); });
} }
if (url.empty()) if (url.empty())
throw EvalError({ throw EvalError({
.hint = hintfmt("'url' argument required"), .msg = hintfmt("'url' argument required"),
.errPos = pos .errPos = pos
}); });

View file

@ -115,7 +115,7 @@ static void fetchTree(
if (!attrs.count("type")) if (!attrs.count("type"))
throw Error({ throw Error({
.hint = hintfmt("attribute 'type' is missing in call to 'fetchTree'"), .msg = hintfmt("attribute 'type' is missing in call to 'fetchTree'"),
.errPos = pos .errPos = pos
}); });
@ -177,14 +177,14 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
name = state.forceStringNoCtx(*attr.value, *attr.pos); name = state.forceStringNoCtx(*attr.value, *attr.pos);
else else
throw EvalError({ throw EvalError({
.hint = hintfmt("unsupported argument '%s' to '%s'", attr.name, who), .msg = hintfmt("unsupported argument '%s' to '%s'", attr.name, who),
.errPos = *attr.pos .errPos = *attr.pos
}); });
} }
if (!url) if (!url)
throw EvalError({ throw EvalError({
.hint = hintfmt("'url' argument required"), .msg = hintfmt("'url' argument required"),
.errPos = pos .errPos = pos
}); });
} else } else

View file

@ -82,7 +82,7 @@ static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Va
visit(v, parser(tomlStream).parse()); visit(v, parser(tomlStream).parse());
} catch (std::runtime_error & e) { } catch (std::runtime_error & e) {
throw EvalError({ throw EvalError({
.hint = hintfmt("while parsing a TOML string: %s", e.what()), .msg = hintfmt("while parsing a TOML string: %s", e.what()),
.errPos = pos .errPos = pos
}); });
} }

View file

@ -87,8 +87,8 @@ void handleDiffHook(
printError(chomp(diffRes.second)); printError(chomp(diffRes.second));
} catch (Error & error) { } catch (Error & error) {
ErrorInfo ei = error.info(); ErrorInfo ei = error.info();
ei.hint = hintfmt("diff hook execution failed: %s", // FIXME: wrap errors.
(error.info().hint.has_value() ? error.info().hint->str() : "")); ei.msg = hintfmt("diff hook execution failed: %s", ei.msg.str());
logError(ei); logError(ei);
} }
} }
@ -439,12 +439,9 @@ void DerivationGoal::repairClosure()
/* Check each path (slow!). */ /* Check each path (slow!). */
for (auto & i : outputClosure) { for (auto & i : outputClosure) {
if (worker.pathContentsGood(i)) continue; if (worker.pathContentsGood(i)) continue;
logError({ printError(
.name = "Corrupt path in closure",
.hint = hintfmt(
"found corrupted or missing path '%s' in the output closure of '%s'", "found corrupted or missing path '%s' in the output closure of '%s'",
worker.store.printStorePath(i), worker.store.printStorePath(drvPath)) worker.store.printStorePath(i), worker.store.printStorePath(drvPath));
});
auto drvPath2 = outputsToDrv.find(i); auto drvPath2 = outputsToDrv.find(i);
if (drvPath2 == outputsToDrv.end()) if (drvPath2 == outputsToDrv.end())
addWaitee(upcast_goal(worker.makeSubstitutionGoal(i, Repair))); addWaitee(upcast_goal(worker.makeSubstitutionGoal(i, Repair)));
@ -877,9 +874,12 @@ void DerivationGoal::buildDone()
statusToString(status)); statusToString(status));
if (!logger->isVerbose() && !logTail.empty()) { if (!logger->isVerbose() && !logTail.empty()) {
msg += (format("; last %d log lines:") % logTail.size()).str(); msg += fmt(";\nlast %d log lines:\n", logTail.size());
for (auto & line : logTail) for (auto & line : logTail) {
msg += "\n " + line; msg += "> ";
msg += line;
msg += "\n";
}
} }
if (diskFull) if (diskFull)
@ -1055,12 +1055,9 @@ HookReply DerivationGoal::tryBuildHook()
} catch (SysError & e) { } catch (SysError & e) {
if (e.errNo == EPIPE) { if (e.errNo == EPIPE) {
logError({ printError(
.name = "Build hook died",
.hint = hintfmt(
"build hook died unexpectedly: %s", "build hook died unexpectedly: %s",
chomp(drainFD(worker.hook->fromHook.readSide.get()))) chomp(drainFD(worker.hook->fromHook.readSide.get())));
});
worker.hook = 0; worker.hook = 0;
return rpDecline; return rpDecline;
} else } else
@ -3068,10 +3065,7 @@ void DerivationGoal::registerOutputs()
auto rewriteOutput = [&]() { auto rewriteOutput = [&]() {
/* Apply hash rewriting if necessary. */ /* Apply hash rewriting if necessary. */
if (!outputRewrites.empty()) { if (!outputRewrites.empty()) {
logWarning({ warn("rewriting hashes in '%1%'; cross fingers", actualPath);
.name = "Rewriting hashes",
.hint = hintfmt("rewriting hashes in '%1%'; cross fingers", actualPath),
});
/* FIXME: this is in-memory. */ /* FIXME: this is in-memory. */
StringSink sink; StringSink sink;
@ -3359,10 +3353,7 @@ void DerivationGoal::registerOutputs()
if (settings.enforceDeterminism) if (settings.enforceDeterminism)
throw NotDeterministic(hint); throw NotDeterministic(hint);
logError({ printError(hint);
.name = "Output determinism error",
.hint = hint
});
curRound = nrRounds; // we know enough, bail out early curRound = nrRounds; // we know enough, bail out early
} }

View file

@ -146,11 +146,8 @@ void SubstitutionGoal::tryNext()
&& !sub->isTrusted && !sub->isTrusted
&& !info->checkSignatures(worker.store, worker.store.getPublicKeys())) && !info->checkSignatures(worker.store, worker.store.getPublicKeys()))
{ {
logWarning({ warn("substituter '%s' does not have a valid signature for path '%s'",
.name = "Invalid path signature", sub->getUri(), worker.store.printStorePath(storePath));
.hint = hintfmt("substituter '%s' does not have a valid signature for path '%s'",
sub->getUri(), worker.store.printStorePath(storePath))
});
tryNext(); tryNext();
return; return;
} }

View file

@ -454,10 +454,7 @@ bool Worker::pathContentsGood(const StorePath & path)
} }
pathContentsGoodCache.insert_or_assign(path, res); pathContentsGoodCache.insert_or_assign(path, res);
if (!res) if (!res)
logError({ printError("path '%s' is corrupted or missing!", store.printStorePath(path));
.name = "Corrupted path",
.hint = hintfmt("path '%s' is corrupted or missing!", store.printStorePath(path))
});
return res; return res;
} }

View file

@ -22,10 +22,7 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
srcFiles = readDirectory(srcDir); srcFiles = readDirectory(srcDir);
} catch (SysError & e) { } catch (SysError & e) {
if (e.errNo == ENOTDIR) { if (e.errNo == ENOTDIR) {
logWarning({ warn("not including '%s' in the user environment because it's not a directory", srcDir);
.name = "Create links - directory",
.hint = hintfmt("not including '%s' in the user environment because it's not a directory", srcDir)
});
return; return;
} }
throw; throw;
@ -44,10 +41,7 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
throw SysError("getting status of '%1%'", srcFile); throw SysError("getting status of '%1%'", srcFile);
} catch (SysError & e) { } catch (SysError & e) {
if (e.errNo == ENOENT || e.errNo == ENOTDIR) { if (e.errNo == ENOENT || e.errNo == ENOTDIR) {
logWarning({ warn("skipping dangling symlink '%s'", dstFile);
.name = "Create links - skipping symlink",
.hint = hintfmt("skipping dangling symlink '%s'", dstFile)
});
continue; continue;
} }
throw; throw;

View file

@ -632,11 +632,7 @@ struct curlFileTransfer : public FileTransfer
workerThreadMain(); workerThreadMain();
} catch (nix::Interrupted & e) { } catch (nix::Interrupted & e) {
} catch (std::exception & e) { } catch (std::exception & e) {
logError({ printError("unexpected error in download thread: %s", e.what());
.name = "File transfer",
.hint = hintfmt("unexpected error in download thread: %s",
e.what())
});
} }
{ {
@ -852,11 +848,10 @@ FileTransferError::FileTransferError(FileTransfer::Error error, std::shared_ptr<
// FIXME: Due to https://github.com/NixOS/nix/issues/3841 we don't know how // 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 // to print different messages for different verbosity levels. For now
// we add some heuristics for detecting when we want to show the response. // we add some heuristics for detecting when we want to show the response.
if (response && (response->size() < 1024 || response->find("<html>") != string::npos)) { if (response && (response->size() < 1024 || response->find("<html>") != string::npos))
err.hint = hintfmt("%1%\n\nresponse body:\n\n%2%", normaltxt(hf.str()), *response); err.msg = hintfmt("%1%\n\nresponse body:\n\n%2%", normaltxt(hf.str()), *response);
} else { else
err.hint = hf; err.msg = hf;
}
} }
bool isUri(const string & s) bool isUri(const string & s)

View file

@ -150,12 +150,7 @@ LocalStore::LocalStore(const Params & params)
struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str()); struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str());
if (!gr) if (!gr)
logError({ printError("warning: the group '%1%' specified in 'build-users-group' does not exist", settings.buildUsersGroup);
.name = "'build-users-group' not found",
.hint = hintfmt(
"warning: the group '%1%' specified in 'build-users-group' does not exist",
settings.buildUsersGroup)
});
else { else {
struct stat st; struct stat st;
if (stat(realStoreDir.c_str(), &st)) if (stat(realStoreDir.c_str(), &st))
@ -1403,12 +1398,8 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
Path linkPath = linksDir + "/" + link.name; Path linkPath = linksDir + "/" + link.name;
string hash = hashPath(htSHA256, linkPath).first.to_string(Base32, false); string hash = hashPath(htSHA256, linkPath).first.to_string(Base32, false);
if (hash != link.name) { if (hash != link.name) {
logError({ printError("link '%s' was modified! expected hash '%s', got '%s'",
.name = "Invalid hash", linkPath, link.name, hash);
.hint = hintfmt(
"link '%s' was modified! expected hash '%s', got '%s'",
linkPath, link.name, hash)
});
if (repair) { if (repair) {
if (unlink(linkPath.c_str()) == 0) if (unlink(linkPath.c_str()) == 0)
printInfo("removed link '%s'", linkPath); printInfo("removed link '%s'", linkPath);
@ -1441,11 +1432,8 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
auto current = hashSink->finish(); auto current = hashSink->finish();
if (info->narHash != nullHash && info->narHash != current.first) { if (info->narHash != nullHash && info->narHash != current.first) {
logError({ printError("path '%s' was modified! expected hash '%s', got '%s'",
.name = "Invalid hash - path modified", printStorePath(i), info->narHash.to_string(Base32, true), current.first.to_string(Base32, true));
.hint = hintfmt("path '%s' was modified! expected hash '%s', got '%s'",
printStorePath(i), info->narHash.to_string(Base32, true), current.first.to_string(Base32, true))
});
if (repair) repairPath(i); else errors = true; if (repair) repairPath(i); else errors = true;
} else { } else {
@ -1496,10 +1484,7 @@ void LocalStore::verifyPath(const Path & pathS, const StringSet & store,
if (!done.insert(pathS).second) return; if (!done.insert(pathS).second) return;
if (!isStorePath(pathS)) { if (!isStorePath(pathS)) {
logError({ printError("path '%s' is not in the Nix store", pathS);
.name = "Nix path not found",
.hint = hintfmt("path '%s' is not in the Nix store", pathS)
});
return; return;
} }
@ -1522,10 +1507,7 @@ void LocalStore::verifyPath(const Path & pathS, const StringSet & store,
auto state(_state.lock()); auto state(_state.lock());
invalidatePath(*state, path); invalidatePath(*state, path);
} else { } else {
logError({ printError("path '%s' disappeared, but it still has valid referrers!", pathS);
.name = "Missing path with referrers",
.hint = hintfmt("path '%s' disappeared, but it still has valid referrers!", pathS)
});
if (repair) if (repair)
try { try {
repairPath(path); repairPath(path);

View file

@ -126,16 +126,13 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
NixOS (example: $fontconfig/var/cache being modified). Skip NixOS (example: $fontconfig/var/cache being modified). Skip
those files. FIXME: check the modification time. */ those files. FIXME: check the modification time. */
if (S_ISREG(st.st_mode) && (st.st_mode & S_IWUSR)) { if (S_ISREG(st.st_mode) && (st.st_mode & S_IWUSR)) {
logWarning({ warn("skipping suspicious writable file '%1%'", path);
.name = "Suspicious file",
.hint = hintfmt("skipping suspicious writable file '%1%'", path)
});
return; return;
} }
/* This can still happen on top-level files. */ /* This can still happen on top-level files. */
if (st.st_nlink > 1 && inodeHash.count(st.st_ino)) { if (st.st_nlink > 1 && inodeHash.count(st.st_ino)) {
debug(format("'%1%' is already linked, with %2% other file(s)") % path % (st.st_nlink - 2)); debug("'%s' is already linked, with %d other file(s)", path, st.st_nlink - 2);
return; return;
} }
@ -191,10 +188,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
} }
if (st.st_size != stLink.st_size) { if (st.st_size != stLink.st_size) {
logWarning({ warn("removing corrupted link '%s'", linkPath);
.name = "Corrupted link",
.hint = hintfmt("removing corrupted link '%1%'", linkPath)
});
unlink(linkPath.c_str()); unlink(linkPath.c_str());
goto retry; goto retry;
} }
@ -229,10 +223,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
/* Atomically replace the old file with the new hard link. */ /* Atomically replace the old file with the new hard link. */
if (rename(tempLink.c_str(), path.c_str()) == -1) { if (rename(tempLink.c_str(), path.c_str()) == -1) {
if (unlink(tempLink.c_str()) == -1) if (unlink(tempLink.c_str()) == -1)
logError({ printError("unable to unlink '%1%'", tempLink);
.name = "Unlink error",
.hint = hintfmt("unable to unlink '%1%'", tempLink)
});
if (errno == EMLINK) { if (errno == EMLINK) {
/* Some filesystems generate too many links on the rename, /* Some filesystems generate too many links on the rename,
rather than on the original link. (Probably it rather than on the original link. (Probably it

View file

@ -211,7 +211,7 @@ void handleSQLiteBusy(const SQLiteBusy & e)
lastWarned = now; lastWarned = now;
logWarning({ logWarning({
.name = "Sqlite busy", .name = "Sqlite busy",
.hint = hintfmt(e.what()) .msg = hintfmt(e.what())
}); });
} }

View file

@ -204,168 +204,109 @@ void printAtPos(const string & prefix, const ErrPos & pos, std::ostream & out)
} }
} }
static std::string indent(std::string_view indentFirst, std::string_view indentRest, std::string_view s)
{
std::string res;
bool first = true;
while (!s.empty()) {
auto end = s.find('\n');
if (!first) res += "\n";
res += first ? indentFirst : indentRest;
res += s.substr(0, end);
first = false;
if (end == s.npos) break;
s = s.substr(end + 1);
}
return res;
}
std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool showTrace) std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool showTrace)
{ {
auto errwidth = std::max<size_t>(getWindowSize().second, 20); std::string prefix;
string prefix = "";
string levelString;
switch (einfo.level) { switch (einfo.level) {
case Verbosity::lvlError: { case Verbosity::lvlError: {
levelString = ANSI_RED; prefix = ANSI_RED "error";
levelString += "error:"; break;
levelString += ANSI_NORMAL; }
case Verbosity::lvlNotice: {
prefix = ANSI_RED "note";
break; break;
} }
case Verbosity::lvlWarn: { case Verbosity::lvlWarn: {
levelString = ANSI_YELLOW; prefix = ANSI_YELLOW "warning";
levelString += "warning:";
levelString += ANSI_NORMAL;
break; break;
} }
case Verbosity::lvlInfo: { case Verbosity::lvlInfo: {
levelString = ANSI_GREEN; prefix = ANSI_GREEN "info";
levelString += "info:";
levelString += ANSI_NORMAL;
break; break;
} }
case Verbosity::lvlTalkative: { case Verbosity::lvlTalkative: {
levelString = ANSI_GREEN; prefix = ANSI_GREEN "talk";
levelString += "talk:";
levelString += ANSI_NORMAL;
break; break;
} }
case Verbosity::lvlChatty: { case Verbosity::lvlChatty: {
levelString = ANSI_GREEN; prefix = ANSI_GREEN "chat";
levelString += "chat:";
levelString += ANSI_NORMAL;
break; break;
} }
case Verbosity::lvlVomit: { case Verbosity::lvlVomit: {
levelString = ANSI_GREEN; prefix = ANSI_GREEN "vomit";
levelString += "vomit:";
levelString += ANSI_NORMAL;
break; break;
} }
case Verbosity::lvlDebug: { case Verbosity::lvlDebug: {
levelString = ANSI_YELLOW; prefix = ANSI_YELLOW "debug";
levelString += "debug:";
levelString += ANSI_NORMAL;
break;
}
default: {
levelString = fmt("invalid error level: %1%", einfo.level);
break; break;
} }
default:
assert(false);
} }
auto ndl = prefix.length() // FIXME: show the program name as part of the trace?
+ filterANSIEscapes(levelString, true).length() if (einfo.programName && einfo.programName != ErrorInfo::programName)
+ 7 prefix += fmt(" [%s]:" ANSI_NORMAL " ", einfo.programName.value_or(""));
+ einfo.name.length()
+ einfo.programName.value_or("").length();
auto dashwidth = std::max<int>(errwidth - ndl, 3);
std::string dashes(dashwidth, '-');
// divider.
if (einfo.name != "")
out << fmt("%1%%2%" ANSI_BLUE " --- %3% %4% %5%" ANSI_NORMAL,
prefix,
levelString,
einfo.name,
dashes,
einfo.programName.value_or(""));
else else
out << fmt("%1%%2%" ANSI_BLUE " -----%3% %4%" ANSI_NORMAL, prefix += ":" ANSI_NORMAL " ";
prefix,
levelString,
dashes,
einfo.programName.value_or(""));
bool nl = false; // intersperse newline between sections. std::ostringstream oss;
if (einfo.errPos.has_value() && (*einfo.errPos)) { oss << einfo.msg << "\n";
out << prefix << std::endl;
printAtPos(prefix, *einfo.errPos, out);
nl = true;
}
// description if (einfo.errPos.has_value() && *einfo.errPos) {
if (einfo.description != "") { oss << "\n";
if (nl) printAtPos("", *einfo.errPos, oss);
out << std::endl << prefix;
out << std::endl << prefix << einfo.description;
nl = true;
}
if (einfo.errPos.has_value() && (*einfo.errPos)) {
auto loc = getCodeLines(*einfo.errPos); auto loc = getCodeLines(*einfo.errPos);
// lines of code. // lines of code.
if (loc.has_value()) { if (loc.has_value()) {
if (nl) oss << "\n";
out << std::endl << prefix; printCodeLines(oss, "", *einfo.errPos, *loc);
printCodeLines(out, prefix, *einfo.errPos, *loc); oss << "\n";
nl = true;
} }
} }
// hint
if (einfo.hint.has_value()) {
if (nl)
out << std::endl << prefix;
out << std::endl << prefix << *einfo.hint;
nl = true;
}
// traces // traces
if (showTrace && !einfo.traces.empty()) if (showTrace && !einfo.traces.empty()) {
{ for (auto iter = einfo.traces.rbegin(); iter != einfo.traces.rend(); ++iter) {
const string tracetitle(" show-trace "); oss << "\n" << "" << iter->hint.str() << "\n";
int fill = errwidth - tracetitle.length();
int lw = 0;
int rw = 0;
const int min_dashes = 3;
if (fill > min_dashes * 2) {
if (fill % 2 != 0) {
lw = fill / 2;
rw = lw + 1;
}
else
{
lw = rw = fill / 2;
}
}
else
lw = rw = min_dashes;
if (nl)
out << std::endl << prefix;
out << ANSI_BLUE << std::string(lw, '-') << tracetitle << std::string(rw, '-') << ANSI_NORMAL;
for (auto iter = einfo.traces.rbegin(); iter != einfo.traces.rend(); ++iter)
{
out << std::endl << prefix;
out << ANSI_BLUE << "trace: " << ANSI_NORMAL << iter->hint.str();
if (iter->pos.has_value() && (*iter->pos)) { if (iter->pos.has_value() && (*iter->pos)) {
auto pos = iter->pos.value(); auto pos = iter->pos.value();
out << std::endl << prefix; oss << "\n";
printAtPos(prefix, pos, out); printAtPos("", pos, oss);
auto loc = getCodeLines(pos); auto loc = getCodeLines(pos);
if (loc.has_value()) if (loc.has_value()) {
{ oss << "\n";
out << std::endl << prefix; printCodeLines(oss, "", pos, *loc);
printCodeLines(out, prefix, pos, *loc); oss << "\n";
out << std::endl << prefix;
} }
} }
} }
} }
out << indent(prefix, std::string(filterANSIEscapes(prefix, true).size(), ' '), chomp(oss.str()));
return out; return out;
} }
} }

View file

@ -107,9 +107,8 @@ struct Trace {
struct ErrorInfo { struct ErrorInfo {
Verbosity level; Verbosity level;
string name; string name; // FIXME: rename
string description; // FIXME: remove? it seems to be barely used hintformat msg;
std::optional<hintformat> hint;
std::optional<ErrPos> errPos; std::optional<ErrPos> errPos;
std::list<Trace> traces; std::list<Trace> traces;
@ -133,23 +132,17 @@ public:
template<typename... Args> template<typename... Args>
BaseError(unsigned int status, const Args & ... args) BaseError(unsigned int status, const Args & ... args)
: err {.level = lvlError, : err { .level = lvlError, .msg = hintfmt(args...) }
.hint = hintfmt(args...)
}
, status(status) , status(status)
{ } { }
template<typename... Args> template<typename... Args>
BaseError(const std::string & fs, const Args & ... args) BaseError(const std::string & fs, const Args & ... args)
: err {.level = lvlError, : err { .level = lvlError, .msg = hintfmt(fs, args...) }
.hint = hintfmt(fs, args...)
}
{ } { }
BaseError(hintformat hint) BaseError(hintformat hint)
: err {.level = lvlError, : err { .level = lvlError, .msg = hint }
.hint = hint
}
{ } { }
BaseError(ErrorInfo && e) BaseError(ErrorInfo && e)
@ -206,7 +199,7 @@ public:
{ {
errNo = errno; errNo = errno;
auto hf = hintfmt(args...); auto hf = hintfmt(args...);
err.hint = hintfmt("%1%: %2%", normaltxt(hf.str()), strerror(errNo)); err.msg = hintfmt("%1%: %2%", normaltxt(hf.str()), strerror(errNo));
} }
virtual const char* sname() const override { return "SysError"; } virtual const char* sname() const override { return "SysError"; }

View file

@ -184,7 +184,7 @@ struct JSONLogger : Logger {
json["action"] = "msg"; json["action"] = "msg";
json["level"] = ei.level; json["level"] = ei.level;
json["msg"] = oss.str(); json["msg"] = oss.str();
json["raw_msg"] = ei.hint->str(); json["raw_msg"] = ei.msg.str();
if (ei.errPos.has_value() && (*ei.errPos)) { if (ei.errPos.has_value() && (*ei.errPos)) {
json["line"] = ei.errPos->line; json["line"] = ei.errPos->line;
@ -305,10 +305,7 @@ bool handleJSONLogMessage(const std::string & msg,
} }
} catch (std::exception & e) { } catch (std::exception & e) {
logError({ printError("bad JSON log message from builder: %s", e.what());
.name = "JSON log message",
.hint = hintfmt("bad log message from builder: %s", e.what())
});
} }
return true; return true;

View file

@ -52,10 +52,7 @@ size_t threshold = 256 * 1024 * 1024;
static void warnLargeDump() static void warnLargeDump()
{ {
logWarning({ warn("dumping very large path (> 256 MiB); this may run out of memory");
.name = "Large path",
.description = "dumping very large path (> 256 MiB); this may run out of memory"
});
} }
@ -306,8 +303,7 @@ Sink & operator << (Sink & sink, const Error & ex)
<< "Error" << "Error"
<< info.level << info.level
<< info.name << info.name
<< info.description << info.msg.str()
<< (info.hint ? info.hint->str() : "")
<< 0 // FIXME: info.errPos << 0 // FIXME: info.errPos
<< info.traces.size(); << info.traces.size();
for (auto & trace : info.traces) { for (auto & trace : info.traces) {
@ -374,12 +370,14 @@ Error readError(Source & source)
{ {
auto type = readString(source); auto type = readString(source);
assert(type == "Error"); assert(type == "Error");
ErrorInfo info; auto level = (Verbosity) readInt(source);
info.level = (Verbosity) readInt(source); auto name = readString(source);
info.name = readString(source); auto msg = readString(source);
info.description = readString(source); ErrorInfo info {
auto hint = readString(source); .level = level,
if (hint != "") info.hint = hintformat(std::move(format("%s") % hint)); .name = name,
.msg = hintformat(std::move(format("%s") % msg)),
};
auto havePos = readNum<size_t>(source); auto havePos = readNum<size_t>(source);
assert(havePos == 0); assert(havePos == 0);
auto nrTraces = readNum<size_t>(source); auto nrTraces = readNum<size_t>(source);

View file

@ -1,3 +1,5 @@
#if 0
#include "logging.hh" #include "logging.hh"
#include "nixexpr.hh" #include "nixexpr.hh"
#include "util.hh" #include "util.hh"
@ -41,8 +43,7 @@ namespace nix {
makeJSONLogger(*logger)->logEI({ makeJSONLogger(*logger)->logEI({
.name = "error name", .name = "error name",
.description = "error without any code lines.", .msg = hintfmt("this hint has %1% templated %2%!!",
.hint = hintfmt("this hint has %1% templated %2%!!",
"yellow", "yellow",
"values"), "values"),
.errPos = Pos(foFile, problem_file, 02, 13) .errPos = Pos(foFile, problem_file, 02, 13)
@ -62,7 +63,7 @@ namespace nix {
throw TestError(e.info()); throw TestError(e.info());
} catch (Error &e) { } catch (Error &e) {
ErrorInfo ei = e.info(); ErrorInfo ei = e.info();
ei.hint = hintfmt("%s; subsequent error message.", normaltxt(e.info().hint ? e.info().hint->str() : "")); ei.msg = hintfmt("%s; subsequent error message.", normaltxt(e.info().msg.str()));
testing::internal::CaptureStderr(); testing::internal::CaptureStderr();
logger->logEI(ei); logger->logEI(ei);
@ -95,7 +96,6 @@ namespace nix {
logger->logEI({ .level = lvlInfo, logger->logEI({ .level = lvlInfo,
.name = "Info name", .name = "Info name",
.description = "Info description",
}); });
auto str = testing::internal::GetCapturedStderr(); auto str = testing::internal::GetCapturedStderr();
@ -109,7 +109,6 @@ namespace nix {
logger->logEI({ .level = lvlTalkative, logger->logEI({ .level = lvlTalkative,
.name = "Talkative name", .name = "Talkative name",
.description = "Talkative description",
}); });
auto str = testing::internal::GetCapturedStderr(); auto str = testing::internal::GetCapturedStderr();
@ -123,7 +122,6 @@ namespace nix {
logger->logEI({ .level = lvlChatty, logger->logEI({ .level = lvlChatty,
.name = "Chatty name", .name = "Chatty name",
.description = "Talkative description",
}); });
auto str = testing::internal::GetCapturedStderr(); auto str = testing::internal::GetCapturedStderr();
@ -137,7 +135,6 @@ namespace nix {
logger->logEI({ .level = lvlDebug, logger->logEI({ .level = lvlDebug,
.name = "Debug name", .name = "Debug name",
.description = "Debug description",
}); });
auto str = testing::internal::GetCapturedStderr(); auto str = testing::internal::GetCapturedStderr();
@ -151,7 +148,6 @@ namespace nix {
logger->logEI({ .level = lvlVomit, logger->logEI({ .level = lvlVomit,
.name = "Vomit name", .name = "Vomit name",
.description = "Vomit description",
}); });
auto str = testing::internal::GetCapturedStderr(); auto str = testing::internal::GetCapturedStderr();
@ -167,7 +163,6 @@ namespace nix {
logError({ logError({
.name = "name", .name = "name",
.description = "error description",
}); });
auto str = testing::internal::GetCapturedStderr(); auto str = testing::internal::GetCapturedStderr();
@ -182,8 +177,7 @@ namespace nix {
logError({ logError({
.name = "error name", .name = "error name",
.description = "error with code lines", .msg = hintfmt("this hint has %1% templated %2%!!",
.hint = hintfmt("this hint has %1% templated %2%!!",
"yellow", "yellow",
"values"), "values"),
.errPos = Pos(foString, problem_file, 02, 13), .errPos = Pos(foString, problem_file, 02, 13),
@ -200,8 +194,7 @@ namespace nix {
logError({ logError({
.name = "error name", .name = "error name",
.description = "error without any code lines.", .msg = hintfmt("this hint has %1% templated %2%!!",
.hint = hintfmt("this hint has %1% templated %2%!!",
"yellow", "yellow",
"values"), "values"),
.errPos = Pos(foFile, problem_file, 02, 13) .errPos = Pos(foFile, problem_file, 02, 13)
@ -216,7 +209,7 @@ namespace nix {
logError({ logError({
.name = "error name", .name = "error name",
.hint = hintfmt("hint %1%", "only"), .msg = hintfmt("hint %1%", "only"),
}); });
auto str = testing::internal::GetCapturedStderr(); auto str = testing::internal::GetCapturedStderr();
@ -233,8 +226,7 @@ namespace nix {
logWarning({ logWarning({
.name = "name", .name = "name",
.description = "warning description", .msg = hintfmt("there was a %1%", "warning"),
.hint = hintfmt("there was a %1%", "warning"),
}); });
auto str = testing::internal::GetCapturedStderr(); auto str = testing::internal::GetCapturedStderr();
@ -250,8 +242,7 @@ namespace nix {
logWarning({ logWarning({
.name = "warning name", .name = "warning name",
.description = "warning description", .msg = hintfmt("this hint has %1% templated %2%!!",
.hint = hintfmt("this hint has %1% templated %2%!!",
"yellow", "yellow",
"values"), "values"),
.errPos = Pos(foStdin, problem_file, 2, 13), .errPos = Pos(foStdin, problem_file, 2, 13),
@ -274,8 +265,7 @@ namespace nix {
auto e = AssertionError(ErrorInfo { auto e = AssertionError(ErrorInfo {
.name = "wat", .name = "wat",
.description = "show-traces", .msg = hintfmt("it has been %1% days since our last error", "zero"),
.hint = hintfmt("it has been %1% days since our last error", "zero"),
.errPos = Pos(foString, problem_file, 2, 13), .errPos = Pos(foString, problem_file, 2, 13),
}); });
@ -301,8 +291,7 @@ namespace nix {
auto e = AssertionError(ErrorInfo { auto e = AssertionError(ErrorInfo {
.name = "wat", .name = "wat",
.description = "hide traces", .msg = hintfmt("it has been %1% days since our last error", "zero"),
.hint = hintfmt("it has been %1% days since our last error", "zero"),
.errPos = Pos(foString, problem_file, 2, 13), .errPos = Pos(foString, problem_file, 2, 13),
}); });
@ -377,3 +366,5 @@ namespace nix {
} }
} }
#endif

View file

@ -369,11 +369,8 @@ static void main_nix_build(int argc, char * * argv)
shell = drv->queryOutPath() + "/bin/bash"; shell = drv->queryOutPath() + "/bin/bash";
} catch (Error & e) { } catch (Error & e) {
logWarning({ logError(e.info());
.name = "bashInteractive", notice("will use bash from your environment");
.hint = hintfmt("%s; will use bash from your environment",
(e.info().hint ? e.info().hint->str() : ""))
});
shell = "bash"; shell = "bash";
} }
} }

View file

@ -124,10 +124,7 @@ static void getAllExprs(EvalState & state,
if (hasSuffix(attrName, ".nix")) if (hasSuffix(attrName, ".nix"))
attrName = string(attrName, 0, attrName.size() - 4); attrName = string(attrName, 0, attrName.size() - 4);
if (!attrs.insert(attrName).second) { if (!attrs.insert(attrName).second) {
logError({ printError("warning: name collision in input Nix expressions, skipping '%1%'", path2);
.name = "Name collision",
.hint = hintfmt("warning: name collision in input Nix expressions, skipping '%1%'", path2)
});
continue; continue;
} }
/* Load the expression on demand. */ /* Load the expression on demand. */
@ -876,11 +873,7 @@ static void queryJSON(Globals & globals, vector<DrvInfo> & elems)
auto placeholder = metaObj.placeholder(j); auto placeholder = metaObj.placeholder(j);
Value * v = i.queryMeta(j); Value * v = i.queryMeta(j);
if (!v) { if (!v) {
logError({ printError("derivation '%s' has invalid meta attribute '%s'", i.queryName(), j);
.name = "Invalid meta attribute",
.hint = hintfmt("derivation '%s' has invalid meta attribute '%s'",
i.queryName(), j)
});
placeholder.write(nullptr); placeholder.write(nullptr);
} else { } else {
PathSet context; PathSet context;
@ -1131,12 +1124,9 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
attrs2["name"] = j; attrs2["name"] = j;
Value * v = i.queryMeta(j); Value * v = i.queryMeta(j);
if (!v) if (!v)
logError({ printError(
.name = "Invalid meta attribute",
.hint = hintfmt(
"derivation '%s' has invalid meta attribute '%s'", "derivation '%s' has invalid meta attribute '%s'",
i.queryName(), j) i.queryName(), j);
});
else { else {
if (v->type() == nString) { if (v->type() == nString) {
attrs2["type"] = "string"; attrs2["type"] = "string";

View file

@ -708,10 +708,7 @@ static void opVerify(Strings opFlags, Strings opArgs)
else throw UsageError("unknown flag '%1%'", i); else throw UsageError("unknown flag '%1%'", i);
if (store->verifyStore(checkContents, repair)) { if (store->verifyStore(checkContents, repair)) {
logWarning({ warn("not all store errors were fixed");
.name = "Store consistency",
.description = "not all errors were fixed"
});
throw Exit(1); throw Exit(1);
} }
} }
@ -733,14 +730,10 @@ static void opVerifyPath(Strings opFlags, Strings opArgs)
store->narFromPath(path, sink); store->narFromPath(path, sink);
auto current = sink.finish(); auto current = sink.finish();
if (current.first != info->narHash) { if (current.first != info->narHash) {
logError({ printError("path '%s' was modified! expected hash '%s', got '%s'",
.name = "Hash mismatch",
.hint = hintfmt(
"path '%s' was modified! expected hash '%s', got '%s'",
store->printStorePath(path), store->printStorePath(path),
info->narHash.to_string(Base32, true), info->narHash.to_string(Base32, true),
current.first.to_string(Base32, true)) current.first.to_string(Base32, true));
});
status = 1; status = 1;
} }
} }

View file

@ -258,8 +258,8 @@ static void daemonLoop()
return; return;
} catch (Error & error) { } catch (Error & error) {
ErrorInfo ei = error.info(); ErrorInfo ei = error.info();
ei.hint = std::optional(hintfmt("error processing connection: %1%", // FIXME: add to trace?
(error.info().hint.has_value() ? error.info().hint->str() : ""))); ei.msg = hintfmt("error processing connection: %1%", ei.msg.str());
logError(ei); logError(ei);
} }
} }

View file

@ -61,10 +61,7 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
if (dryRun) { if (dryRun) {
stopProgressBar(); stopProgressBar();
logWarning({ warn("would upgrade to version %s", version);
.name = "Version update",
.hint = hintfmt("would upgrade to version %s", version)
});
return; return;
} }

View file

@ -101,14 +101,10 @@ struct CmdVerify : StorePathsCommand
if (hash.first != info->narHash) { if (hash.first != info->narHash) {
corrupted++; corrupted++;
act2.result(resCorruptedPath, store->printStorePath(info->path)); act2.result(resCorruptedPath, store->printStorePath(info->path));
logError({ printError("path '%s' was modified! expected hash '%s', got '%s'",
.name = "Hash error - path modified",
.hint = hintfmt(
"path '%s' was modified! expected hash '%s', got '%s'",
store->printStorePath(info->path), store->printStorePath(info->path),
info->narHash.to_string(Base32, true), info->narHash.to_string(Base32, true),
hash.first.to_string(Base32, true)) hash.first.to_string(Base32, true));
});
} }
} }
@ -156,12 +152,7 @@ struct CmdVerify : StorePathsCommand
if (!good) { if (!good) {
untrusted++; untrusted++;
act2.result(resUntrustedPath, store->printStorePath(info->path)); act2.result(resUntrustedPath, store->printStorePath(info->path));
logError({ printError("path '%s' is untrusted", store->printStorePath(info->path));
.name = "Untrusted path",
.hint = hintfmt("path '%s' is untrusted",
store->printStorePath(info->path))
});
} }
} }