From 9151dbff88fa765496e970aee2db5a8ce640b3a4 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 2 Jun 2022 10:26:46 -0600 Subject: ignore-try flag --- src/libexpr/eval.cc | 1 + src/libexpr/eval.hh | 1 + src/libexpr/primops.cc | 14 ++++++++++++++ 3 files changed, 16 insertions(+) (limited to 'src/libexpr') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 40462afdf..c35527992 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -467,6 +467,7 @@ EvalState::EvalState( , debugRepl(0) , debugStop(false) , debugQuit(false) + , ignoreTry(false) , regexCache(makeRegexCache()) #if HAVE_BOEHMGC , valueAllocCache(std::allocate_shared(traceable_allocator(), nullptr)) diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 7b8732169..3c3dddd1e 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -130,6 +130,7 @@ public: void (* debugRepl)(ref es, const ValMap & extraEnv); bool debugStop; bool debugQuit; + bool ignoreTry; std::list debugTraces; std::map> exprEnvs; const std::shared_ptr getStaticEnv(const Expr & expr) const diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index eea274301..772898932 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -851,6 +851,15 @@ static RegisterPrimOp primop_floor({ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v) { auto attrs = state.buildBindings(2); + + void (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; + if (state.debugRepl && state.ignoreTry) + { + // to prevent starting the repl from exceptions withing a tryEval, null it. + savedDebugRepl = state.debugRepl; + state.debugRepl = nullptr; + } + try { state.forceValue(*args[0], pos); attrs.insert(state.sValue, args[0]); @@ -859,6 +868,11 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va attrs.alloc(state.sValue).mkBool(false); attrs.alloc("success").mkBool(false); } + + // restore the debugRepl pointer if we saved it earlier. + if (savedDebugRepl) + state.debugRepl = savedDebugRepl; + v.mkAttrs(attrs); } -- cgit v1.2.3 From bc0d41e9baa19c10977dd38f4bb255c14bd6554d Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 2 Jun 2022 12:17:28 -0600 Subject: print message with exceptions in a try clause --- src/libexpr/eval.cc | 12 ++++++++++-- src/libexpr/eval.hh | 1 + src/libexpr/primops.cc | 15 +++++++++++---- 3 files changed, 22 insertions(+), 6 deletions(-) (limited to 'src/libexpr') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index c35527992..60214453a 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -464,10 +464,11 @@ EvalState::EvalState( , emptyBindings(0) , store(store) , buildStore(buildStore ? buildStore : store) - , debugRepl(0) + , debugRepl(nullptr) , debugStop(false) , debugQuit(false) , ignoreTry(false) + , trylevel(0) , regexCache(makeRegexCache()) #if HAVE_BOEHMGC , valueAllocCache(std::allocate_shared(traceable_allocator(), nullptr)) @@ -833,7 +834,14 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & : nullptr; if (error) - printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error->what()); + { + printError("%s\n\n", error->what()); + + if (trylevel > 0 && error->info().level != lvlInfo) + printError("This exception occurred in a try clause. use " ANSI_GREEN "--ignore-try" ANSI_NORMAL " to skip these.\n"); + + printError(ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error->what()); + } auto se = getStaticEnv(expr); if (se) { diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 3c3dddd1e..9aff77042 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -131,6 +131,7 @@ public: bool debugStop; bool debugQuit; bool ignoreTry; + int trylevel; std::list debugTraces; std::map> exprEnvs; const std::shared_ptr getStaticEnv(const Expr & expr) const diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 772898932..e4fd8f650 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -853,11 +853,15 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va auto attrs = state.buildBindings(2); void (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; - if (state.debugRepl && state.ignoreTry) + if (state.debugRepl) { - // to prevent starting the repl from exceptions withing a tryEval, null it. - savedDebugRepl = state.debugRepl; - state.debugRepl = nullptr; + state.trylevel++; + if (state.ignoreTry) + { + // to prevent starting the repl from exceptions withing a tryEval, null it. + savedDebugRepl = state.debugRepl; + state.debugRepl = nullptr; + } } try { @@ -873,6 +877,9 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va if (savedDebugRepl) state.debugRepl = savedDebugRepl; + if (state.debugRepl) + state.trylevel--; + v.mkAttrs(attrs); } -- cgit v1.2.3 From 8cf6ae86648336bd67a1555302b21576b790c368 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Thu, 2 Jun 2022 12:29:38 -0600 Subject: use Counter class to count tryEval levels --- src/libexpr/primops.cc | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'src/libexpr') diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index e4fd8f650..ecc1c136a 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -846,22 +846,30 @@ static RegisterPrimOp primop_floor({ .fun = prim_floor, }); +class Counter +{ + private: + int &counter; + public: + Counter(int &counter) :counter(counter) { counter++; } + ~Counter() { counter--; } +}; + /* Try evaluating the argument. Success => {success=true; value=something;}, * else => {success=false; value=false;} */ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v) { auto attrs = state.buildBindings(2); + /* increment state.trylevel, and decrement it when this function returns. */ + Counter trylevel(state.trylevel); + void (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; - if (state.debugRepl) + if (state.debugRepl && state.ignoreTry) { - state.trylevel++; - if (state.ignoreTry) - { - // to prevent starting the repl from exceptions withing a tryEval, null it. - savedDebugRepl = state.debugRepl; - state.debugRepl = nullptr; - } + /* to prevent starting the repl from exceptions withing a tryEval, null it. */ + savedDebugRepl = state.debugRepl; + state.debugRepl = nullptr; } try { @@ -877,9 +885,6 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va if (savedDebugRepl) state.debugRepl = savedDebugRepl; - if (state.debugRepl) - state.trylevel--; - v.mkAttrs(attrs); } -- cgit v1.2.3 From 81a486c607405027914d1f445bb570f19a4977b7 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 2 Jun 2022 16:55:28 +0200 Subject: Shut up clang warnings --- src/libexpr/eval.hh | 4 ++-- src/libexpr/nixexpr.hh | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src/libexpr') diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 7b8732169..4eaa3c9b0 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -150,7 +150,7 @@ public: if (debugRepl) runDebugRepl(&error, env, expr); - throw error; + throw std::move(error); } template @@ -165,7 +165,7 @@ public: runDebugRepl(&e, last.env, last.expr); } - throw e; + throw std::move(e); } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 8813c61a9..5eb022770 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -150,16 +150,16 @@ struct Expr }; #define COMMON_METHODS \ - void show(const SymbolTable & symbols, std::ostream & str) const; \ - void eval(EvalState & state, Env & env, Value & v); \ - void bindVars(EvalState & es, const std::shared_ptr & env); + void show(const SymbolTable & symbols, std::ostream & str) const override; \ + void eval(EvalState & state, Env & env, Value & v) override; \ + void bindVars(EvalState & es, const std::shared_ptr & env) override; struct ExprInt : Expr { NixInt n; Value v; ExprInt(NixInt n) : n(n) { v.mkInt(n); }; - Value * maybeThunk(EvalState & state, Env & env); + Value * maybeThunk(EvalState & state, Env & env) override; COMMON_METHODS }; @@ -168,7 +168,7 @@ struct ExprFloat : Expr NixFloat nf; Value v; ExprFloat(NixFloat nf) : nf(nf) { v.mkFloat(nf); }; - Value * maybeThunk(EvalState & state, Env & env); + Value * maybeThunk(EvalState & state, Env & env) override; COMMON_METHODS }; @@ -177,7 +177,7 @@ struct ExprString : Expr std::string s; Value v; ExprString(std::string s) : s(std::move(s)) { v.mkString(this->s.data()); }; - Value * maybeThunk(EvalState & state, Env & env); + Value * maybeThunk(EvalState & state, Env & env) override; COMMON_METHODS }; @@ -186,7 +186,7 @@ struct ExprPath : Expr std::string s; Value v; ExprPath(std::string s) : s(std::move(s)) { v.mkPath(this->s.c_str()); }; - Value * maybeThunk(EvalState & state, Env & env); + Value * maybeThunk(EvalState & state, Env & env) override; COMMON_METHODS }; @@ -213,7 +213,7 @@ struct ExprVar : Expr ExprVar(Symbol name) : name(name) { }; ExprVar(const PosIdx & pos, Symbol name) : pos(pos), name(name) { }; - Value * maybeThunk(EvalState & state, Env & env); + Value * maybeThunk(EvalState & state, Env & env) override; PosIdx getPos() const override { return pos; } COMMON_METHODS }; @@ -326,7 +326,7 @@ struct ExprLambda : Expr : pos(pos), formals(formals), body(body) { } - void setName(Symbol name); + void setName(Symbol name) override; std::string showNamePos(const EvalState & state) const; inline bool hasFormals() const { return formals != nullptr; } PosIdx getPos() const override { return pos; } @@ -395,15 +395,15 @@ struct ExprOpNot : Expr Expr * e1, * e2; \ name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \ name(const PosIdx & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \ - void show(const SymbolTable & symbols, std::ostream & str) const \ + void show(const SymbolTable & symbols, std::ostream & str) const override \ { \ str << "("; e1->show(symbols, str); str << " " s " "; e2->show(symbols, str); str << ")"; \ } \ - void bindVars(EvalState & es, const std::shared_ptr & env) \ + void bindVars(EvalState & es, const std::shared_ptr & env) override \ { \ e1->bindVars(es, env); e2->bindVars(es, env); \ } \ - void eval(EvalState & state, Env & env, Value & v); \ + void eval(EvalState & state, Env & env, Value & v) override; \ PosIdx getPos() const override { return pos; } \ }; -- cgit v1.2.3 From 49ff4ef6373f4aaeb6194fb4a195d3037c74312e Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Fri, 10 Jun 2022 12:22:36 -0600 Subject: remove unused parameter --- src/libexpr/eval.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libexpr') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 60214453a..28256ec5c 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -840,7 +840,7 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & if (trylevel > 0 && error->info().level != lvlInfo) printError("This exception occurred in a try clause. use " ANSI_GREEN "--ignore-try" ANSI_NORMAL " to skip these.\n"); - printError(ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error->what()); + printError(ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL); } auto se = getStaticEnv(expr); -- cgit v1.2.3 From d82a3dc70d5a5c68815327a8922c8db0d0c95cdb Mon Sep 17 00:00:00 2001 From: Alexander Bantyev Date: Mon, 13 Jun 2022 20:49:16 +0400 Subject: flake.cc: Make non-flake overrides sticky Overrides for inputs with flake=false were non-sticky, since they changed the `original` in `flake.lock`. This fixes it, by using the same locked original for both flake and non-flake inputs. --- src/libexpr/flake/flake.cc | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'src/libexpr') diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 35c841897..920726b73 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -513,6 +513,15 @@ LockedFlake lockFlake( if (!lockFlags.allowMutable && !input.ref->input.isLocked()) throw Error("cannot update flake input '%s' in pure mode", inputPathS); + /* Note: in case of an --override-input, we use + the *original* ref (input2.ref) for the + "original" field, rather than the + override. This ensures that the override isn't + nuked the next time we update the lock + file. That is, overrides are sticky unless you + use --no-write-lock-file. */ + auto ref = input2.ref ? *input2.ref : *input.ref; + if (input.isFlake) { Path localPath = parentPath; FlakeRef localRef = *input.ref; @@ -524,15 +533,7 @@ LockedFlake lockFlake( auto inputFlake = getFlake(state, localRef, useRegistries, flakeCache, inputPath); - /* Note: in case of an --override-input, we use - the *original* ref (input2.ref) for the - "original" field, rather than the - override. This ensures that the override isn't - nuked the next time we update the lock - file. That is, overrides are sticky unless you - use --no-write-lock-file. */ - auto childNode = std::make_shared( - inputFlake.lockedRef, input2.ref ? *input2.ref : *input.ref); + auto childNode = std::make_shared(inputFlake.lockedRef, ref); node->inputs.insert_or_assign(id, childNode); @@ -560,7 +561,7 @@ LockedFlake lockFlake( auto [sourceInfo, resolvedRef, lockedRef] = fetchOrSubstituteTree( state, *input.ref, useRegistries, flakeCache); node->inputs.insert_or_assign(id, - std::make_shared(lockedRef, *input.ref, false)); + std::make_shared(lockedRef, ref, false)); } } -- cgit v1.2.3 From 983efdbde47bd0ecaff866d43c3155761574c112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophane=20Hufschmitt?= Date: Tue, 21 Jun 2022 14:08:18 +0200 Subject: Forbid the tilde expansion in pure eval mode Fix #6684 --- src/libexpr/parser.y | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/libexpr') diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 8cbc2da4d..7c9b5a2db 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -520,6 +520,12 @@ path_start $$ = new ExprPath(path); } | HPATH { + if (evalSettings.pureEval) { + throw Error( + "the path '%s' can not be resolved in pure mode", + std::string_view($1.p, $1.l) + ); + } Path path(getHome() + std::string($1.p + 1, $1.l - 1)); $$ = new ExprPath(path); } -- cgit v1.2.3 From 2beb929753d28604ccd40057fca295a11640e40e Mon Sep 17 00:00:00 2001 From: Rick van Schijndel Date: Thu, 23 Jun 2022 21:11:08 +0200 Subject: eval-cache: cast rowId to correct type Prevents errors when running with UBSan: /nix/store/j5vhrywqmz1ixwhsmmjjxa85fpwryzh0-gcc-11.3.0/include/c++/11.3.0/bits/stl_pair.h:353:4: runtime error: load of value 229, which is not a valid value for type 'AttrType' --- src/libexpr/eval-cache.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libexpr') diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index d77b25898..dbfd8e70b 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -282,7 +282,7 @@ struct AttrDb auto queryAttribute(state->queryAttribute.use()(key.first)(symbols[key.second])); if (!queryAttribute.next()) return {}; - auto rowId = (AttrType) queryAttribute.getInt(0); + auto rowId = (AttrId) queryAttribute.getInt(0); auto type = (AttrType) queryAttribute.getInt(1); switch (type) { -- cgit v1.2.3 From e8109cf405d672c50b1e5a25c632ddcb1d517233 Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Sun, 26 Jun 2022 12:00:00 +0000 Subject: fetchGit: document `shallow` argument --- src/libexpr/primops/fetchTree.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/libexpr') diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index e5eeea520..84e7f5c02 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -364,6 +364,10 @@ static RegisterPrimOp primop_fetchGit({ A Boolean parameter that specifies whether submodules should be checked out. Defaults to `false`. + - shallow\ + A Boolean parameter that specifies whether fetching a shallow clone + is allowed. Defaults to `false`. + - allRefs\ Whether to fetch all refs of the repository. With this argument being true, it's possible to load a `rev` from *any* `ref` (by default only -- cgit v1.2.3 From 455177cbe0aa4c71040857c9b3fa3ccc6312830a Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 29 Jun 2022 11:29:36 +0200 Subject: src/libexpr/tests/primops.cc: Quote Nix expressions Otherwise they don't survive reformatting, see the failure in https://github.com/NixOS/nix/pull/6721. --- src/libexpr/tests/primops.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src/libexpr') diff --git a/src/libexpr/tests/primops.cc b/src/libexpr/tests/primops.cc index f65b6593d..16cf66d2c 100644 --- a/src/libexpr/tests/primops.cc +++ b/src/libexpr/tests/primops.cc @@ -540,22 +540,22 @@ namespace nix { ASSERT_THAT(v, IsStringEq(output)); } -#define CASE(input, output) (std::make_tuple(std::string_view("builtins.toString " #input), std::string_view(output))) +#define CASE(input, output) (std::make_tuple(std::string_view("builtins.toString " input), std::string_view(output))) INSTANTIATE_TEST_SUITE_P( toString, ToStringPrimOpTest, testing::Values( - CASE("foo", "foo"), - CASE(1, "1"), - CASE([1 2 3], "1 2 3"), - CASE(.123, "0.123000"), - CASE(true, "1"), - CASE(false, ""), - CASE(null, ""), - CASE({ v = "bar"; __toString = self: self.v; }, "bar"), - CASE({ v = "bar"; __toString = self: self.v; outPath = "foo"; }, "bar"), - CASE({ outPath = "foo"; }, "foo"), - CASE(./test, "/test") + CASE(R"("foo")", "foo"), + CASE(R"(1)", "1"), + CASE(R"([1 2 3])", "1 2 3"), + CASE(R"(.123)", "0.123000"), + CASE(R"(true)", "1"), + CASE(R"(false)", ""), + CASE(R"(null)", ""), + CASE(R"({ v = "bar"; __toString = self: self.v; })", "bar"), + CASE(R"({ v = "bar"; __toString = self: self.v; outPath = "foo"; })", "bar"), + CASE(R"({ outPath = "foo"; })", "foo"), + CASE(R"(./test)", "/test") ) ); #undef CASE -- cgit v1.2.3 From ba1fe85b65e4e6408971bb36c40e0aad684cfc74 Mon Sep 17 00:00:00 2001 From: Gytis Ivaskevicius Date: Mon, 13 Dec 2021 09:24:24 +0200 Subject: Add builtins.traceVerbose Co-Authored-By: Silvan Mosberger Add builtins.traceVerbose tests --- src/libexpr/eval.hh | 3 +++ src/libexpr/primops.cc | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'src/libexpr') diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 4eaa3c9b0..7db954bf4 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -646,6 +646,9 @@ struct EvalSettings : Config Setting useEvalCache{this, true, "eval-cache", "Whether to use the flake evaluation cache."}; + + Setting traceVerbose{this, false, "trace-verbose", + "Whether `builtins.traceVerbose` should trace its first argument when evaluated."}; }; extern EvalSettings evalSettings; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index eea274301..ac84e26c3 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -970,6 +970,15 @@ static RegisterPrimOp primop_trace({ }); +/* Takes two arguments and evaluates to the second one. Used as the + * builtins.traceVerbose implementation when --trace-verbose is not enabled + */ +static void prim_second(EvalState & state, const Pos & pos, Value * * args, Value & v) +{ + state.forceValue(*args[1], pos); + v = *args[1]; +} + /************************************************************* * Derivations *************************************************************/ @@ -3926,6 +3935,18 @@ void EvalState::createBaseEnv() addPrimOp("__exec", 1, prim_exec); } + addPrimOp({ + .fun = evalSettings.traceVerbose ? prim_trace : prim_second, + .arity = 2, + .name = symbols.create("__traceVerbose"), + .args = { "e1", "e2" }, + .doc = R"( + Evaluate *e1* and print its abstract syntax representation on standard + error if `--trace-verbose` is enabled. Then return *e2*. This function + is useful for debugging. + )", + }); + /* Add a value containing the current Nix expression search path. */ mkList(v, searchPath.size()); int n = 0; -- cgit v1.2.3 From b2703c73a4e28a2456a599a122cc2b4ab0d33430 Mon Sep 17 00:00:00 2001 From: Gytis Ivaskevicius Date: Tue, 5 Jul 2022 19:56:39 +0300 Subject: builtins.traceVerbose: Post rebase fixes --- src/libexpr/primops.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libexpr') diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index ac84e26c3..5fda9af75 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -973,7 +973,7 @@ static RegisterPrimOp primop_trace({ /* Takes two arguments and evaluates to the second one. Used as the * builtins.traceVerbose implementation when --trace-verbose is not enabled */ -static void prim_second(EvalState & state, const Pos & pos, Value * * args, Value & v) +static void prim_second(EvalState & state, const PosIdx pos, Value * * args, Value & v) { state.forceValue(*args[1], pos); v = *args[1]; @@ -3938,7 +3938,7 @@ void EvalState::createBaseEnv() addPrimOp({ .fun = evalSettings.traceVerbose ? prim_trace : prim_second, .arity = 2, - .name = symbols.create("__traceVerbose"), + .name = "__traceVerbose", .args = { "e1", "e2" }, .doc = R"( Evaluate *e1* and print its abstract syntax representation on standard -- cgit v1.2.3 From 69ea265fd26e6b503bb52566ce6f5f12e0a75661 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 11 Jul 2022 10:21:12 -0600 Subject: 'tryEval' not 'try clause' --- src/libexpr/eval.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libexpr') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 28256ec5c..956c4b474 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -838,7 +838,7 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & printError("%s\n\n", error->what()); if (trylevel > 0 && error->info().level != lvlInfo) - printError("This exception occurred in a try clause. use " ANSI_GREEN "--ignore-try" ANSI_NORMAL " to skip these.\n"); + printError("This exception occurred in a 'tryEval' call. Use " ANSI_GREEN "--ignore-try" ANSI_NORMAL " to skip these.\n"); printError(ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL); } -- cgit v1.2.3 From 6ac8200ff5d21d7c4464b4b3a2d3716fa4b942fd Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 11 Jul 2022 10:21:40 -0600 Subject: use util.hh class instead of local --- src/libexpr/primops.cc | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'src/libexpr') diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index ecc1c136a..3a07e43a7 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -846,15 +846,6 @@ static RegisterPrimOp primop_floor({ .fun = prim_floor, }); -class Counter -{ - private: - int &counter; - public: - Counter(int &counter) :counter(counter) { counter++; } - ~Counter() { counter--; } -}; - /* Try evaluating the argument. Success => {success=true; value=something;}, * else => {success=false; value=false;} */ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v) @@ -862,7 +853,7 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va auto attrs = state.buildBindings(2); /* increment state.trylevel, and decrement it when this function returns. */ - Counter trylevel(state.trylevel); + MaintainCount trylevel(state.trylevel); void (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; if (state.debugRepl && state.ignoreTry) -- cgit v1.2.3 From a3629ab0ccd40a4492ac99424d84b3649df8b057 Mon Sep 17 00:00:00 2001 From: Ben Burdette Date: Mon, 11 Jul 2022 10:47:09 -0600 Subject: move ignore-try to EvalSettings --- src/libexpr/eval.cc | 1 - src/libexpr/eval.hh | 8 +++++++- src/libexpr/primops.cc | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'src/libexpr') diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 956c4b474..f485e2fed 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -467,7 +467,6 @@ EvalState::EvalState( , debugRepl(nullptr) , debugStop(false) , debugQuit(false) - , ignoreTry(false) , trylevel(0) , regexCache(makeRegexCache()) #if HAVE_BOEHMGC diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 9aff77042..b8903c06c 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -130,7 +130,6 @@ public: void (* debugRepl)(ref es, const ValMap & extraEnv); bool debugStop; bool debugQuit; - bool ignoreTry; int trylevel; std::list debugTraces; std::map> exprEnvs; @@ -648,6 +647,13 @@ struct EvalSettings : Config Setting useEvalCache{this, true, "eval-cache", "Whether to use the flake evaluation cache."}; + + Setting ignoreExceptionsDuringTry{this, false, "ignore-try", + R"( + If set to true, ignore exceptions inside 'tryEval' calls when evaluating nix expressions in + debug mode (using the --debugger flag). By default the debugger will pause on all exceptions. + )"}; + }; extern EvalSettings evalSettings; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 3a07e43a7..2201ca0c4 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -856,7 +856,7 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va MaintainCount trylevel(state.trylevel); void (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; - if (state.debugRepl && state.ignoreTry) + if (state.debugRepl && evalSettings.ignoreExceptionsDuringTry) { /* to prevent starting the repl from exceptions withing a tryEval, null it. */ savedDebugRepl = state.debugRepl; -- cgit v1.2.3 From c1c37f32002e2e2ad167bcac2e5d76a3a3ad6a35 Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Mon, 13 Jun 2022 20:39:09 +0200 Subject: flakes: throw an error if `follows`-declaration for an input is invalid I recently got fairly confused why the following expression didn't have any effect { description = "Foobar"; inputs.sops-nix = { url = github:mic92/sops-nix; inputs.nixpkgs_22_05.follows = "nixpkgs"; }; } until I found out that the input was called `nixpkgs-22_05` (please note the dash vs. underscore). IMHO it's not a good idea to not throw an error in that case and probably leave end-users rather confused, so I implemented a small check for that which basically checks whether `follows`-declaration from overrides actually have corresponding inputs in the transitive flake. In fact this was done by accident already in our own test-suite where the removal of a `follows` was apparently forgotten[1]. Since the key of the `std::map` that holds the `overrides` is a vector and we have to find the last element of each vector (i.e. the override) this has to be done with a for loop in O(n) complexity with `n` being the total amount of overrides (which shouldn't be that large though). Please note that this doesn't work with nested expressions, i.e. inputs.fenix.inputs.nixpkgs.follows = "..."; which is a known problem[2]. For the expression demonstrated above, an error like this will be thrown: error: sops-nix has a `follows'-declaration for a non-existant input nixpkgs_22_05! [1] 2664a216e57169ec57d7f51be1b8383c1be83fd5 [2] https://github.com/NixOS/nix/issues/5790 --- src/libexpr/flake/flake.cc | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'src/libexpr') diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 920726b73..b97780a9c 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -373,6 +373,29 @@ LockedFlake lockFlake( { debug("computing lock file node '%s'", printInputPath(inputPathPrefix)); + auto overrides2 = overrides; + for (auto & [inputPath, inputOverride] : overrides2) { + auto inputPath2(inputPath); + auto follow = inputPath2.back(); + inputPath2.pop_back(); + if (inputPath2 == inputPathPrefix + && flakeInputs.find(follow) == flakeInputs.end() + ) { + std::string root; + for (auto & element : inputPath2) { + root.append(element); + if (element != inputPath2.back()) { + root.append(".inputs."); + } + } + throw Error( + "%s has a `follows'-declaration for a non-existant input %s!", + root, + follow + ); + } + } + /* Get the overrides (i.e. attributes of the form 'inputs.nixops.inputs.nixpkgs.url = ...'). */ for (auto & [id, input] : flakeInputs) { -- cgit v1.2.3 From 411111a3bc0e47520797106e1697aaa11631a101 Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Tue, 12 Jul 2022 11:22:35 +0200 Subject: Turn error for non-existant follows into a warning --- src/libexpr/flake/flake.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/libexpr') diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index b97780a9c..c59a42d56 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -373,8 +373,7 @@ LockedFlake lockFlake( { debug("computing lock file node '%s'", printInputPath(inputPathPrefix)); - auto overrides2 = overrides; - for (auto & [inputPath, inputOverride] : overrides2) { + for (auto [inputPath, inputOverride] : overrides) { auto inputPath2(inputPath); auto follow = inputPath2.back(); inputPath2.pop_back(); @@ -388,7 +387,7 @@ LockedFlake lockFlake( root.append(".inputs."); } } - throw Error( + warn( "%s has a `follows'-declaration for a non-existant input %s!", root, follow -- cgit v1.2.3 From 1f771065f1353ba462d73641b047b4fb2f02f482 Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Tue, 12 Jul 2022 11:25:33 +0200 Subject: Move follows-check into its own function --- src/libexpr/flake/flake.cc | 47 +++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) (limited to 'src/libexpr') diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index c59a42d56..906e11251 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -353,26 +353,15 @@ LockedFlake lockFlake( std::vector parents; std::function node, const InputPath & inputPathPrefix, - std::shared_ptr oldNode, - const InputPath & lockRootPath, - const Path & parentPath, - bool trustLock)> - computeLocks; + const FlakeInputs & flakeInputs + )> + checkFollowsDeclarations; - computeLocks = [&]( - const FlakeInputs & flakeInputs, - std::shared_ptr node, + checkFollowsDeclarations = [&]( const InputPath & inputPathPrefix, - std::shared_ptr oldNode, - const InputPath & lockRootPath, - const Path & parentPath, - bool trustLock) - { - debug("computing lock file node '%s'", printInputPath(inputPathPrefix)); - + const FlakeInputs & flakeInputs + ) { for (auto [inputPath, inputOverride] : overrides) { auto inputPath2(inputPath); auto follow = inputPath2.back(); @@ -394,6 +383,30 @@ LockedFlake lockFlake( ); } } + }; + + std::function node, + const InputPath & inputPathPrefix, + std::shared_ptr oldNode, + const InputPath & lockRootPath, + const Path & parentPath, + bool trustLock)> + computeLocks; + + computeLocks = [&]( + const FlakeInputs & flakeInputs, + std::shared_ptr node, + const InputPath & inputPathPrefix, + std::shared_ptr oldNode, + const InputPath & lockRootPath, + const Path & parentPath, + bool trustLock) + { + debug("computing lock file node '%s'", printInputPath(inputPathPrefix)); + + checkFollowsDeclarations(inputPathPrefix, flakeInputs); /* Get the overrides (i.e. attributes of the form 'inputs.nixops.inputs.nixpkgs.url = ...'). */ -- cgit v1.2.3 From f6a434c8a4d76973a26e8cbd938be2beb29696de Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 12 Jul 2022 11:53:24 +0200 Subject: Fix debug message --- src/libexpr/eval-cache.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libexpr') diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index dbfd8e70b..0d83b6cfe 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -486,7 +486,7 @@ std::shared_ptr AttrCursor::maybeGetAttr(Symbol name, bool forceErro return nullptr; else if (std::get_if(&attr->second)) { if (forceErrors) - debug("reevaluating failed cached attribute '%s'"); + debug("reevaluating failed cached attribute '%s'", getAttrPathStr(name)); else throw CachedEvalError("cached failure of attribute '%s'", getAttrPathStr(name)); } else -- cgit v1.2.3 From 694a9dc282dd9f07e9f8f1bc7362bef50588389c Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Wed, 13 Jul 2022 01:10:32 +0900 Subject: Fix typo in flake.cc non-existant -> non-existent --- src/libexpr/flake/flake.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libexpr') diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 906e11251..233e52407 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -377,7 +377,7 @@ LockedFlake lockFlake( } } warn( - "%s has a `follows'-declaration for a non-existant input %s!", + "%s has a `follows'-declaration for a non-existent input %s!", root, follow ); -- cgit v1.2.3 From 12df8885cc70499cc8fa2bfe73992c6d37ec332e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 13 Jul 2022 13:39:06 +0200 Subject: Simplify the check for overrides on non-existent inputs --- src/libexpr/flake/flake.cc | 47 ++++++++++++---------------------------------- 1 file changed, 12 insertions(+), 35 deletions(-) (limited to 'src/libexpr') diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 233e52407..cc9be1336 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -352,39 +352,6 @@ LockedFlake lockFlake( std::vector parents; - std::function - checkFollowsDeclarations; - - checkFollowsDeclarations = [&]( - const InputPath & inputPathPrefix, - const FlakeInputs & flakeInputs - ) { - for (auto [inputPath, inputOverride] : overrides) { - auto inputPath2(inputPath); - auto follow = inputPath2.back(); - inputPath2.pop_back(); - if (inputPath2 == inputPathPrefix - && flakeInputs.find(follow) == flakeInputs.end() - ) { - std::string root; - for (auto & element : inputPath2) { - root.append(element); - if (element != inputPath2.back()) { - root.append(".inputs."); - } - } - warn( - "%s has a `follows'-declaration for a non-existent input %s!", - root, - follow - ); - } - } - }; - std::function node, @@ -406,8 +373,6 @@ LockedFlake lockFlake( { debug("computing lock file node '%s'", printInputPath(inputPathPrefix)); - checkFollowsDeclarations(inputPathPrefix, flakeInputs); - /* Get the overrides (i.e. attributes of the form 'inputs.nixops.inputs.nixpkgs.url = ...'). */ for (auto & [id, input] : flakeInputs) { @@ -419,6 +384,18 @@ LockedFlake lockFlake( } } + /* Check whether this input has overrides for a + non-existent input. */ + for (auto [inputPath, inputOverride] : overrides) { + auto inputPath2(inputPath); + auto follow = inputPath2.back(); + inputPath2.pop_back(); + if (inputPath2 == inputPathPrefix && !flakeInputs.count(follow)) + warn( + "input '%s' has an override for a non-existent input '%s'", + printInputPath(inputPathPrefix), follow); + } + /* Go over the flake inputs, resolve/fetch them if necessary (i.e. if they're new or the flakeref changed from what's in the lock file). */ -- cgit v1.2.3