From 3aa73c21e3afc91522a6121b0d591af6925b4ba6 Mon Sep 17 00:00:00 2001 From: Rodrigo Arias Mallo Date: Mon, 13 Oct 2025 16:05:30 +0200 Subject: [PATCH] Add builtins.catchAll to catch all types of errors Allows fetching multiple Git repositories with builtin.fetchGit and catching any errors thrown by the builtin, in opposition to the builtin tryEval. --- src/libexpr/primops.cc | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 36a67a39d..3b26f9f43 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -849,6 +849,44 @@ static RegisterPrimOp primop_tryEval({ .fun = prim_tryEval, }); +/* Like tryEval but catch all errors. Success => {success=true; value=something;}, + * else => {success=false; value=false;} */ +static void prim_catchAll(EvalState & state, const PosIdx pos, Value * * args, Value & v) +{ + auto attrs = state.buildBindings(3); + try { + state.forceValue(*args[0], pos); + attrs.insert(state.sValue, args[0]); + attrs.alloc("success").mkBool(true); + attrs.alloc("msg").mkNull(); + } catch (Error & e) { + attrs.alloc(state.sValue).mkBool(false); + attrs.alloc("success").mkBool(false); + attrs.alloc("msg").mkString(e.msg()); + } + v.mkAttrs(attrs); +} + +static RegisterPrimOp primop_catchAll({ + .name = "__catchAll", + .args = {"e"}, + .doc = R"( + Try to shallowly evaluate *e*. Return a set containing the + attributes `success` (`true` if *e* evaluated successfully, + `false` if an error was thrown) and `value`, equalling *e* if + successful and `false` otherwise. In contrast with `tryEval`, + `catchAll` will prevent all errors from being thrown, including + for those created by `abort` and type errors generated by + builtins. Also note that this doesn't evaluate *e* deeply, so + `let e = { x = throw ""; }; in (builtins.catchAll e).success` + will be `true`. Using `builtins.deepSeq` one can get the expected + result: `let e = { x = throw ""; }; in + (builtins.catchAll (builtins.deepSeq e e)).success` will be + `false`. + )", + .fun = prim_catchAll, +}); + /* Return an environment variable. Use with care. */ static void prim_getEnv(EvalState & state, const PosIdx pos, Value * * args, Value & v) { -- 2.51.0