Add detailed error mesage for coerceTo{String,Path}

This commit is contained in:
Guillaume Maudoux 2022-03-04 21:47:58 +01:00
parent be1f069746
commit 3a5855353e
14 changed files with 79 additions and 66 deletions

View file

@ -1775,7 +1775,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
/* skip canonization of first path, which would only be not
canonized in the first place if it's coming from a ./${foo} type
path */
auto part = state.coerceToString(i_pos, vTmp, context, false, firstType == nString, !first);
auto part = state.coerceToString(i_pos, vTmp, context, false, firstType == nString, !first, "");
sSize += part->size();
s.emplace_back(std::move(part));
}
@ -1958,14 +1958,15 @@ std::optional<std::string> EvalState::tryAttrsToString(const Pos & pos, Value &
if (i != v.attrs->end()) {
Value v1;
callFunction(*i->value, v, v1, pos);
return coerceToString(pos, v1, context, coerceMore, copyToStore).toOwned();
return coerceToString(pos, v1, context, coerceMore, copyToStore,
"While evaluating the result of the `toString` attribute").toOwned();
}
return {};
}
BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
bool coerceMore, bool copyToStore, bool canonicalizePath)
bool coerceMore, bool copyToStore, bool canonicalizePath, const std::string & errorCtx)
{
forceValue(v, pos);
@ -1988,12 +1989,12 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet &
if (maybeString)
return std::move(*maybeString);
auto i = v.attrs->find(sOutPath);
if (i == v.attrs->end()) throwTypeError(pos, "cannot coerce a set to a string");
return coerceToString(pos, *i->value, context, coerceMore, copyToStore);
if (i == v.attrs->end()) throwTypeError(pos, "%2%: cannot coerce %1% to a string", v, errorCtx);
return coerceToString(pos, *i->value, context, coerceMore, copyToStore, canonicalizePath, errorCtx);
}
if (v.type() == nExternal)
return v.external->coerceToString(pos, context, coerceMore, copyToStore);
return v.external->coerceToString(pos, context, coerceMore, copyToStore, errorCtx);
if (coerceMore) {
@ -2008,7 +2009,8 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet &
if (v.isList()) {
std::string result;
for (auto [n, v2] : enumerate(v.listItems())) {
result += *coerceToString(pos, *v2, context, coerceMore, copyToStore);
result += *coerceToString(pos, *v2, context, coerceMore, copyToStore, canonicalizePath,
errorCtx + ": While evaluating one element of the list");
if (n < v.listSize() - 1
/* !!! not quite correct */
&& (!v2->isList() || v2->listSize() != 0))
@ -2018,7 +2020,7 @@ BackedStringView EvalState::coerceToString(const Pos & pos, Value & v, PathSet &
}
}
throwTypeError(pos, "cannot coerce %1% to a string", v);
throwTypeError(pos, "%2%: cannot coerce %1% to a string", v, errorCtx);
}
@ -2046,22 +2048,22 @@ std::string EvalState::copyPathToStore(PathSet & context, const Path & path)
}
Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context)
Path EvalState::coerceToPath(const Pos & pos, Value & v, PathSet & context, const std::string & errorCtx)
{
auto path = coerceToString(pos, v, context, false, false).toOwned();
auto path = coerceToString(pos, v, context, false, false, true, errorCtx).toOwned();
if (path == "" || path[0] != '/')
throwEvalError(pos, "string '%1%' doesn't represent an absolute path", path);
throwEvalError(pos, "%2%: string '%1%' doesn't represent an absolute path", path, errorCtx);
return path;
}
StorePath EvalState::coerceToStorePath(const Pos & pos, Value & v, PathSet & context)
StorePath EvalState::coerceToStorePath(const Pos & pos, Value & v, PathSet & context, const std::string & errorCtx)
{
auto path = coerceToString(pos, v, context, false, false).toOwned();
auto path = coerceToString(pos, v, context, false, false, errorCtx).toOwned();
if (auto storePath = store->maybeParseStorePath(path))
return *storePath;
throw EvalError({
.msg = hintfmt("path '%1%' is not in the Nix store", path),
.msg = hintfmt("%2%: path '%1%' is not in the Nix store", path, errorCtx),
.errPos = pos
});
}
@ -2263,10 +2265,10 @@ void EvalState::printStats()
}
std::string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const
std::string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore, const std::string & errorCtx) const
{
throw TypeError({
.msg = hintfmt("cannot coerce %1% to a string", showType()),
.msg = hintfmt("%2%: cannot coerce %1% to a string", showType(), errorCtx),
.errPos = pos
});
}

View file

@ -262,17 +262,18 @@ public:
referenced paths are copied to the Nix store as a side effect. */
BackedStringView coerceToString(const Pos & pos, Value & v, PathSet & context,
bool coerceMore = false, bool copyToStore = true,
bool canonicalizePath = true);
bool canonicalizePath = true,
const std::string & errorCtx = "");
std::string copyPathToStore(PathSet & context, const Path & path);
/* Path coercion. Converts strings, paths and derivations to a
path. The result is guaranteed to be a canonicalised, absolute
path. Nothing is copied to the store. */
Path coerceToPath(const Pos & pos, Value & v, PathSet & context);
Path coerceToPath(const Pos & pos, Value & v, PathSet & context, const std::string & errorCtx);
/* Like coerceToPath, but the result must be a store path. */
StorePath coerceToStorePath(const Pos & pos, Value & v, PathSet & context);
StorePath coerceToStorePath(const Pos & pos, Value & v, PathSet & context, const std::string & errorCtx);
public:

View file

@ -260,7 +260,7 @@ static Flake getFlake(
PathSet emptyContext = {};
flake.config.settings.emplace(
setting.name,
state.coerceToString(*setting.pos, *setting.value, emptyContext, false, true, true) .toOwned());
state.coerceToString(*setting.pos, *setting.value, emptyContext, false, true, true, "") .toOwned());
}
else if (setting.value->type() == nInt)
flake.config.settings.insert({setting.name, state.forceInt(*setting.value, *setting.pos, "")});

View file

@ -74,7 +74,7 @@ std::optional<StorePath> DrvInfo::queryDrvPath() const
if (i == attrs->end())
drvPath = {std::nullopt};
else
drvPath = {state->coerceToStorePath(*i->pos, *i->value, context)};
drvPath = {state->coerceToStorePath(*i->pos, *i->value, context, "Whyle evaluating the drv path of a DrvInfo")};
}
return drvPath.value_or(std::nullopt);
}
@ -94,7 +94,7 @@ StorePath DrvInfo::queryOutPath() const
Bindings::iterator i = attrs->find(state->sOutPath);
PathSet context;
if (i != attrs->end())
outPath = state->coerceToStorePath(*i->pos, *i->value, context);
outPath = state->coerceToStorePath(*i->pos, *i->value, context, "While evaluating the output path of a DrvInfo");
}
if (!outPath)
throw UnimplementedError("CA derivations are not yet supported");
@ -122,7 +122,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall)
Bindings::iterator outPath = out->value->attrs->find(state->sOutPath);
if (outPath == out->value->attrs->end()) continue; // FIXME: throw error?
PathSet context;
outputs.emplace(name, state->coerceToStorePath(*outPath->pos, *outPath->value, context));
outputs.emplace(name, state->coerceToStorePath(*outPath->pos, *outPath->value, context, "While evaluating the outPath of an output path of a DrvInfo"));
}
} else
outputs.emplace("out", queryOutPath());

View file

@ -103,7 +103,7 @@ static Path realisePath(EvalState & state, const Pos & pos, Value & v, const Rea
auto path = [&]()
{
try {
return state.coerceToPath(pos, v, context);
return state.coerceToPath(pos, v, context, "While realising the context of a path");
} catch (Error & e) {
e.addTrace(pos, "while realising the context of a path");
throw;
@ -350,10 +350,12 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
});
}
PathSet context;
auto program = state.coerceToString(pos, *elems[0], context, false, false).toOwned();
auto program = state.coerceToString(pos, *elems[0], context, false, false,
"While evaluating the first element of the argument passed to builtins.exec").toOwned();
Strings commandArgs;
for (unsigned int i = 1; i < args[0]->listSize(); ++i) {
commandArgs.push_back(state.coerceToString(pos, *elems[i], context, false, false).toOwned());
commandArgs.push_back(state.coerceToString(pos, *elems[i], context, false, false,
"While evaluating an element of the argument passed to builtins.exec").toOwned());
}
try {
auto _ = state.realiseContext(context); // FIXME: Handle CA derivations
@ -714,7 +716,8 @@ static RegisterPrimOp primop_abort({
.fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
auto s = state.coerceToString(pos, *args[0], context).toOwned();
auto s = state.coerceToString(pos, *args[0], context,
"While evaluating the error message passed to builtins.abort").toOwned();
throw Abort("evaluation aborted with the following error message: '%1%'", s);
}
});
@ -732,7 +735,8 @@ static RegisterPrimOp primop_throw({
.fun = [](EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
auto s = state.coerceToString(pos, *args[0], context).toOwned();
auto s = state.coerceToString(pos, *args[0], context,
"While evaluating the error message passed to builtin.throw").toOwned();
throw ThrownError(s);
}
});
@ -744,7 +748,8 @@ static void prim_addErrorContext(EvalState & state, const Pos & pos, Value * * a
v = *args[1];
} catch (Error & e) {
PathSet context;
e.addTrace(std::nullopt, state.coerceToString(pos, *args[0], context).toOwned());
e.addTrace(std::nullopt, state.coerceToString(pos, *args[0], context,
"While evaluating the error message passed to builtins.addErrorContext").toOwned());
throw;
}
}
@ -757,7 +762,8 @@ static RegisterPrimOp primop_addErrorContext(RegisterPrimOp::Info {
static void prim_ceil(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
auto value = state.forceFloat(*args[0], args[0]->determinePos(pos), "While evaluating the first argument passed to builtins.ceil");
auto value = state.forceFloat(*args[0], args[0]->determinePos(pos),
"While evaluating the first argument passed to builtins.ceil");
v.mkInt(ceil(value));
}
@ -1028,7 +1034,8 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
}
if (i->name == state.sContentAddressed) {
contentAddressed = state.forceBool(*i->value, pos, "While evaluating the `__contentAddressed` attribute passed to builtins.derivationStrict");
contentAddressed = state.forceBool(*i->value, pos,
"While evaluating the `__contentAddressed` attribute passed to builtins.derivationStrict");
if (contentAddressed)
settings.requireExperimentalFeature(Xp::CaDerivations);
}
@ -1036,9 +1043,11 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
/* The `args' attribute is special: it supplies the
command-line arguments to the builder. */
else if (i->name == state.sArgs) {
state.forceList(*i->value, pos, "While evaluating the `args` attribute passed to builtins.derivationStrict");
state.forceList(*i->value, pos,
"While evaluating the `args` attribute passed to builtins.derivationStrict");
for (auto elem : i->value->listItems()) {
auto s = state.coerceToString(posDrvName, *elem, context, true).toOwned();
auto s = state.coerceToString(posDrvName, *elem, context, true,
"While evaluating an element of the `args` argument passed to builtins.derivationStrict").toOwned();
drv.args.push_back(s);
}
}
@ -1074,7 +1083,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
}
} else {
auto s = state.coerceToString(*i->pos, *i->value, context, true).toOwned();
auto s = state.coerceToString(*i->pos, *i->value, context, true, "While evaluating an attribute passed to builtins.derivationStrict").toOwned();
drv.env.emplace(key, s);
if (i->name == state.sBuilder) drv.builder = std::move(s);
else if (i->name == state.sSystem) drv.platform = std::move(s);
@ -1306,7 +1315,7 @@ static RegisterPrimOp primop_placeholder({
static void prim_toPath(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
Path path = state.coerceToPath(pos, *args[0], context);
Path path = state.coerceToPath(pos, *args[0], context, "While evaluating the first argument passed to builtins.toPath");
v.mkString(canonPath(path), context);
}
@ -1337,7 +1346,7 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V
});
PathSet context;
Path path = state.checkSourcePath(state.coerceToPath(pos, *args[0], context));
Path path = state.checkSourcePath(state.coerceToPath(pos, *args[0], context, "While evaluating the first argument passed to builtins.storePath"));
/* Resolve symlinks in path, unless path itself is a symlink
directly in the store. The latter condition is necessary so
e.g. nix-push does the right thing. */
@ -1407,7 +1416,7 @@ static RegisterPrimOp primop_pathExists({
static void prim_baseNameOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
v.mkString(baseNameOf(*state.coerceToString(pos, *args[0], context, false, false)), context);
v.mkString(baseNameOf(*state.coerceToString(pos, *args[0], context, false, false, "While evaluating the first argument passed to builtins.baseNameOf")), context);
}
static RegisterPrimOp primop_baseNameOf({
@ -1427,7 +1436,7 @@ static RegisterPrimOp primop_baseNameOf({
static void prim_dirOf(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
auto path = state.coerceToString(pos, *args[0], context, false, false);
auto path = state.coerceToString(pos, *args[0], context, false, false, "While evaluating the first argument passed to builtins.dirOf");
auto dir = dirOf(*path);
if (args[0]->type() == nPath) v.mkPath(dir); else v.mkString(dir, context);
}
@ -1484,7 +1493,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
std::string prefix;
Bindings::iterator i = v2->attrs->find(state.sPrefix);
if (i != v2->attrs->end())
prefix = state.forceStringNoCtx(*i->value, pos, "While evaluating the `prefix` attribute passed to an element of the list passed to builtins.findFile");
prefix = state.forceStringNoCtx(*i->value, pos, "While evaluating the `prefix` attribute of an element of the list passed to builtins.findFile");
i = getAttr(
state,
@ -1495,7 +1504,8 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
);
PathSet context;
auto path = state.coerceToString(pos, *i->value, context, false, false).toOwned();
auto path = state.coerceToString(pos, *i->value, context, false, false,
"While evaluating the `path` attribute of an element of the list passed to builtins.findFile").toOwned();
try {
auto rewrites = state.realiseContext(context);
@ -1945,7 +1955,7 @@ static void addPath(
static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
Path path = state.coerceToPath(pos, *args[1], context);
Path path = state.coerceToPath(pos, *args[1], context, "While evaluating the second argument (the path to filter) passed to builtins.filterSource");
state.forceValue(*args[0], pos);
if (args[0]->type() != nFunction)
@ -2027,7 +2037,7 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value
for (auto & attr : *args[0]->attrs) {
auto & n(attr.name);
if (n == "path")
path = state.coerceToPath(*attr.pos, *attr.value, context);
path = state.coerceToPath(*attr.pos, *attr.value, context, "While evaluating the `path` attribute passed to builtins.path");
else if (attr.name == state.sName)
name = state.forceStringNoCtx(*attr.value, *attr.pos, "while evaluating the `name` attribute passed to builtins.path");
else if (n == "filter") {
@ -2045,7 +2055,7 @@ static void prim_path(EvalState & state, const Pos & pos, Value * * args, Value
}
if (path.empty())
throw EvalError({
.msg = hintfmt("'path' required"),
.msg = hintfmt("Missing required 'path' attribute in the first argument to builtins.path"),
.errPos = pos
});
if (name.empty())
@ -3318,7 +3328,7 @@ static RegisterPrimOp primop_lessThan({
static void prim_toString(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
auto s = state.coerceToString(pos, *args[0], context, true, false);
auto s = state.coerceToString(pos, *args[0], context, true, false, "While evaluating the first argument passed to builtins.toString");
v.mkString(*s, context);
}
@ -3352,10 +3362,10 @@ static RegisterPrimOp primop_toString({
non-negative. */
static void prim_substring(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
int start = state.forceInt(*args[0], pos, "While evaluating the first argument passed to builtins.substring");
int len = state.forceInt(*args[1], pos, "While evaluating the second argument passed to builtins.substring");
int start = state.forceInt(*args[0], pos, "While evaluating the first argument (the start offset) passed to builtins.substring");
int len = state.forceInt(*args[1], pos, "While evaluating the second argument (the substring length) passed to builtins.substring");
PathSet context;
auto s = state.coerceToString(pos, *args[2], context);
auto s = state.coerceToString(pos, *args[2], context, "While evaluating the third argument (the string) passed to builtins.substring");
if (start < 0)
throw EvalError({
@ -3389,7 +3399,7 @@ static RegisterPrimOp primop_substring({
static void prim_stringLength(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
auto s = state.coerceToString(pos, *args[0], context);
auto s = state.coerceToString(pos, *args[0], context, "While evaluating the argument passed to builtins.stringLength");
v.mkInt(s->size());
}
@ -3641,8 +3651,8 @@ static void prim_concatStringsSep(EvalState & state, const Pos & pos, Value * *
{
PathSet context;
auto sep = state.forceString(*args[0], context, pos, "While evaluating the first argument passed to builtins.concatStringsSep");
state.forceList(*args[1], pos, "While evaluating the second argument passed to builtins.concatStringsSep");
auto sep = state.forceString(*args[0], context, pos, "While evaluating the first argument (the separator string) passed to builtins.concatStringsSep");
state.forceList(*args[1], pos, "While evaluating the second argument (the list of strings to concat) passed to builtins.concatStringsSep");
std::string res;
res.reserve((args[1]->listSize() + 32) * sep.size());
@ -3650,7 +3660,7 @@ static void prim_concatStringsSep(EvalState & state, const Pos & pos, Value * *
for (auto elem : args[1]->listItems()) {
if (first) first = false; else res += sep;
res += *state.coerceToString(pos, *elem, context);
res += *state.coerceToString(pos, *elem, context, "While evaluating one element of the list of strings to concat passed to builtins.concatStringsSep");
}
v.mkString(res, context);

View file

@ -7,7 +7,7 @@ namespace nix {
static void prim_unsafeDiscardStringContext(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
auto s = state.coerceToString(pos, *args[0], context);
auto s = state.coerceToString(pos, *args[0], context, "While evaluating the argument passed to builtins.unsafeDiscardStringContext");
v.mkString(*s);
}
@ -33,7 +33,7 @@ static RegisterPrimOp primop_hasContext("__hasContext", 1, prim_hasContext);
static void prim_unsafeDiscardOutputDependency(EvalState & state, const Pos & pos, Value * * args, Value & v)
{
PathSet context;
auto s = state.coerceToString(pos, *args[0], context);
auto s = state.coerceToString(pos, *args[0], context, "While evaluating the argument passed to builtins.unsafeDiscardOutputDependency");
PathSet context2;
for (auto & p : context)

View file

@ -22,7 +22,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
for (auto & attr : *args[0]->attrs) {
std::string_view n(attr.name);
if (n == "url")
url = state.coerceToString(*attr.pos, *attr.value, context, false, false).toOwned();
url = state.coerceToString(*attr.pos, *attr.value, context, false, false, "While evaluating the `url` attribute passed to builtins.fetchMercurial").toOwned();
else if (n == "rev") {
// Ugly: unlike fetchGit, here the "rev" attribute can
// be both a revision or a branch/tag name.
@ -48,7 +48,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar
});
} else
url = state.coerceToString(pos, *args[0], context, false, false).toOwned();
url = state.coerceToString(pos, *args[0], context, false, false, "While evaluating the first argument passed to builtins.fetchMercurial").toOwned();
// FIXME: git externals probably can be used to bypass the URI
// whitelist. Ah well.

View file

@ -125,7 +125,7 @@ static void fetchTree(
if (attr.name == state.sType) continue;
state.forceValue(*attr.value, *attr.pos);
if (attr.value->type() == nPath || attr.value->type() == nString) {
auto s = state.coerceToString(*attr.pos, *attr.value, context, false, false).toOwned();
auto s = state.coerceToString(*attr.pos, *attr.value, context, false, false, "").toOwned();
attrs.emplace(attr.name,
attr.name == "url"
? type == "git"
@ -151,7 +151,7 @@ static void fetchTree(
input = fetchers::Input::fromAttrs(std::move(attrs));
} else {
auto url = state.coerceToString(pos, *args[0], context, false, false).toOwned();
auto url = state.coerceToString(pos, *args[0], context, false, false, "While evaluating the first argument passed to the fetcher").toOwned();
if (type == "git") {
fetchers::Attrs attrs;

View file

@ -85,7 +85,7 @@ class ExternalValueBase
/* Coerce the value to a string. Defaults to uncoercable, i.e. throws an
* error.
*/
virtual std::string coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const;
virtual std::string coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore, const std::string & errorCtx) const;
/* Compare to another value of the same type. Defaults to uncomparable,
* i.e. always false.

View file

@ -132,9 +132,9 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
state.forceValue(topLevel, [&]() { return topLevel.determinePos(noPos); });
PathSet context;
Attr & aDrvPath(*topLevel.attrs->find(state.sDrvPath));
auto topLevelDrv = state.coerceToStorePath(*aDrvPath.pos, *aDrvPath.value, context);
auto topLevelDrv = state.coerceToStorePath(*aDrvPath.pos, *aDrvPath.value, context, "");
Attr & aOutPath(*topLevel.attrs->find(state.sOutPath));
auto topLevelOut = state.coerceToStorePath(*aOutPath.pos, *aOutPath.value, context);
auto topLevelOut = state.coerceToStorePath(*aOutPath.pos, *aOutPath.value, context, "");
/* Realise the resulting store expression. */
debug("building user environment");

View file

@ -97,13 +97,13 @@ struct CmdBundle : InstallableCommand
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
PathSet context2;
auto drvPath = evalState->coerceToStorePath(*attr1->pos, *attr1->value, context2);
auto drvPath = evalState->coerceToStorePath(*attr1->pos, *attr1->value, context2, "");
auto attr2 = vRes->attrs->get(evalState->sOutPath);
if (!attr2)
throw Error("the bundler '%s' does not produce a derivation", bundler.what());
auto outPath = evalState->coerceToStorePath(*attr2->pos, *attr2->value, context2);
auto outPath = evalState->coerceToStorePath(*attr2->pos, *attr2->value, context2, "");
store->buildPaths({ DerivedPath::Built { drvPath } });

View file

@ -107,7 +107,7 @@ struct CmdEval : MixJSON, InstallableCommand
else if (raw) {
stopProgressBar();
std::cout << *state->coerceToString(noPos, *v, context);
std::cout << *state->coerceToString(noPos, *v, context, "While generating the eval command output");
}
else if (json) {

View file

@ -448,7 +448,7 @@ struct CmdFlakeCheck : FlakeCommand
if (auto attr = v.attrs->get(state->symbols.create("path"))) {
if (attr->name == state->symbols.create("path")) {
PathSet context;
auto path = state->coerceToPath(*attr->pos, *attr->value, context);
auto path = state->coerceToPath(*attr->pos, *attr->value, context, "");
if (!store->isInStore(path))
throw Error("template '%s' has a bad 'path' attribute");
// TODO: recursively check the flake in 'path'.

View file

@ -461,7 +461,7 @@ bool NixRepl::processLine(std::string line)
if (v.type() == nPath || v.type() == nString) {
PathSet context;
auto filename = state->coerceToString(noPos, v, context);
auto filename = state->coerceToString(noPos, v, context, "While evaluating the filename to edit");
pos.file = state->symbols.create(*filename);
} else if (v.isLambda()) {
pos = v.lambda.fun->pos;
@ -780,7 +780,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
Bindings::iterator i = v.attrs->find(state->sDrvPath);
PathSet context;
if (i != v.attrs->end())
str << state->store->printStorePath(state->coerceToStorePath(*i->pos, *i->value, context));
str << state->store->printStorePath(state->coerceToStorePath(*i->pos, *i->value, context, "While evaluating the drvPath of a derivation"));
else
str << "???";
str << "»";