From 48a5879b63dbb7d60e7d88fa84bafe5cf59d1505 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 12 Sep 2022 12:52:07 +0200 Subject: [PATCH] Decode virtual paths in user-thrown errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit E.g. instead of error: Package ‘steam’ in /__virtual__/4/pkgs/games/steam/steam.nix:43 has an unfree license (‘unfreeRedistributable’), refusing to evaluate. you now get error: Package ‘steam’ in «github:nixos/nixpkgs/b82ccafb54163ab9024e893e578d840577785fea»/pkgs/games/steam/steam.nix:43 has an unfree license (‘unfreeRedistributable’), refusing to evaluate. --- src/libexpr/eval.cc | 2 +- src/libexpr/eval.hh | 5 +++++ src/libexpr/paths.cc | 30 ++++++++++++++++++++++++++++++ src/libexpr/primops.cc | 6 +++--- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index bc597466b..f3d2b79d3 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -1757,7 +1757,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) Nix attempted to evaluate a function as a top level expression; in this case it must have its arguments supplied either by default values, or passed explicitly with '--arg' or '--argstr'. See -https://nixos.org/manual/nix/stable/expressions/language-constructs.html#functions.)", symbols[i.name], +https://nixos.org/manual/nix/stable/expressions/language-constructs.html#functions.)", symbols[i.name], *fun.lambda.env, *fun.lambda.fun); } } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index dbf7175cc..e7a219653 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -231,6 +231,11 @@ public: /* Decode a path encoded by `encodePath()`. */ SourcePath decodePath(std::string_view s, PosIdx pos = noPos); + /* Decode all virtual paths in a string, i.e. all + /__virtual__/... substrings are replaced by the corresponding + input accessor. */ + std::string decodePaths(std::string_view s); + /* Allow access to a path. */ void allowPath(const Path & path); diff --git a/src/libexpr/paths.cc b/src/libexpr/paths.cc index 222638bad..7e409738a 100644 --- a/src/libexpr/paths.cc +++ b/src/libexpr/paths.cc @@ -63,4 +63,34 @@ SourcePath EvalState::decodePath(std::string_view s, PosIdx pos) return {rootFS, CanonPath(s)}; } +std::string EvalState::decodePaths(std::string_view s) +{ + std::string res; + + size_t pos = 0; + + while (true) { + auto m = s.find(marker, pos); + if (m == s.npos) { + res.append(s.substr(pos)); + return res; + } + + res.append(s.substr(pos, m - pos)); + + auto end = s.find_first_of(" \n\r\t'\"’:", m); + if (end == s.npos) end = s.size(); + + try { + auto path = decodePath(s.substr(m, end - m), noPos); + res.append(path.to_string()); + } catch (...) { + throw; + res.append(s.substr(pos, end - m)); + } + + pos = end; + } +} + } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 485994da0..67efc986c 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -770,7 +770,7 @@ static RegisterPrimOp primop_abort({ .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { PathSet context; - auto s = state.coerceToString(pos, *args[0], context).toOwned(); + auto s = state.decodePaths(*state.coerceToString(pos, *args[0], context)); state.debugThrowLastTrace(Abort("evaluation aborted with the following error message: '%1%'", s)); } }); @@ -788,7 +788,7 @@ static RegisterPrimOp primop_throw({ .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) { PathSet context; - auto s = state.coerceToString(pos, *args[0], context).toOwned(); + auto s = state.decodePaths(*state.coerceToString(pos, *args[0], context)); state.debugThrowLastTrace(ThrownError(s)); } }); @@ -800,7 +800,7 @@ static void prim_addErrorContext(EvalState & state, const PosIdx pos, Value * * v = *args[1]; } catch (Error & e) { PathSet context; - e.addTrace(nullptr, state.coerceToString(pos, *args[0], context).toOwned()); + e.addTrace(nullptr, state.decodePaths(*state.coerceToString(pos, *args[0], context))); throw; } }