diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index ce5a16e11a7..9f5d7d91daf 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -366,7 +366,7 @@ public: /* Realise the given context, and return a mapping from the placeholders * used to construct the associated value to their final store path */ - [[nodiscard]] StringMap realiseContext(const PathSet & context); + [[nodiscard]] StringMap realiseContext(const PathSet & context, const Pos &pos, const string & reason); private: @@ -496,6 +496,9 @@ struct EvalSettings : Config Setting useEvalCache{this, true, "eval-cache", "Whether to use the flake evaluation cache."}; + + Setting logImportFromDerivation{this, false, "log-import-from-derivation", + "Emit log messages for all imports from derivations at the `info` log level"}; }; extern EvalSettings evalSettings; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index defb861e637..26007bf9b46 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -37,7 +37,7 @@ namespace nix { InvalidPathError::InvalidPathError(const Path & path) : EvalError("path '%s' is not valid", path), path(path) {} -StringMap EvalState::realiseContext(const PathSet & context) +StringMap EvalState::realiseContext(const PathSet & context, const Pos & pos, std::string_view reason) { std::vector drvs; StringMap res; @@ -49,6 +49,9 @@ StringMap EvalState::realiseContext(const PathSet & context) throw InvalidPathError(store->printStorePath(ctx)); if (!outputName.empty() && ctx.isDerivation()) { drvs.push_back({ctx, {outputName}}); + if (evalSettings.logAllIFD) { + printInfo("'import from derivation of '%s' by '%s' at %s", ctxS, reason, pos); + } } else { res.insert_or_assign(ctxS, ctxS); } @@ -96,7 +99,7 @@ struct RealisePathFlags { bool checkForPureEval = true; }; -static Path realisePath(EvalState & state, const Pos & pos, Value & v, const RealisePathFlags flags = {}) +static Path realisePath(EvalState & state, const Pos & pos, Value & v, std::string_view reason, const RealisePathFlags flags = {}) { PathSet context; @@ -111,7 +114,7 @@ static Path realisePath(EvalState & state, const Pos & pos, Value & v, const Rea }(); try { - StringMap rewrites = state.realiseContext(context); + StringMap rewrites = state.realiseContext(context, pos, reason); auto realPath = state.toRealPath(rewriteStrings(path, rewrites), context); @@ -159,7 +162,7 @@ static void mkOutputString( argument. */ static void import(EvalState & state, const Pos & pos, Value & vPath, Value * vScope, Value & v) { - auto path = realisePath(state, pos, vPath); + auto path = realisePath(state, pos, vPath, "scopedImport"); // FIXME auto isValidDerivationInStore = [&]() -> std::optional { @@ -312,7 +315,7 @@ extern "C" typedef void (*ValueInitializer)(EvalState & state, Value & v); /* Load a ValueInitializer from a DSO and return whatever it initializes */ void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value & v) { - auto path = realisePath(state, pos, *args[0]); + auto path = realisePath(state, pos, *args[0], "importNative"); string sym(state.forceStringNoCtx(*args[1], pos)); @@ -356,7 +359,7 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v) commandArgs.push_back(state.coerceToString(pos, *elems[i], context, false, false).toOwned()); } try { - auto _ = state.realiseContext(context); // FIXME: Handle CA derivations + auto _ = state.realiseContext(context, pos, "exec"); // FIXME: Handle CA derivations } catch (InvalidPathError & e) { throw EvalError({ .msg = hintfmt("cannot execute '%1%', since path '%2%' is not valid", @@ -1372,7 +1375,7 @@ static void prim_pathExists(EvalState & state, const Pos & pos, Value * * args, can’t just catch the exception here because we still want to throw if something in the evaluation of `*args[0]` tries to access an unauthorized path). */ - auto path = realisePath(state, pos, *args[0], { .checkForPureEval = false }); + auto path = realisePath(state, pos, *args[0], "pathExists", { .checkForPureEval = false }); try { v.mkBool(pathExists(state.checkSourcePath(path))); @@ -1439,7 +1442,7 @@ static RegisterPrimOp primop_dirOf({ /* Return the contents of a file as a string. */ static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Value & v) { - auto path = realisePath(state, pos, *args[0]); + auto path = realisePath(state, pos, *args[0], "readFile"); string s = readFile(path); if (s.find((char) 0) != string::npos) throw Error("the contents of the file '%1%' cannot be represented as a Nix string", path); @@ -1491,7 +1494,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va string path = state.coerceToString(pos, *i->value, context, false, false).toOwned(); try { - auto rewrites = state.realiseContext(context); + auto rewrites = state.realiseContext(context, pos, "findFile"); path = rewriteStrings(path, rewrites); } catch (InvalidPathError & e) { throw EvalError({ @@ -1526,7 +1529,7 @@ static void prim_hashFile(EvalState & state, const Pos & pos, Value * * args, Va .errPos = pos }); - auto path = realisePath(state, pos, *args[1]); + auto path = realisePath(state, pos, *args[1], "hashFile"); v.mkString(hashFile(*ht, path).to_string(Base16, false)); } @@ -1545,7 +1548,7 @@ static RegisterPrimOp primop_hashFile({ /* Read a directory (without . or ..) */ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Value & v) { - auto path = realisePath(state, pos, *args[0]); + auto path = realisePath(state, pos, *args[0], "readDir"); DirEntries entries = readDirectory(path); @@ -1874,7 +1877,7 @@ static void addPath( try { // FIXME: handle CA derivation outputs (where path needs to // be rewritten to the actual output). - auto rewrites = state.realiseContext(context); + auto rewrites = state.realiseContext(context, noPos, "addPath"); path = state.toRealPath(rewriteStrings(path, rewrites), context); StorePathSet refs;