aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/build-remote/build-remote.cc4
-rw-r--r--src/libcmd/common-eval-args.cc2
-rw-r--r--src/libcmd/installables.cc2
-rw-r--r--src/libexpr/flake/flake.cc2
-rw-r--r--src/libexpr/parser.y4
-rw-r--r--src/libexpr/primops.cc6
-rw-r--r--src/libexpr/primops/fetchTree.cc2
-rw-r--r--src/libstore/build/derivation-goal.cc12
-rw-r--r--src/libstore/build/local-derivation-goal.cc8
-rw-r--r--src/libstore/daemon.cc4
-rw-r--r--src/libstore/derivations.cc4
-rw-r--r--src/libstore/derived-path.cc2
-rw-r--r--src/libstore/globals.cc12
-rw-r--r--src/libstore/globals.hh8
-rw-r--r--src/libstore/local-store.cc10
-rw-r--r--src/libstore/lock.cc2
-rw-r--r--src/libstore/misc.cc2
-rw-r--r--src/libstore/remote-store.cc4
-rw-r--r--src/libstore/store-api.cc8
-rw-r--r--src/libutil/config.cc26
-rw-r--r--src/libutil/config.hh40
-rw-r--r--src/nix-build/nix-build.cc2
-rw-r--r--src/nix/develop.cc2
-rw-r--r--src/nix/flake.cc2
-rw-r--r--src/nix/main.cc7
-rw-r--r--src/nix/realisation.cc2
-rw-r--r--src/nix/registry.cc2
-rw-r--r--src/nix/repl.cc2
28 files changed, 113 insertions, 70 deletions
diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc
index 63e3e3fa9..cfc4baaca 100644
--- a/src/build-remote/build-remote.cc
+++ b/src/build-remote/build-remote.cc
@@ -305,7 +305,7 @@ connected:
std::set<Realisation> missingRealisations;
StorePathSet missingPaths;
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations) && !drv.type().hasKnownOutputPaths()) {
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations) && !drv.type().hasKnownOutputPaths()) {
for (auto & outputName : wantedOutputs) {
auto thisOutputHash = outputHashes.at(outputName);
auto thisOutputId = DrvOutput{ thisOutputHash, outputName };
@@ -337,7 +337,7 @@ connected:
for (auto & realisation : missingRealisations) {
// Should hold, because if the feature isn't enabled the set
// of missing realisations should be empty
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
store->registerDrvOutput(realisation);
}
diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc
index 908127b4d..a954a8c6f 100644
--- a/src/libcmd/common-eval-args.cc
+++ b/src/libcmd/common-eval-args.cc
@@ -166,7 +166,7 @@ Path lookupFileArg(EvalState & state, std::string_view s)
}
else if (hasPrefix(s, "flake:")) {
- settings.requireExperimentalFeature(Xp::Flakes);
+ experimentalFeatureSettings.require(Xp::Flakes);
auto flakeRef = parseFlakeRef(std::string(s.substr(6)), {}, true, false);
auto storePath = flakeRef.resolve(state.store).fetchTree(state.store).first.storePath;
return state.store->toRealPath(storePath);
diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc
index 5cbf26b88..cf2096984 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -332,7 +332,7 @@ void completeFlakeRefWithFragment(
void completeFlakeRef(ref<Store> store, std::string_view prefix)
{
- if (!settings.isExperimentalFeatureEnabled(Xp::Flakes))
+ if (!experimentalFeatureSettings.isEnabled(Xp::Flakes))
return;
if (prefix == "")
diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc
index 336eb274d..81e94848a 100644
--- a/src/libexpr/flake/flake.cc
+++ b/src/libexpr/flake/flake.cc
@@ -320,7 +320,7 @@ LockedFlake lockFlake(
const FlakeRef & topRef,
const LockFlags & lockFlags)
{
- settings.requireExperimentalFeature(Xp::Flakes);
+ experimentalFeatureSettings.require(Xp::Flakes);
FlakeCache flakeCache;
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index 0f75ed9a0..97e615c37 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -469,7 +469,7 @@ expr_simple
new ExprString(std::move(path))});
}
| URI {
- static bool noURLLiterals = settings.isExperimentalFeatureEnabled(Xp::NoUrlLiterals);
+ static bool noURLLiterals = experimentalFeatureSettings.isEnabled(Xp::NoUrlLiterals);
if (noURLLiterals)
throw ParseError({
.msg = hintfmt("URL literals are disabled"),
@@ -816,7 +816,7 @@ std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathEl
}
else if (hasPrefix(elem.second, "flake:")) {
- settings.requireExperimentalFeature(Xp::Flakes);
+ experimentalFeatureSettings.require(Xp::Flakes);
auto flakeRef = parseFlakeRef(elem.second.substr(6), {}, true, false);
debug("fetching flake search path element '%s''", elem.second);
auto storePath = flakeRef.resolve(store).fetchTree(store).first.storePath;
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index fb7fc3ddb..3641ee468 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -1141,13 +1141,13 @@ drvName, Bindings * attrs, Value & v)
if (i->name == state.sContentAddressed) {
contentAddressed = state.forceBool(*i->value, noPos, context_below);
if (contentAddressed)
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
}
else if (i->name == state.sImpure) {
isImpure = state.forceBool(*i->value, noPos, context_below);
if (isImpure)
- settings.requireExperimentalFeature(Xp::ImpureDerivations);
+ experimentalFeatureSettings.require(Xp::ImpureDerivations);
}
/* The `args' attribute is special: it supplies the
@@ -4114,7 +4114,7 @@ void EvalState::createBaseEnv()
if (RegisterPrimOp::primOps)
for (auto & primOp : *RegisterPrimOp::primOps)
if (!primOp.experimentalFeature
- || settings.isExperimentalFeatureEnabled(*primOp.experimentalFeature))
+ || experimentalFeatureSettings.isEnabled(*primOp.experimentalFeature))
{
addPrimOp({
.fun = primOp.fun,
diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc
index fd51dfb90..b7a19c094 100644
--- a/src/libexpr/primops/fetchTree.cc
+++ b/src/libexpr/primops/fetchTree.cc
@@ -190,7 +190,7 @@ static void fetchTree(
static void prim_fetchTree(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
- settings.requireExperimentalFeature(Xp::Flakes);
+ experimentalFeatureSettings.require(Xp::Flakes);
fetchTree(state, pos, args, v, std::nullopt, FetchTreeParams { .allowNameArgument = false });
}
diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc
index 38b73d531..596034c0f 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -199,10 +199,10 @@ void DerivationGoal::haveDerivation()
parsedDrv = std::make_unique<ParsedDerivation>(drvPath, *drv);
if (!drv->type().hasKnownOutputPaths())
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
if (!drv->type().isPure()) {
- settings.requireExperimentalFeature(Xp::ImpureDerivations);
+ experimentalFeatureSettings.require(Xp::ImpureDerivations);
for (auto & [outputName, output] : drv->outputs) {
auto randomPath = StorePath::random(outputPathName(drv->name, outputName));
@@ -336,7 +336,7 @@ void DerivationGoal::gaveUpOnSubstitution()
for (auto & i : dynamic_cast<Derivation *>(drv.get())->inputDrvs) {
/* Ensure that pure, non-fixed-output derivations don't
depend on impure derivations. */
- if (settings.isExperimentalFeatureEnabled(Xp::ImpureDerivations) && drv->type().isPure() && !drv->type().isFixed()) {
+ if (experimentalFeatureSettings.isEnabled(Xp::ImpureDerivations) && drv->type().isPure() && !drv->type().isFixed()) {
auto inputDrv = worker.evalStore.readDerivation(i.first);
if (!inputDrv.type().isPure())
throw Error("pure derivation '%s' depends on impure derivation '%s'",
@@ -477,7 +477,7 @@ void DerivationGoal::inputsRealised()
ca.fixed
/* Can optionally resolve if fixed, which is good
for avoiding unnecessary rebuilds. */
- ? settings.isExperimentalFeatureEnabled(Xp::CaDerivations)
+ ? experimentalFeatureSettings.isEnabled(Xp::CaDerivations)
/* Must resolve if floating and there are any inputs
drvs. */
: true);
@@ -488,7 +488,7 @@ void DerivationGoal::inputsRealised()
}, drvType.raw());
if (resolveDrv && !fullDrv.inputDrvs.empty()) {
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
/* We are be able to resolve this derivation based on the
now-known results of dependencies. If so, we become a
@@ -1352,7 +1352,7 @@ std::pair<bool, DrvOutputs> DerivationGoal::checkPathValidity()
};
}
auto drvOutput = DrvOutput{info.outputHash, i.first};
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
if (auto real = worker.store.queryRealisation(drvOutput)) {
info.known = {
.path = real->outPath,
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index 521117c68..923530d08 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -413,7 +413,7 @@ void LocalDerivationGoal::startBuilder()
)
{
#if __linux__
- settings.requireExperimentalFeature(Xp::Cgroups);
+ experimentalFeatureSettings.require(Xp::Cgroups);
auto cgroupFS = getCgroupFS();
if (!cgroupFS)
@@ -1393,7 +1393,7 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
void LocalDerivationGoal::startDaemon()
{
- settings.requireExperimentalFeature(Xp::RecursiveNix);
+ experimentalFeatureSettings.require(Xp::RecursiveNix);
Store::Params params;
params["path-info-cache-size"] = "0";
@@ -2268,7 +2268,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
bool discardReferences = false;
if (auto structuredAttrs = parsedDrv->getStructuredAttrs()) {
if (auto udr = get(*structuredAttrs, "unsafeDiscardReferences")) {
- settings.requireExperimentalFeature(Xp::DiscardReferences);
+ experimentalFeatureSettings.require(Xp::DiscardReferences);
if (auto output = get(*udr, outputName)) {
if (!output->is_boolean())
throw Error("attribute 'unsafeDiscardReferences.\"%s\"' of derivation '%s' must be a Boolean", outputName, drvPath.to_string());
@@ -2688,7 +2688,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
},
.outPath = newInfo.path
};
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)
&& drv->type().isPure())
{
signRealisation(thisRealisation);
diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc
index 7f8b0f905..656ad4587 100644
--- a/src/libstore/daemon.cc
+++ b/src/libstore/daemon.cc
@@ -231,10 +231,10 @@ struct ClientSettings
try {
if (name == "ssh-auth-sock") // obsolete
;
- else if (name == settings.experimentalFeatures.name) {
+ else if (name == experimentalFeatureSettings.experimentalFeatures.name) {
// We don’t want to forward the experimental features to
// the daemon, as that could cause some pretty weird stuff
- if (parseFeatures(tokenizeString<StringSet>(value)) != settings.experimentalFeatures.get())
+ if (parseFeatures(tokenizeString<StringSet>(value)) != experimentalFeatureSettings.experimentalFeatures.get())
debug("Ignoring the client-specified experimental features");
} else if (name == settings.pluginFiles.name) {
if (tokenizeString<Paths>(value) != settings.pluginFiles.get())
diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc
index 05dc9a3cc..06cc69056 100644
--- a/src/libstore/derivations.cc
+++ b/src/libstore/derivations.cc
@@ -221,7 +221,7 @@ static DerivationOutput parseDerivationOutput(const Store & store,
}
const auto hashType = parseHashType(hashAlgo);
if (hash == "impure") {
- settings.requireExperimentalFeature(Xp::ImpureDerivations);
+ experimentalFeatureSettings.require(Xp::ImpureDerivations);
assert(pathS == "");
return DerivationOutput::Impure {
.method = std::move(method),
@@ -236,7 +236,7 @@ static DerivationOutput parseDerivationOutput(const Store & store,
},
};
} else {
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
assert(pathS == "");
return DerivationOutput::CAFloating {
.method = std::move(method),
diff --git a/src/libstore/derived-path.cc b/src/libstore/derived-path.cc
index e0d86a42f..e5f0f1b33 100644
--- a/src/libstore/derived-path.cc
+++ b/src/libstore/derived-path.cc
@@ -105,7 +105,7 @@ RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const
auto drvHashes =
staticOutputHashes(store, store.readDerivation(p.drvPath));
for (auto& [outputName, outputPath] : p.outputs) {
- if (settings.isExperimentalFeatureEnabled(
+ if (experimentalFeatureSettings.isEnabled(
Xp::CaDerivations)) {
auto drvOutput = get(drvHashes, outputName);
if (!drvOutput)
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index fae79c1a0..8781e10ea 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -166,18 +166,6 @@ StringSet Settings::getDefaultExtraPlatforms()
return extraPlatforms;
}
-bool Settings::isExperimentalFeatureEnabled(const ExperimentalFeature & feature)
-{
- auto & f = experimentalFeatures.get();
- return std::find(f.begin(), f.end(), feature) != f.end();
-}
-
-void Settings::requireExperimentalFeature(const ExperimentalFeature & feature)
-{
- if (!isExperimentalFeatureEnabled(feature))
- throw MissingExperimentalFeature(feature);
-}
-
bool Settings::isWSL1()
{
struct utsname utsbuf;
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 93086eaf8..db01ab657 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -3,7 +3,6 @@
#include "types.hh"
#include "config.hh"
#include "util.hh"
-#include "experimental-features.hh"
#include <map>
#include <limits>
@@ -932,13 +931,6 @@ public:
are loaded as plugins (non-recursively).
)"};
- Setting<std::set<ExperimentalFeature>> experimentalFeatures{this, {}, "experimental-features",
- "Experimental Nix features to enable."};
-
- bool isExperimentalFeatureEnabled(const ExperimentalFeature &);
-
- void requireExperimentalFeature(const ExperimentalFeature &);
-
Setting<size_t> narBufferSize{this, 32 * 1024 * 1024, "nar-buffer-size",
"Maximum size of NARs before spilling them to disk."};
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index c9a466ee8..7782f7b50 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -336,7 +336,7 @@ LocalStore::LocalStore(const Params & params)
else openDB(*state, false);
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
migrateCASchema(state->db, dbDir + "/ca-schema", globalLock);
}
@@ -366,7 +366,7 @@ LocalStore::LocalStore(const Params & params)
state->stmts->QueryPathFromHashPart.create(state->db,
"select path from ValidPaths where path >= ? limit 1;");
state->stmts->QueryValidPaths.create(state->db, "select path from ValidPaths");
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
state->stmts->RegisterRealisedOutput.create(state->db,
R"(
insert into Realisations (drvPath, outputName, outputPath, signatures)
@@ -754,7 +754,7 @@ void LocalStore::checkDerivationOutputs(const StorePath & drvPath, const Derivat
void LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs)
{
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
if (checkSigs == NoCheckSigs || !realisationIsUntrusted(info))
registerDrvOutput(info);
else
@@ -763,7 +763,7 @@ void LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag check
void LocalStore::registerDrvOutput(const Realisation & info)
{
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
retrySQLite<void>([&]() {
auto state(_state.lock());
if (auto oldR = queryRealisation_(*state, info.id)) {
@@ -1052,7 +1052,7 @@ LocalStore::queryPartialDerivationOutputMap(const StorePath & path_)
return outputs;
});
- if (!settings.isExperimentalFeatureEnabled(Xp::CaDerivations))
+ if (!experimentalFeatureSettings.isEnabled(Xp::CaDerivations))
return outputs;
auto drv = readInvalidDerivation(path);
diff --git a/src/libstore/lock.cc b/src/libstore/lock.cc
index 4fe1fcf56..7202a64b3 100644
--- a/src/libstore/lock.cc
+++ b/src/libstore/lock.cc
@@ -129,7 +129,7 @@ struct AutoUserLock : UserLock
useUserNamespace = false;
#endif
- settings.requireExperimentalFeature(Xp::AutoAllocateUids);
+ experimentalFeatureSettings.require(Xp::AutoAllocateUids);
assert(settings.startId > 0);
assert(settings.uidCount % maxIdsPerBuild == 0);
assert((uint64_t) settings.startId + (uint64_t) settings.uidCount <= std::numeric_limits<uid_t>::max());
diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc
index b28768459..89148d415 100644
--- a/src/libstore/misc.cc
+++ b/src/libstore/misc.cc
@@ -326,7 +326,7 @@ OutputPathMap resolveDerivedPath(Store & store, const DerivedPath::Built & bfd,
throw Error(
"the derivation '%s' doesn't have an output named '%s'",
store.printStorePath(bfd.drvPath), output);
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
DrvOutput outputId { *outputHash, output };
auto realisation = store.queryRealisation(outputId);
if (!realisation)
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index d1296627a..d24d83117 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -265,7 +265,7 @@ void RemoteStore::setOptions(Connection & conn)
overrides.erase(settings.buildCores.name);
overrides.erase(settings.useSubstitutes.name);
overrides.erase(loggerSettings.showTrace.name);
- overrides.erase(settings.experimentalFeatures.name);
+ overrides.erase(experimentalFeatureSettings.experimentalFeatures.name);
overrides.erase(settings.pluginFiles.name);
conn.to << overrides.size();
for (auto & i : overrides)
@@ -876,7 +876,7 @@ std::vector<BuildResult> RemoteStore::buildPathsWithResults(
"the derivation '%s' doesn't have an output named '%s'",
printStorePath(bfd.drvPath), output);
auto outputId = DrvOutput{ *outputHash, output };
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
auto realisation =
queryRealisation(outputId);
if (!realisation)
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 19b0a7f5f..b0ca1321c 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -445,10 +445,10 @@ StringSet StoreConfig::getDefaultSystemFeatures()
{
auto res = settings.systemFeatures.get();
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations))
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations))
res.insert("ca-derivations");
- if (settings.isExperimentalFeatureEnabled(Xp::RecursiveNix))
+ if (experimentalFeatureSettings.isEnabled(Xp::RecursiveNix))
res.insert("recursive-nix");
return res;
@@ -1017,7 +1017,7 @@ std::map<StorePath, StorePath> copyPaths(
for (auto & path : paths) {
storePaths.insert(path.path());
if (auto realisation = std::get_if<Realisation>(&path.raw)) {
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
toplevelRealisations.insert(*realisation);
}
}
@@ -1250,7 +1250,7 @@ std::optional<StorePath> Store::getBuildDerivationPath(const StorePath & path)
}
}
- if (!settings.isExperimentalFeatureEnabled(Xp::CaDerivations) || !isValidPath(path))
+ if (!experimentalFeatureSettings.isEnabled(Xp::CaDerivations) || !isValidPath(path))
return path;
auto drv = readDerivation(path);
diff --git a/src/libutil/config.cc b/src/libutil/config.cc
index b349f2d80..3b854eded 100644
--- a/src/libutil/config.cc
+++ b/src/libutil/config.cc
@@ -444,4 +444,30 @@ GlobalConfig::Register::Register(Config * config)
configRegistrations->emplace_back(config);
}
+ExperimentalFeatureSettings experimentalFeatureSettings;
+
+static GlobalConfig::Register rSettings(&experimentalFeatureSettings);
+
+bool ExperimentalFeatureSettings::isEnabled(const ExperimentalFeature & feature) const
+{
+ auto & f = experimentalFeatures.get();
+ return std::find(f.begin(), f.end(), feature) != f.end();
+}
+
+void ExperimentalFeatureSettings::require(const ExperimentalFeature & feature) const
+{
+ if (!isEnabled(feature))
+ throw MissingExperimentalFeature(feature);
+}
+
+bool ExperimentalFeatureSettings::isEnabled(const std::optional<ExperimentalFeature> & feature) const
+{
+ return !feature || isEnabled(*feature);
+}
+
+void ExperimentalFeatureSettings::require(const std::optional<ExperimentalFeature> & feature) const
+{
+ if (feature) require(*feature);
+}
+
}
diff --git a/src/libutil/config.hh b/src/libutil/config.hh
index 7ac43c854..3e6796f50 100644
--- a/src/libutil/config.hh
+++ b/src/libutil/config.hh
@@ -1,12 +1,13 @@
+#pragma once
+
#include <cassert>
#include <map>
#include <set>
-#include "types.hh"
-
#include <nlohmann/json_fwd.hpp>
-#pragma once
+#include "types.hh"
+#include "experimental-features.hh"
namespace nix {
@@ -357,4 +358,37 @@ struct GlobalConfig : public AbstractConfig
extern GlobalConfig globalConfig;
+
+struct ExperimentalFeatureSettings : Config {
+
+ Setting<std::set<ExperimentalFeature>> experimentalFeatures{this, {}, "experimental-features",
+ "Experimental Nix features to enable."};
+
+ /**
+ * Check whether the given experimental feature is enabled.
+ */
+ bool isEnabled(const ExperimentalFeature &) const;
+
+ /**
+ * Require an experimental feature be enabled, throwing an error if it is
+ * not.
+ */
+ void require(const ExperimentalFeature &) const;
+
+ /**
+ * `std::nullopt` pointer means no feature, which means there is nothing that could be
+ * disabled, and so the function returns true in that case.
+ */
+ bool isEnabled(const std::optional<ExperimentalFeature> &) const;
+
+ /**
+ * `std::nullopt` pointer means no feature, which means there is nothing that could be
+ * disabled, and so the function does nothing in that case.
+ */
+ void require(const std::optional<ExperimentalFeature> &) const;
+};
+
+// FIXME: don't use a global variable.
+extern ExperimentalFeatureSettings experimentalFeatureSettings;
+
}
diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc
index a4b3b1f96..bc7e7eb18 100644
--- a/src/nix-build/nix-build.cc
+++ b/src/nix-build/nix-build.cc
@@ -440,7 +440,7 @@ static void main_nix_build(int argc, char * * argv)
shell = store->printStorePath(shellDrvOutputs.at("out").value()) + "/bin/bash";
}
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
auto resolvedDrv = drv.tryResolve(*store);
assert(resolvedDrv && "Successfully resolved the derivation");
drv = *resolvedDrv;
diff --git a/src/nix/develop.cc b/src/nix/develop.cc
index f06ade008..17993874b 100644
--- a/src/nix/develop.cc
+++ b/src/nix/develop.cc
@@ -208,7 +208,7 @@ static StorePath getDerivationEnvironment(ref<Store> store, ref<Store> evalStore
drv.name += "-env";
drv.env.emplace("name", drv.name);
drv.inputSrcs.insert(std::move(getEnvShPath));
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
+ if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
for (auto & output : drv.outputs) {
output.second = DerivationOutput::Deferred {},
drv.env[output.first] = hashPlaceholder(output.first);
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index 0a6616396..395180267 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -1328,7 +1328,7 @@ struct CmdFlake : NixMultiCommand
{
if (!command)
throw UsageError("'nix flake' requires a sub-command.");
- settings.requireExperimentalFeature(Xp::Flakes);
+ experimentalFeatureSettings.require(Xp::Flakes);
command->second->run();
}
};
diff --git a/src/nix/main.cc b/src/nix/main.cc
index 7b715f281..da920615f 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -297,7 +297,10 @@ void mainWrapped(int argc, char * * argv)
}
if (argc == 2 && std::string(argv[1]) == "__dump-builtins") {
- settings.experimentalFeatures = {Xp::Flakes, Xp::FetchClosure};
+ experimentalFeatureSettings.experimentalFeatures = {
+ Xp::Flakes,
+ Xp::FetchClosure,
+ };
evalSettings.pureEval = false;
EvalState state({}, openStore("dummy://"));
auto res = nlohmann::json::object();
@@ -366,7 +369,7 @@ void mainWrapped(int argc, char * * argv)
if (args.command->first != "repl"
&& args.command->first != "doctor"
&& args.command->first != "upgrade-nix")
- settings.requireExperimentalFeature(Xp::NixCommand);
+ experimentalFeatureSettings.require(Xp::NixCommand);
if (args.useNet && !haveInternet()) {
warn("you don't have Internet access; disabling some network-dependent features");
diff --git a/src/nix/realisation.cc b/src/nix/realisation.cc
index 13db80282..e19e93219 100644
--- a/src/nix/realisation.cc
+++ b/src/nix/realisation.cc
@@ -45,7 +45,7 @@ struct CmdRealisationInfo : BuiltPathsCommand, MixJSON
void run(ref<Store> store, BuiltPaths && paths) override
{
- settings.requireExperimentalFeature(Xp::CaDerivations);
+ experimentalFeatureSettings.require(Xp::CaDerivations);
RealisedPath::Set realisations;
for (auto & builtPath : paths) {
diff --git a/src/nix/registry.cc b/src/nix/registry.cc
index 1f4f820ac..cb94bbd31 100644
--- a/src/nix/registry.cc
+++ b/src/nix/registry.cc
@@ -224,7 +224,7 @@ struct CmdRegistry : virtual NixMultiCommand
void run() override
{
- settings.requireExperimentalFeature(Xp::Flakes);
+ experimentalFeatureSettings.require(Xp::Flakes);
if (!command)
throw UsageError("'nix registry' requires a sub-command.");
command->second->run();
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index 51d3074b4..1b329f1a6 100644
--- a/src/nix/repl.cc
+++ b/src/nix/repl.cc
@@ -37,7 +37,7 @@ struct CmdRepl : RawInstallablesCommand
void applyDefaultInstallables(std::vector<std::string> & rawInstallables) override
{
- if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && rawInstallables.size() >= 1) {
+ if (!experimentalFeatureSettings.isEnabled(Xp::ReplFlake) && !(file) && rawInstallables.size() >= 1) {
warn("future versions of Nix will require using `--file` to load a file");
if (rawInstallables.size() > 1)
warn("more than one input file is not currently supported");