Only provide builtin.{getFlake,fetchClosure} is the corresponding experimental feature is enabled

This allows writing fallback code like

  if builtins ? fetchClosure then
    builtins.fetchClose { ... }
  else
    builtins.storePath ...
This commit is contained in:
Eelco Dolstra 2022-03-25 14:04:18 +01:00
parent 55bc524019
commit 86b05ccd54
8 changed files with 31 additions and 39 deletions

View file

@ -5,9 +5,12 @@
* `nix store make-content-addressable` has been renamed to `nix store * `nix store make-content-addressable` has been renamed to `nix store
make-content-addressed`. make-content-addressed`.
* New builtin function `builtins.fetchClosure` that copies a closure * New experimental builtin function `builtins.fetchClosure` that
from a binary cache at evaluation time and rewrites it to copies a closure from a binary cache at evaluation time and rewrites
content-addressed form (if it isn't already). Like it to content-addressed form (if it isn't already). Like
`builtins.storePath`, this allows importing pre-built store paths; `builtins.storePath`, this allows importing pre-built store paths;
the difference is that it doesn't require the user to configure the difference is that it doesn't require the user to configure
binary caches and trusted public keys. binary caches and trusted public keys.
This function is only available if you enable the experimental
feature `fetch-closure`.

View file

@ -507,23 +507,6 @@ EvalState::~EvalState()
} }
void EvalState::requireExperimentalFeatureOnEvaluation(
const ExperimentalFeature & feature,
const std::string_view fName,
const Pos & pos)
{
if (!settings.isExperimentalFeatureEnabled(feature)) {
throw EvalError({
.msg = hintfmt(
"Cannot call '%2%' because experimental Nix feature '%1%' is disabled. You can enable it via '--extra-experimental-features %1%'.",
feature,
fName
),
.errPos = pos
});
}
}
void EvalState::allowPath(const Path & path) void EvalState::allowPath(const Path & path)
{ {
if (allowedPaths) if (allowedPaths)

View file

@ -149,12 +149,6 @@ public:
std::shared_ptr<Store> buildStore = nullptr); std::shared_ptr<Store> buildStore = nullptr);
~EvalState(); ~EvalState();
void requireExperimentalFeatureOnEvaluation(
const ExperimentalFeature &,
const std::string_view fName,
const Pos & pos
);
void addToSearchPath(const std::string & s); void addToSearchPath(const std::string & s);
SearchPath getSearchPath() { return searchPath; } SearchPath getSearchPath() { return searchPath; }

View file

@ -706,8 +706,6 @@ void callFlake(EvalState & state,
static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
state.requireExperimentalFeatureOnEvaluation(Xp::Flakes, "builtins.getFlake", pos);
std::string flakeRefS(state.forceStringNoCtx(*args[0], pos)); std::string flakeRefS(state.forceStringNoCtx(*args[0], pos));
auto flakeRef = parseFlakeRef(flakeRefS, {}, true); auto flakeRef = parseFlakeRef(flakeRefS, {}, true);
if (evalSettings.pureEval && !flakeRef.input.isLocked()) if (evalSettings.pureEval && !flakeRef.input.isLocked())
@ -723,7 +721,12 @@ static void prim_getFlake(EvalState & state, const Pos & pos, Value * * args, Va
v); v);
} }
static RegisterPrimOp r2("__getFlake", 1, prim_getFlake); static RegisterPrimOp r2({
.name = "__getFlake",
.args = {"args"},
.fun = prim_getFlake,
.experimentalFeature = Xp::Flakes,
});
} }

View file

@ -3814,7 +3814,7 @@ RegisterPrimOp::RegisterPrimOp(std::string name, size_t arity, PrimOpFun fun)
.name = name, .name = name,
.args = {}, .args = {},
.arity = arity, .arity = arity,
.fun = fun .fun = fun,
}); });
} }
@ -3886,13 +3886,17 @@ void EvalState::createBaseEnv()
if (RegisterPrimOp::primOps) if (RegisterPrimOp::primOps)
for (auto & primOp : *RegisterPrimOp::primOps) for (auto & primOp : *RegisterPrimOp::primOps)
addPrimOp({ if (!primOp.experimentalFeature
.fun = primOp.fun, || settings.isExperimentalFeatureEnabled(*primOp.experimentalFeature))
.arity = std::max(primOp.args.size(), primOp.arity), {
.name = symbols.create(primOp.name), addPrimOp({
.args = primOp.args, .fun = primOp.fun,
.doc = primOp.doc, .arity = std::max(primOp.args.size(), primOp.arity),
}); .name = symbols.create(primOp.name),
.args = primOp.args,
.doc = primOp.doc,
});
}
/* Add a wrapper around the derivation primop that computes the /* Add a wrapper around the derivation primop that computes the
`drvPath' and `outPath' attributes lazily. */ `drvPath' and `outPath' attributes lazily. */

View file

@ -16,6 +16,7 @@ struct RegisterPrimOp
size_t arity = 0; size_t arity = 0;
const char * doc; const char * doc;
PrimOpFun fun; PrimOpFun fun;
std::optional<ExperimentalFeature> experimentalFeature;
}; };
typedef std::vector<Info> PrimOps; typedef std::vector<Info> PrimOps;
@ -35,6 +36,7 @@ struct RegisterPrimOp
/* These primops are disabled without enableNativeCode, but plugins /* These primops are disabled without enableNativeCode, but plugins
may wish to use them in limited contexts without globally enabling may wish to use them in limited contexts without globally enabling
them. */ them. */
/* Load a ValueInitializer from a DSO and return whatever it initializes */ /* Load a ValueInitializer from a DSO and return whatever it initializes */
void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value & v); void prim_importNative(EvalState & state, const Pos & pos, Value * * args, Value & v);

View file

@ -7,8 +7,6 @@ namespace nix {
static void prim_fetchClosure(EvalState & state, const Pos & pos, Value * * args, Value & v) static void prim_fetchClosure(EvalState & state, const Pos & pos, Value * * args, Value & v)
{ {
settings.requireExperimentalFeature(Xp::FetchClosure);
state.forceAttrs(*args[0], pos); state.forceAttrs(*args[0], pos);
std::optional<std::string> fromStoreUrl; std::optional<std::string> fromStoreUrl;
@ -145,8 +143,12 @@ static RegisterPrimOp primop_fetchClosure({
specifying a binary cache from which the path can be fetched. specifying a binary cache from which the path can be fetched.
Also, requiring a content-addressed final store path avoids the Also, requiring a content-addressed final store path avoids the
need for users to configure binary cache public keys. need for users to configure binary cache public keys.
This function is only available if you enable the experimental
feature `fetch-closure`.
)", )",
.fun = prim_fetchClosure, .fun = prim_fetchClosure,
.experimentalFeature = Xp::FetchClosure,
}); });
} }

View file

@ -289,6 +289,7 @@ void mainWrapped(int argc, char * * argv)
} }
if (argc == 2 && std::string(argv[1]) == "__dump-builtins") { if (argc == 2 && std::string(argv[1]) == "__dump-builtins") {
settings.experimentalFeatures = {Xp::Flakes, Xp::FetchClosure};
evalSettings.pureEval = false; evalSettings.pureEval = false;
EvalState state({}, openStore("dummy://")); EvalState state({}, openStore("dummy://"));
auto res = nlohmann::json::object(); auto res = nlohmann::json::object();