Merge pull request #4467 from edolstra/error-formatting

Improve error formatting
This commit is contained in:
Eelco Dolstra 2021-01-25 12:50:57 +01:00 committed by GitHub
commit 488a826842
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 265 additions and 454 deletions

View file

@ -176,13 +176,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;
@ -191,25 +192,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";
} }
@ -234,12 +231,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)));
@ -893,9 +890,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)
@ -1071,12 +1071,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
@ -3088,10 +3085,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;
@ -3385,10 +3379,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

@ -144,11 +144,8 @@ void SubstitutionGoal::tryNext()
only after we've downloaded the path. */ only after we've downloaded the path. */
if (!sub->isTrusted && worker.store.pathInfoIsTrusted(*info)) if (!sub->isTrusted && worker.store.pathInfoIsTrusted(*info))
{ {
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

@ -456,10 +456,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

@ -639,11 +639,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())
});
} }
{ {
@ -859,11 +855,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))
@ -1406,12 +1401,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);
@ -1444,11 +1435,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 {
@ -1499,10 +1487,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;
} }
@ -1525,10 +1510,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

@ -43,9 +43,9 @@ string showErrPos(const ErrPos & errPos)
{ {
if (errPos.line > 0) { if (errPos.line > 0) {
if (errPos.column > 0) { if (errPos.column > 0) {
return fmt("(%1%:%2%)", errPos.line, errPos.column); return fmt("%d:%d", errPos.line, errPos.column);
} else { } else {
return fmt("(%1%)", errPos.line); return fmt("%d", errPos.line);
} }
} }
else { else {
@ -180,24 +180,20 @@ void printCodeLines(std::ostream & out,
} }
} }
void printAtPos(const string & prefix, const ErrPos & pos, std::ostream & out) void printAtPos(const ErrPos & pos, std::ostream & out)
{ {
if (pos) if (pos) {
{
switch (pos.origin) { switch (pos.origin) {
case foFile: { case foFile: {
out << prefix << ANSI_BLUE << "at: " << ANSI_YELLOW << showErrPos(pos) << out << fmt(ANSI_BLUE "at " ANSI_YELLOW "%s:%s" ANSI_NORMAL ":", pos.file, showErrPos(pos));
ANSI_BLUE << " in file: " << ANSI_NORMAL << pos.file;
break; break;
} }
case foString: { case foString: {
out << prefix << ANSI_BLUE << "at: " << ANSI_YELLOW << showErrPos(pos) << out << fmt(ANSI_BLUE "at " ANSI_YELLOW "«string»:%s" ANSI_NORMAL ":", showErrPos(pos));
ANSI_BLUE << " from string" << ANSI_NORMAL;
break; break;
} }
case foStdin: { case foStdin: {
out << prefix << ANSI_BLUE << "at: " << ANSI_YELLOW << showErrPos(pos) << out << fmt(ANSI_BLUE "at " ANSI_YELLOW "«stdin»:%s" ANSI_NORMAL ":", showErrPos(pos));
ANSI_BLUE << " from stdin" << ANSI_NORMAL;
break; break;
} }
default: default:
@ -206,168 +202,108 @@ 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 += chomp(std::string(first ? indentFirst : indentRest) + std::string(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

@ -1249,7 +1249,7 @@ template StringSet tokenizeString(std::string_view s, const string & separators)
template vector<string> tokenizeString(std::string_view s, const string & separators); template vector<string> tokenizeString(std::string_view s, const string & separators);
string chomp(const string & s) string chomp(std::string_view s)
{ {
size_t i = s.find_last_not_of(" \n\r\t"); size_t i = s.find_last_not_of(" \n\r\t");
return i == string::npos ? "" : string(s, 0, i + 1); return i == string::npos ? "" : string(s, 0, i + 1);

View file

@ -373,8 +373,9 @@ template<class C> Strings quoteStrings(const C & c)
} }
/* Remove trailing whitespace from a string. */ /* Remove trailing whitespace from a string. FIXME: return
string chomp(const string & s); std::string_view. */
string chomp(std::string_view s);
/* Remove whitespace from the start and end of a string. */ /* Remove whitespace from the start and end of a string. */

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))
});
} }
} }

View file

@ -39,18 +39,12 @@ std::set<std::string> runResolver(const Path & filename)
throw SysError("statting '%s'", filename); throw SysError("statting '%s'", filename);
if (!S_ISREG(st.st_mode)) { if (!S_ISREG(st.st_mode)) {
logError({ printError("file '%s' is not a regular MACH binary", filename);
.name = "Regular MACH file",
.hint = hintfmt("file '%s' is not a regular file", filename)
});
return {}; return {};
} }
if (st.st_size < sizeof(mach_header_64)) { if (st.st_size < sizeof(mach_header_64)) {
logError({ printError("file '%s' is too short for a MACH binary", filename);
.name = "File too short",
.hint = hintfmt("file '%s' is too short for a MACH binary", filename)
});
return {}; return {};
} }
@ -72,19 +66,13 @@ std::set<std::string> runResolver(const Path & filename)
} }
} }
if (mach64_offset == 0) { if (mach64_offset == 0) {
logError({ printError("could not find any mach64 blobs in file '%1%', continuing...", filename);
.name = "No mach64 blobs",
.hint = hintfmt("Could not find any mach64 blobs in file '%1%', continuing...", filename)
});
return {}; return {};
} }
} else if (magic == MH_MAGIC_64 || magic == MH_CIGAM_64) { } else if (magic == MH_MAGIC_64 || magic == MH_CIGAM_64) {
mach64_offset = 0; mach64_offset = 0;
} else { } else {
logError({ printError("Object file has unknown magic number '%1%', skipping it...", magic);
.name = "Magic number",
.hint = hintfmt("Object file has unknown magic number '%1%', skipping it...", magic)
});
return {}; return {};
} }

View file

@ -17,10 +17,10 @@ nix-env -q --foo 2>&1 | grep "unknown flag"
# Eval Errors. # Eval Errors.
eval_arg_res=$(nix-instantiate --eval -E 'let a = {} // a; in a.foo' 2>&1 || true) eval_arg_res=$(nix-instantiate --eval -E 'let a = {} // a; in a.foo' 2>&1 || true)
echo $eval_arg_res | grep "at: (1:15) from string" echo $eval_arg_res | grep "at «string»:1:15:"
echo $eval_arg_res | grep "infinite recursion encountered" echo $eval_arg_res | grep "infinite recursion encountered"
eval_stdin_res=$(echo 'let a = {} // a; in a.foo' | nix-instantiate --eval -E - 2>&1 || true) eval_stdin_res=$(echo 'let a = {} // a; in a.foo' | nix-instantiate --eval -E - 2>&1 || true)
echo $eval_stdin_res | grep "at: (1:15) from stdin" echo $eval_stdin_res | grep "at «stdin»:1:15:"
echo $eval_stdin_res | grep "infinite recursion encountered" echo $eval_stdin_res | grep "infinite recursion encountered"