Merge pull request #6314 from edolstra/experimental-primop

Only provide builtins is the corresponding experimental feature is enabled
This commit is contained in:
Eelco Dolstra 2022-03-25 16:16:31 +01:00 committed by GitHub
commit 1844172dd1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 50 additions and 40 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

@ -17,7 +17,7 @@
namespace nix { namespace nix {
struct Store; class Store;
class EvalState; class EvalState;
class StorePath; class StorePath;
enum RepairFlag : bool; enum RepairFlag : bool;
@ -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,30 @@ 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"},
.doc = R"(
Fetch a flake from a flake reference, and return its output attributes and some metadata. For example:
```nix
(builtins.getFlake "nix/55bc52401966fbffa525c574c14f67b00bc4fb3a").packages.x86_64-linux.nix
```
Unless impure evaluation is allowed (`--impure`), the flake reference
must be "locked", e.g. contain a Git revision or content hash. An
example of an unlocked usage is:
```nix
(builtins.getFlake "github:edolstra/dwarffs").rev
```
This function is only available if you enable the experimental feature
`flakes`.
)",
.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();