From df546884d71f46ff5947ded9e27b9954d68ca1dc Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 14 Jun 2024 12:41:09 -0400 Subject: [PATCH] No global eval settings in `libnixexpr` Progress on #5638 There is still a global eval settings, but it pushed down into `libnixcmd`, which is a lot less bad a place for this sort of thing. --- .editorconfig | 8 +++--- src/libcmd/command.cc | 8 +++--- src/libcmd/common-eval-args.cc | 8 +++++- src/libcmd/common-eval-args.hh | 6 +++++ src/libcmd/installables.cc | 6 ++--- src/libcmd/repl.cc | 6 ++--- src/libexpr-c/nix_api_expr.cc | 16 +++++++++++- src/libexpr-c/nix_api_expr_internal.h | 3 +++ src/libexpr/eval-settings.cc | 13 ++++----- src/libexpr/eval-settings.hh | 10 +++---- src/libexpr/eval.cc | 29 +++++++++++---------- src/libexpr/eval.hh | 4 ++- src/libexpr/flake/config.cc | 1 - src/libexpr/flake/flake.cc | 6 ++--- src/libexpr/parser-state.hh | 1 + src/libexpr/parser.y | 6 +++-- src/libexpr/primops.cc | 25 +++++++++--------- src/libexpr/primops/fetchMercurial.cc | 2 +- src/libexpr/primops/fetchTree.cc | 8 +++--- src/nix-build/nix-build.cc | 2 +- src/nix-env/nix-env.cc | 2 +- src/nix-instantiate/nix-instantiate.cc | 2 +- src/nix/flake.cc | 6 ++--- src/nix/main.cc | 16 ++++++------ src/nix/prefetch.cc | 2 +- src/nix/repl.cc | 2 +- src/nix/search.cc | 2 +- src/nix/upgrade-nix.cc | 4 +-- tests/unit/libexpr-support/tests/libexpr.hh | 6 +++-- 29 files changed, 120 insertions(+), 90 deletions(-) diff --git a/.editorconfig b/.editorconfig index 86360e6582d..e1c8bae3929 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,20 +4,20 @@ # Top-most EditorConfig file root = true -# Unix-style newlines with a newline ending every file, utf-8 charset +# Unix-style newlines with a newline ending every file, UTF-8 charset [*] end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true charset = utf-8 -# Match nix files, set indent to spaces with width of two +# Match Nix files, set indent to spaces with width of two [*.nix] indent_style = space indent_size = 2 -# Match c++/shell/perl, set indent to spaces with width of four -[*.{hpp,cc,hh,sh,pl,xs}] +# Match C++/C/shell/Perl, set indent to spaces with width of four +[*.{hpp,cc,hh,c,h,sh,pl,xs}] indent_style = space indent_size = 4 diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 543250da3ac..509fb4d0c9b 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -126,13 +126,11 @@ ref EvalCommand::getEvalState() { if (!evalState) { evalState = + std::allocate_shared( #if HAVE_BOEHMGC - std::allocate_shared(traceable_allocator(), - lookupPath, getEvalStore(), getStore()) - #else - std::make_shared( - lookupPath, getEvalStore(), getStore()) + traceable_allocator(), #endif + lookupPath, getEvalStore(), globalEvalSettings, getStore()) ; evalState->repair = repair; diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc index cd0f192577f..b8e39c8cd5d 100644 --- a/src/libcmd/common-eval-args.cc +++ b/src/libcmd/common-eval-args.cc @@ -13,6 +13,12 @@ namespace nix { +EvalSettings globalEvalSettings { + settings.readOnlyMode +}; + +static GlobalConfig::Register rEvalSettings(&globalEvalSettings); + MixEvalArgs::MixEvalArgs() { addFlag({ @@ -134,7 +140,7 @@ MixEvalArgs::MixEvalArgs() .description = "Allow access to mutable paths and repositories.", .category = category, .handler = {[&]() { - evalSettings.pureEval = false; + globalEvalSettings.pureEval = false; }}, }); diff --git a/src/libcmd/common-eval-args.hh b/src/libcmd/common-eval-args.hh index 75cb19334fe..3a94246f027 100644 --- a/src/libcmd/common-eval-args.hh +++ b/src/libcmd/common-eval-args.hh @@ -12,9 +12,15 @@ namespace nix { class Store; class EvalState; +struct EvalSettings; class Bindings; struct SourcePath; +/** + * @todo Get rid of global setttings variables + */ +extern EvalSettings globalEvalSettings; + struct MixEvalArgs : virtual Args, virtual MixRepair { static constexpr auto category = "Common evaluation options"; diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 6835c512c1c..f3ce79518a5 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -258,7 +258,7 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s if (file) { completions.setType(AddCompletions::Type::Attrs); - evalSettings.pureEval = false; + globalEvalSettings.pureEval = false; auto state = getEvalState(); auto e = state->parseExprFromFile( @@ -442,7 +442,7 @@ ref openEvalCache( EvalState & state, std::shared_ptr lockedFlake) { - auto fingerprint = evalSettings.useEvalCache && evalSettings.pureEval + auto fingerprint = globalEvalSettings.useEvalCache && globalEvalSettings.pureEval ? lockedFlake->getFingerprint(state.store) : std::nullopt; auto rootLoader = [&state, lockedFlake]() @@ -484,7 +484,7 @@ Installables SourceExprCommand::parseInstallables( throw UsageError("'--file' and '--expr' are exclusive"); // FIXME: backward compatibility hack - if (file) evalSettings.pureEval = false; + if (file) globalEvalSettings.pureEval = false; auto state = getEvalState(); auto vFile = state->allocValue(); diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 1e80d14e1d3..0fa46aaef7d 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -690,7 +690,7 @@ void NixRepl::loadFlake(const std::string & flakeRefS) throw Error("cannot use ':load-flake' without a path specified. (Use '.' for the current working directory.)"); auto flakeRef = parseFlakeRef(flakeRefS, absPath("."), true); - if (evalSettings.pureEval && !flakeRef.input.isLocked()) + if (globalEvalSettings.pureEval && !flakeRef.input.isLocked()) throw Error("cannot use ':load-flake' on locked flake reference '%s' (use --impure to override)", flakeRefS); Value v; @@ -699,8 +699,8 @@ void NixRepl::loadFlake(const std::string & flakeRefS) flake::lockFlake(*state, flakeRef, flake::LockFlags { .updateLockFile = false, - .useRegistries = !evalSettings.pureEval, - .allowUnlocked = !evalSettings.pureEval, + .useRegistries = !globalEvalSettings.pureEval, + .allowUnlocked = !globalEvalSettings.pureEval, }), v); addAttrsToScope(v); diff --git a/src/libexpr-c/nix_api_expr.cc b/src/libexpr-c/nix_api_expr.cc index b86d745db28..197e3ffd42d 100644 --- a/src/libexpr-c/nix_api_expr.cc +++ b/src/libexpr-c/nix_api_expr.cc @@ -7,6 +7,7 @@ #include "eval.hh" #include "globals.hh" #include "util.hh" +#include "eval-settings.hh" #include "nix_api_expr.h" #include "nix_api_expr_internal.h" @@ -106,7 +107,20 @@ EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath_c for (size_t i = 0; lookupPath_c[i] != nullptr; i++) lookupPath.push_back(lookupPath_c[i]); - return new EvalState{nix::EvalState(nix::LookupPath::parse(lookupPath), store->ptr)}; + void * p = ::operator new( + sizeof(EvalState), + static_cast(alignof(EvalState))); + auto * p2 = static_cast(p); + return new (p) EvalState { + .readOnlyMode = false, + .settings = nix::EvalSettings{ + p2->readOnlyMode, + }, + .state = nix::EvalState( + nix::LookupPath::parse(lookupPath), + store->ptr, + p2->settings), + }; } NIXC_CATCH_ERRS_NULL } diff --git a/src/libexpr-c/nix_api_expr_internal.h b/src/libexpr-c/nix_api_expr_internal.h index 7743849fdb8..b2f08363239 100644 --- a/src/libexpr-c/nix_api_expr_internal.h +++ b/src/libexpr-c/nix_api_expr_internal.h @@ -2,11 +2,14 @@ #define NIX_API_EXPR_INTERNAL_H #include "eval.hh" +#include "eval-settings.hh" #include "attr-set.hh" #include "nix_api_value.h" struct EvalState { + bool readOnlyMode; + nix::EvalSettings settings; nix::EvalState state; }; diff --git a/src/libexpr/eval-settings.cc b/src/libexpr/eval-settings.cc index 85b1677ea17..41011410977 100644 --- a/src/libexpr/eval-settings.cc +++ b/src/libexpr/eval-settings.cc @@ -44,7 +44,8 @@ static Strings parseNixPath(const std::string & s) return res; } -EvalSettings::EvalSettings() +EvalSettings::EvalSettings(bool & readOnlyMode) + : readOnlyMode{readOnlyMode} { auto var = getEnv("NIX_PATH"); if (var) nixPath = parseNixPath(*var); @@ -54,7 +55,7 @@ EvalSettings::EvalSettings() builtinsAbortOnWarn = true; } -Strings EvalSettings::getDefaultNixPath() +Strings EvalSettings::getDefaultNixPath() const { Strings res; auto add = [&](const Path & p, const std::string & s = std::string()) { @@ -67,7 +68,7 @@ Strings EvalSettings::getDefaultNixPath() } }; - if (!evalSettings.restrictEval && !evalSettings.pureEval) { + if (!restrictEval && !pureEval) { add(getNixDefExpr() + "/channels"); add(rootChannelsDir() + "/nixpkgs", "nixpkgs"); add(rootChannelsDir()); @@ -93,16 +94,12 @@ std::string EvalSettings::resolvePseudoUrl(std::string_view url) return std::string(url); } -const std::string & EvalSettings::getCurrentSystem() +const std::string & EvalSettings::getCurrentSystem() const { const auto & evalSystem = currentSystem.get(); return evalSystem != "" ? evalSystem : settings.thisSystem.get(); } -EvalSettings evalSettings; - -static GlobalConfig::Register rEvalSettings(&evalSettings); - Path getNixDefExpr() { return settings.useXDGBaseDirectories diff --git a/src/libexpr/eval-settings.hh b/src/libexpr/eval-settings.hh index d01de980fa4..2689a846569 100644 --- a/src/libexpr/eval-settings.hh +++ b/src/libexpr/eval-settings.hh @@ -7,9 +7,11 @@ namespace nix { struct EvalSettings : Config { - EvalSettings(); + EvalSettings(bool & readOnlyMode); - static Strings getDefaultNixPath(); + bool & readOnlyMode; + + Strings getDefaultNixPath() const; static bool isPseudoUrl(std::string_view s); @@ -74,7 +76,7 @@ struct EvalSettings : Config * Implements the `eval-system` vs `system` defaulting logic * described for `eval-system`. */ - const std::string & getCurrentSystem(); + const std::string & getCurrentSystem() const; Setting restrictEval{ this, false, "restrict-eval", @@ -193,8 +195,6 @@ struct EvalSettings : Config )"}; }; -extern EvalSettings evalSettings; - /** * Conventionally part of the default nix path in impure mode. */ diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 301b81a6262..7f62c8b2157 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -9,7 +9,6 @@ #include "store-api.hh" #include "derivations.hh" #include "downstream-placeholder.hh" -#include "globals.hh" #include "eval-inline.hh" #include "filetransfer.hh" #include "function-trace.hh" @@ -219,8 +218,10 @@ static constexpr size_t BASE_ENV_SIZE = 128; EvalState::EvalState( const LookupPath & _lookupPath, ref store, + const EvalSettings & settings, std::shared_ptr buildStore) - : sWith(symbols.create("")) + : settings{settings} + , sWith(symbols.create("")) , sOutPath(symbols.create("outPath")) , sDrvPath(symbols.create("drvPath")) , sType(symbols.create("type")) @@ -270,10 +271,10 @@ EvalState::EvalState( , repair(NoRepair) , emptyBindings(0) , rootFS( - evalSettings.restrictEval || evalSettings.pureEval + settings.restrictEval || settings.pureEval ? ref(AllowListSourceAccessor::create(getFSSourceAccessor(), {}, - [](const CanonPath & path) -> RestrictedPathError { - auto modeInformation = evalSettings.pureEval + [&settings](const CanonPath & path) -> RestrictedPathError { + auto modeInformation = settings.pureEval ? "in pure evaluation mode (use '--impure' to override)" : "in restricted mode"; throw RestrictedPathError("access to absolute path '%1%' is forbidden %2%", path, modeInformation); @@ -324,10 +325,10 @@ EvalState::EvalState( vStringUnknown.mkString("unknown"); /* Initialise the Nix expression search path. */ - if (!evalSettings.pureEval) { + if (!settings.pureEval) { for (auto & i : _lookupPath.elements) lookupPath.elements.emplace_back(LookupPath::Elem {i}); - for (auto & i : evalSettings.nixPath.get()) + for (auto & i : settings.nixPath.get()) lookupPath.elements.emplace_back(LookupPath::Elem::parse(i)); } @@ -405,9 +406,9 @@ bool isAllowedURI(std::string_view uri, const Strings & allowedUris) void EvalState::checkURI(const std::string & uri) { - if (!evalSettings.restrictEval) return; + if (!settings.restrictEval) return; - if (isAllowedURI(uri, evalSettings.allowedUris.get())) return; + if (isAllowedURI(uri, settings.allowedUris.get())) return; /* If the URI is a path, then check it against allowedPaths as well. */ @@ -452,7 +453,7 @@ void EvalState::addConstant(const std::string & name, Value * v, Constant info) constantInfos.push_back({name2, info}); - if (!(evalSettings.pureEval && info.impureOnly)) { + if (!(settings.pureEval && info.impureOnly)) { /* Check the type, if possible. We might know the type of a thunk in advance, so be allowed @@ -1407,11 +1408,11 @@ class CallDepth { void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vRes, const PosIdx pos) { - if (callDepth > evalSettings.maxCallDepth) + if (callDepth > settings.maxCallDepth) error("stack overflow; max-call-depth exceeded").atPos(pos).debugThrow(); CallDepth _level(callDepth); - auto trace = evalSettings.traceFunctionCalls + auto trace = settings.traceFunctionCalls ? std::make_unique(positions[pos]) : nullptr; @@ -2739,7 +2740,7 @@ SourcePath EvalState::findFile(const LookupPath & lookupPath, const std::string_ return {corepkgsFS, CanonPath(path.substr(3))}; error( - evalSettings.pureEval + settings.pureEval ? "cannot look up '<%s>' in pure evaluation mode (use '--impure' to override)" : "file '%s' was not found in the Nix search path (add it using $NIX_PATH or -I)", path @@ -2819,7 +2820,7 @@ Expr * EvalState::parse( const SourcePath & basePath, std::shared_ptr & staticEnv) { - auto result = parseExprFromBuf(text, length, origin, basePath, symbols, positions, rootFS, exprSymbols); + auto result = parseExprFromBuf(text, length, origin, basePath, symbols, settings, positions, rootFS, exprSymbols); result->bindVars(*this, staticEnv); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 0e5e0433e90..49ce55bd1d2 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -30,6 +30,7 @@ namespace nix { constexpr size_t maxPrimOpArity = 8; class Store; +struct EvalSettings; class EvalState; class StorePath; struct SingleDerivedPath; @@ -39,7 +40,6 @@ namespace eval_cache { class EvalCache; } - /** * Function that implements a primop. */ @@ -162,6 +162,7 @@ struct DebugTrace { class EvalState : public std::enable_shared_from_this { public: + const EvalSettings & settings; SymbolTable symbols; PosTable positions; @@ -349,6 +350,7 @@ public: EvalState( const LookupPath & _lookupPath, ref store, + const EvalSettings & settings, std::shared_ptr buildStore = nullptr); ~EvalState(); diff --git a/src/libexpr/flake/config.cc b/src/libexpr/flake/config.cc index e0c5d45121d..e20f1b6877e 100644 --- a/src/libexpr/flake/config.cc +++ b/src/libexpr/flake/config.cc @@ -1,5 +1,4 @@ #include "users.hh" -#include "globals.hh" #include "fetch-settings.hh" #include "flake.hh" diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 3af9ef14ee3..67b19bd57ef 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -803,7 +803,7 @@ static void prim_getFlake(EvalState & state, const PosIdx pos, Value * * args, V { std::string flakeRefS(state.forceStringNoCtx(*args[0], pos, "while evaluating the argument passed to builtins.getFlake")); auto flakeRef = parseFlakeRef(flakeRefS, {}, true); - if (evalSettings.pureEval && !flakeRef.input.isLocked()) + if (state.settings.pureEval && !flakeRef.input.isLocked()) throw Error("cannot call 'getFlake' on unlocked flake reference '%s', at %s (use --impure to override)", flakeRefS, state.positions[pos]); callFlake(state, @@ -811,8 +811,8 @@ static void prim_getFlake(EvalState & state, const PosIdx pos, Value * * args, V LockFlags { .updateLockFile = false, .writeLockFile = false, - .useRegistries = !evalSettings.pureEval && fetchSettings.useRegistries, - .allowUnlocked = !evalSettings.pureEval, + .useRegistries = !state.settings.pureEval && fetchSettings.useRegistries, + .allowUnlocked = !state.settings.pureEval, }), v); } diff --git a/src/libexpr/parser-state.hh b/src/libexpr/parser-state.hh index 5a928e9aadb..cff6282faa0 100644 --- a/src/libexpr/parser-state.hh +++ b/src/libexpr/parser-state.hh @@ -46,6 +46,7 @@ struct ParserState PosTable::Origin origin; const ref rootFS; const Expr::AstSymbols & s; + const EvalSettings & settings; void dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos); void dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos); diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index 00300449f6f..709a4532a85 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -25,7 +25,6 @@ #include "nixexpr.hh" #include "eval.hh" #include "eval-settings.hh" -#include "globals.hh" #include "parser-state.hh" #define YYLTYPE ::nix::ParserLocation @@ -40,6 +39,7 @@ Expr * parseExprFromBuf( Pos::Origin origin, const SourcePath & basePath, SymbolTable & symbols, + const EvalSettings & settings, PosTable & positions, const ref rootFS, const Expr::AstSymbols & astSymbols); @@ -294,7 +294,7 @@ path_start $$ = new ExprPath(ref(state->rootFS), std::move(path)); } | HPATH { - if (evalSettings.pureEval) { + if (state->settings.pureEval) { throw Error( "the path '%s' can not be resolved in pure mode", std::string_view($1.p, $1.l) @@ -429,6 +429,7 @@ Expr * parseExprFromBuf( Pos::Origin origin, const SourcePath & basePath, SymbolTable & symbols, + const EvalSettings & settings, PosTable & positions, const ref rootFS, const Expr::AstSymbols & astSymbols) @@ -441,6 +442,7 @@ Expr * parseExprFromBuf( .origin = positions.addOrigin(origin, length), .rootFS = rootFS, .s = astSymbols, + .settings = settings, }; yylex_init(&scanner); diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 9177b0a2f3e..5b9acae6478 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -5,7 +5,6 @@ #include "eval.hh" #include "eval-settings.hh" #include "gc-small-vector.hh" -#include "globals.hh" #include "json-to-value.hh" #include "names.hh" #include "path-references.hh" @@ -78,7 +77,7 @@ StringMap EvalState::realiseContext(const NixStringContext & context, StorePathS if (drvs.empty()) return {}; - if (isIFD && !evalSettings.enableImportFromDerivation) + if (isIFD && !settings.enableImportFromDerivation) error( "cannot build '%1%' during evaluation because the option 'allow-import-from-derivation' is disabled", drvs.begin()->to_string(*store) @@ -901,7 +900,7 @@ static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Va MaintainCount trylevel(state.trylevel); ReplExitStatus (* savedDebugRepl)(ref es, const ValMap & extraEnv) = nullptr; - if (state.debugRepl && evalSettings.ignoreExceptionsDuringTry) + if (state.debugRepl && state.settings.ignoreExceptionsDuringTry) { /* to prevent starting the repl from exceptions withing a tryEval, null it. */ savedDebugRepl = state.debugRepl; @@ -950,7 +949,7 @@ static RegisterPrimOp primop_tryEval({ static void prim_getEnv(EvalState & state, const PosIdx pos, Value * * args, Value & v) { std::string name(state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.getEnv")); - v.mkString(evalSettings.restrictEval || evalSettings.pureEval ? "" : getEnv(name).value_or("")); + v.mkString(state.settings.restrictEval || state.settings.pureEval ? "" : getEnv(name).value_or("")); } static RegisterPrimOp primop_getEnv({ @@ -1017,7 +1016,7 @@ static void prim_trace(EvalState & state, const PosIdx pos, Value * * args, Valu printError("trace: %1%", args[0]->string_view()); else printError("trace: %1%", ValuePrinter(state, *args[0])); - if (evalSettings.builtinsTraceDebugger) { + if (state.settings.builtinsTraceDebugger) { state.runDebugRepl(nullptr); } state.forceValue(*args[1], pos); @@ -1056,11 +1055,11 @@ static void prim_warn(EvalState & state, const PosIdx pos, Value * * args, Value logWarning(info); } - if (evalSettings.builtinsAbortOnWarn) { + if (state.settings.builtinsAbortOnWarn) { // Not an EvalError or subclass, which would cause the error to be stored in the eval cache. state.error("aborting to reveal stack trace of warning, as abort-on-warn is set").setIsFromExpr().debugThrow(); } - if (evalSettings.builtinsTraceDebugger || evalSettings.builtinsDebuggerOnWarn) { + if (state.settings.builtinsTraceDebugger || state.settings.builtinsDebuggerOnWarn) { state.runDebugRepl(nullptr); } state.forceValue(*args[1], pos); @@ -1564,7 +1563,7 @@ static RegisterPrimOp primop_toPath({ corner cases. */ static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args, Value & v) { - if (evalSettings.pureEval) + if (state.settings.pureEval) state.error( "'%s' is not allowed in pure evaluation mode", "builtins.storePath" @@ -4548,7 +4547,7 @@ void EvalState::createBaseEnv() )", }); - if (!evalSettings.pureEval) { + if (!settings.pureEval) { v.mkInt(time(0)); } addConstant("__currentTime", v, { @@ -4575,8 +4574,8 @@ void EvalState::createBaseEnv() .impureOnly = true, }); - if (!evalSettings.pureEval) - v.mkString(evalSettings.getCurrentSystem()); + if (!settings.pureEval) + v.mkString(settings.getCurrentSystem()); addConstant("__currentSystem", v, { .type = nString, .doc = R"( @@ -4656,7 +4655,7 @@ void EvalState::createBaseEnv() #ifndef _WIN32 // TODO implement on Windows // Miscellaneous - if (evalSettings.enableNativeCode) { + if (settings.enableNativeCode) { addPrimOp({ .name = "__importNative", .arity = 2, @@ -4679,7 +4678,7 @@ void EvalState::createBaseEnv() error if `--trace-verbose` is enabled. Then return *e2*. This function is useful for debugging. )", - .fun = evalSettings.traceVerbose ? prim_trace : prim_second, + .fun = settings.traceVerbose ? prim_trace : prim_second, }); /* Add a value containing the current Nix expression search path. */ diff --git a/src/libexpr/primops/fetchMercurial.cc b/src/libexpr/primops/fetchMercurial.cc index d9ba6aa97d8..7b5f4193a23 100644 --- a/src/libexpr/primops/fetchMercurial.cc +++ b/src/libexpr/primops/fetchMercurial.cc @@ -53,7 +53,7 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * a // whitelist. Ah well. state.checkURI(url); - if (evalSettings.pureEval && !rev) + if (state.settings.pureEval && !rev) throw Error("in pure evaluation mode, 'fetchMercurial' requires a Mercurial revision"); fetchers::Attrs attrs; diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index a99a715770b..7b05c5b4863 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -171,10 +171,10 @@ static void fetchTree( } } - if (!evalSettings.pureEval && !input.isDirect() && experimentalFeatureSettings.isEnabled(Xp::Flakes)) + if (!state.settings.pureEval && !input.isDirect() && experimentalFeatureSettings.isEnabled(Xp::Flakes)) input = lookupInRegistries(state.store, input).first; - if (evalSettings.pureEval && !input.isLocked()) { + if (state.settings.pureEval && !input.isLocked()) { auto fetcher = "fetchTree"; if (params.isFetchGit) fetcher = "fetchGit"; @@ -453,14 +453,14 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v url = state.forceStringNoCtx(*args[0], pos, "while evaluating the url we should fetch"); if (who == "fetchTarball") - url = evalSettings.resolvePseudoUrl(*url); + url = state.settings.resolvePseudoUrl(*url); state.checkURI(*url); if (name == "") name = baseNameOf(*url); - if (evalSettings.pureEval && !expectedHash) + if (state.settings.pureEval && !expectedHash) state.error("in pure evaluation mode, '%s' requires a 'sha256' argument", who).atPos(pos).debugThrow(); // early exit if pinned and already in the store diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc index 77df08edd14..f68ac21eada 100644 --- a/src/nix-build/nix-build.cc +++ b/src/nix-build/nix-build.cc @@ -259,7 +259,7 @@ static void main_nix_build(int argc, char * * argv) auto store = openStore(); auto evalStore = myArgs.evalStoreUrl ? openStore(*myArgs.evalStoreUrl) : store; - auto state = std::make_unique(myArgs.lookupPath, evalStore, store); + auto state = std::make_unique(myArgs.lookupPath, evalStore, globalEvalSettings, store); state->repair = myArgs.repair; if (myArgs.repair) buildMode = bmRepair; diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index b5e13cc2308..522094e8f54 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -1525,7 +1525,7 @@ static int main_nix_env(int argc, char * * argv) auto store = openStore(); - globals.state = std::shared_ptr(new EvalState(myArgs.lookupPath, store)); + globals.state = std::shared_ptr(new EvalState(myArgs.lookupPath, store, globalEvalSettings)); globals.state->repair = myArgs.repair; globals.instSource.nixExprPath = std::make_shared( diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index 35664374cea..3b4d7700f8f 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -157,7 +157,7 @@ static int main_nix_instantiate(int argc, char * * argv) auto store = openStore(); auto evalStore = myArgs.evalStoreUrl ? openStore(*myArgs.evalStoreUrl) : store; - auto state = std::make_unique(myArgs.lookupPath, evalStore, store); + auto state = std::make_unique(myArgs.lookupPath, evalStore, globalEvalSettings, store); state->repair = myArgs.repair; Bindings & autoArgs = *myArgs.getAutoArgs(*state); diff --git a/src/nix/flake.cc b/src/nix/flake.cc index fb7ea621124..718a176e1d1 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -348,7 +348,7 @@ struct CmdFlakeCheck : FlakeCommand { if (!build) { settings.readOnlyMode = true; - evalSettings.enableImportFromDerivation.setDefault(false); + globalEvalSettings.enableImportFromDerivation.setDefault(false); } auto state = getEvalState(); @@ -578,7 +578,7 @@ struct CmdFlakeCheck : FlakeCommand fmt("checking flake output '%s'", name)); try { - evalSettings.enableImportFromDerivation.setDefault(name != "hydraJobs"); + globalEvalSettings.enableImportFromDerivation.setDefault(name != "hydraJobs"); state->forceValue(vOutput, pos); @@ -1119,7 +1119,7 @@ struct CmdFlakeShow : FlakeCommand, MixJSON void run(nix::ref store) override { - evalSettings.enableImportFromDerivation.setDefault(false); + globalEvalSettings.enableImportFromDerivation.setDefault(false); auto state = getEvalState(); auto flake = std::make_shared(lockFlake()); diff --git a/src/nix/main.cc b/src/nix/main.cc index 81d368d6af2..156622c8190 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -240,9 +240,9 @@ static void showHelp(std::vector subcommand, NixArgs & toplevel) { auto mdName = subcommand.empty() ? "nix" : fmt("nix3-%s", concatStringsSep("-", subcommand)); - evalSettings.restrictEval = false; - evalSettings.pureEval = false; - EvalState state({}, openStore("dummy://")); + globalEvalSettings.restrictEval = false; + globalEvalSettings.pureEval = false; + EvalState state({}, openStore("dummy://"), globalEvalSettings); auto vGenerateManpage = state.allocValue(); state.eval(state.parseExprFromString( @@ -391,7 +391,7 @@ void mainWrapped(int argc, char * * argv) if (legacy) return legacy(argc, argv); } - evalSettings.pureEval = true; + globalEvalSettings.pureEval = true; setLogFormat("bar"); settings.verboseBuild = false; @@ -417,8 +417,8 @@ void mainWrapped(int argc, char * * argv) Xp::DynamicDerivations, Xp::FetchTree, }; - evalSettings.pureEval = false; - EvalState state({}, openStore("dummy://")); + globalEvalSettings.pureEval = false; + EvalState state({}, openStore("dummy://"), globalEvalSettings); auto res = nlohmann::json::object(); res["builtins"] = ({ auto builtinsJson = nlohmann::json::object(); @@ -530,8 +530,8 @@ void mainWrapped(int argc, char * * argv) settings.ttlPositiveNarInfoCache = 0; } - if (args.command->second->forceImpureByDefault() && !evalSettings.pureEval.overridden) { - evalSettings.pureEval = false; + if (args.command->second->forceImpureByDefault() && !globalEvalSettings.pureEval.overridden) { + globalEvalSettings.pureEval = false; } try { diff --git a/src/nix/prefetch.cc b/src/nix/prefetch.cc index 3ce52acc563..d981eb88f1c 100644 --- a/src/nix/prefetch.cc +++ b/src/nix/prefetch.cc @@ -193,7 +193,7 @@ static int main_nix_prefetch_url(int argc, char * * argv) startProgressBar(); auto store = openStore(); - auto state = std::make_unique(myArgs.lookupPath, store); + auto state = std::make_unique(myArgs.lookupPath, store, globalEvalSettings); Bindings & autoArgs = *myArgs.getAutoArgs(*state); diff --git a/src/nix/repl.cc b/src/nix/repl.cc index a2f3e033e72..d36f561df10 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -10,7 +10,7 @@ namespace nix { struct CmdRepl : RawInstallablesCommand { CmdRepl() { - evalSettings.pureEval = false; + globalEvalSettings.pureEval = false; } /** diff --git a/src/nix/search.cc b/src/nix/search.cc index 97ef1375ed2..5a50ec399c7 100644 --- a/src/nix/search.cc +++ b/src/nix/search.cc @@ -65,7 +65,7 @@ struct CmdSearch : InstallableValueCommand, MixJSON void run(ref store, ref installable) override { settings.readOnlyMode = true; - evalSettings.enableImportFromDerivation.setDefault(false); + globalEvalSettings.enableImportFromDerivation.setDefault(false); // Recommend "^" here instead of ".*" due to differences in resulting highlighting if (res.empty()) diff --git a/src/nix/upgrade-nix.cc b/src/nix/upgrade-nix.cc index 17d1edb97e3..f2cf74f24ac 100644 --- a/src/nix/upgrade-nix.cc +++ b/src/nix/upgrade-nix.cc @@ -57,7 +57,7 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand void run(ref store) override { - evalSettings.pureEval = true; + globalEvalSettings.pureEval = true; if (profileDir == "") profileDir = getProfileDir(store); @@ -147,7 +147,7 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand auto req = FileTransferRequest((std::string&) settings.upgradeNixStorePathUrl); auto res = getFileTransfer()->download(req); - auto state = std::make_unique(LookupPath{}, store); + auto state = std::make_unique(LookupPath{}, store, globalEvalSettings); auto v = state->allocValue(); state->eval(state->parseExprFromString(res.data, state->rootPath(CanonPath("/no-such-path"))), *v); Bindings & bindings(*state->allocBindings(0)); diff --git a/tests/unit/libexpr-support/tests/libexpr.hh b/tests/unit/libexpr-support/tests/libexpr.hh index 1a431399082..eacbf0d5cac 100644 --- a/tests/unit/libexpr-support/tests/libexpr.hh +++ b/tests/unit/libexpr-support/tests/libexpr.hh @@ -19,14 +19,14 @@ namespace nix { static void SetUpTestSuite() { LibStoreTest::SetUpTestSuite(); initGC(); - evalSettings.nixPath = {}; } protected: LibExprTest() : LibStoreTest() - , state({}, store) + , state({}, store, evalSettings, nullptr) { + evalSettings.nixPath = {}; } Value eval(std::string input, bool forceValue = true) { Value v; @@ -42,6 +42,8 @@ namespace nix { return state.symbols.create(value); } + bool readOnlyMode = true; + EvalSettings evalSettings{readOnlyMode}; EvalState state; };