1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-24 22:11:15 +02:00

C API: (breaking) remove nix-flake-c global init

This commit is contained in:
Robert Hensing 2025-03-26 08:59:05 +00:00
parent 3c4c0953e0
commit 6a192ec0cd
12 changed files with 124 additions and 69 deletions

View file

@ -0,0 +1,20 @@
---
synopsis: C API `nix_flake_init_global` removed
prs: 12759
issues: 5638
---
In order to improve the modularity of the code base, we are removing a use of global state, and therefore the `nix_flake_init_global` function.
Instead, use `nix_flake_settings_add_to_eval_state_builder`. For example:
```diff
- nix_flake_init_global(ctx, settings);
- HANDLE_ERROR(ctx);
-
nix_eval_state_builder * builder = nix_eval_state_builder_new(ctx, store);
HANDLE_ERROR(ctx);
+ nix_flake_settings_add_to_eval_state_builder(ctx, settings, builder);
+ HANDLE_ERROR(ctx);
```

View file

@ -1,6 +1,7 @@
#include "nix_api_flake.h"
#include "nix_api_flake_internal.hh"
#include "nix_api_util_internal.h"
#include "nix_api_expr_internal.h"
#include "flake/flake.hh"
@ -18,15 +19,11 @@ void nix_flake_settings_free(nix_flake_settings * settings)
delete settings;
}
nix_err nix_flake_init_global(nix_c_context * context, nix_flake_settings * settings)
nix_err nix_flake_settings_add_to_eval_state_builder(
nix_c_context * context, nix_flake_settings * settings, nix_eval_state_builder * builder)
{
static std::shared_ptr<nix::flake::Settings> registeredSettings;
try {
if (registeredSettings)
throw nix::Error("nix_flake_init_global already initialized");
registeredSettings = settings->settings;
nix::flake::initLib(*registeredSettings);
settings->settings->configureEvalSettings(builder->settings);
}
NIXC_CATCH_ERRS
}

View file

@ -35,9 +35,15 @@ nix_flake_settings * nix_flake_settings_new(nix_c_context * context);
void nix_flake_settings_free(nix_flake_settings * settings);
/**
* @brief Register Flakes support process-wide.
* @brief Initialize a `nix_flake_settings` to contain `builtins.getFlake` and
* potentially more.
*
* @param[out] context Optional, stores error information
* @param[in] settings The settings to use for e.g. `builtins.getFlake`
* @param[in] builder The builder to modify
*/
nix_err nix_flake_init_global(nix_c_context * context, nix_flake_settings * settings);
nix_err nix_flake_settings_add_to_eval_state_builder(
nix_c_context * context, nix_flake_settings * settings, nix_eval_state_builder * builder);
#ifdef __cplusplus
} // extern "C"

View file

@ -25,13 +25,13 @@ TEST_F(nix_api_store_test, nix_api_init_global_getFlake_exists)
assert_ctx_ok();
ASSERT_NE(nullptr, settings);
nix_flake_init_global(ctx, settings);
assert_ctx_ok();
nix_eval_state_builder * builder = nix_eval_state_builder_new(ctx, store);
ASSERT_NE(nullptr, builder);
assert_ctx_ok();
nix_flake_settings_add_to_eval_state_builder(ctx, settings, builder);
assert_ctx_ok();
auto state = nix_eval_state_build(ctx, builder);
assert_ctx_ok();
ASSERT_NE(nullptr, state);

View file

@ -0,0 +1,59 @@
#include "flake-primops.hh"
#include "eval.hh"
#include "flake.hh"
#include "flakeref.hh"
#include "settings.hh"
namespace nix::flake::primops {
PrimOp getFlake(const Settings & settings)
{
auto prim_getFlake = [&settings](EvalState & state, const PosIdx pos, Value ** args, Value & v) {
std::string flakeRefS(
state.forceStringNoCtx(*args[0], pos, "while evaluating the argument passed to builtins.getFlake"));
auto flakeRef = nix::parseFlakeRef(state.fetchSettings, flakeRefS, {}, true);
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,
lockFlake(
settings,
state,
flakeRef,
LockFlags{
.updateLockFile = false,
.writeLockFile = false,
.useRegistries = !state.settings.pureEval && settings.useRegistries,
.allowUnlocked = !state.settings.pureEval,
}),
v);
};
return PrimOp{
.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
```
)",
.fun = prim_getFlake,
.experimentalFeature = Xp::Flakes,
};
}
} // namespace nix::flake::primops

View file

@ -0,0 +1,13 @@
#pragma once
#include "eval.hh"
#include "flake/settings.hh"
namespace nix::flake::primops {
/**
* Returns a `builtins.getFlake` primop with the given nix::flake::Settings.
*/
nix::PrimOp getFlake(const Settings & settings);
} // namespace nix::flake

View file

@ -973,49 +973,6 @@ void callFlake(EvalState & state,
state.callFunction(*vCallFlake, args, vRes, noPos);
}
void initLib(const Settings & settings)
{
auto prim_getFlake = [&settings](EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
std::string flakeRefS(state.forceStringNoCtx(*args[0], pos, "while evaluating the argument passed to builtins.getFlake"));
auto flakeRef = parseFlakeRef(state.fetchSettings, flakeRefS, {}, true);
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,
lockFlake(settings, state, flakeRef,
LockFlags {
.updateLockFile = false,
.writeLockFile = false,
.useRegistries = !state.settings.pureEval && settings.useRegistries,
.allowUnlocked = !state.settings.pureEval,
}),
v);
};
RegisterPrimOp::primOps->push_back({
.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
```
)",
.fun = prim_getFlake,
.experimentalFeature = Xp::Flakes,
});
}
static void prim_parseFlakeRef(
EvalState & state,
const PosIdx pos,

View file

@ -14,14 +14,6 @@ namespace flake {
struct Settings;
/**
* Initialize `libnixflake`
*
* So far, this registers the `builtins.getFlake` primop, which depends
* on the choice of `flake:Settings`.
*/
void initLib(const Settings & settings);
struct FlakeInput;
typedef std::map<FlakeId, FlakeInput> FlakeInputs;

View file

@ -1,7 +1,13 @@
#include "flake/settings.hh"
#include "flake/flake-primops.hh"
namespace nix::flake {
Settings::Settings() {}
void Settings::configureEvalSettings(nix::EvalSettings & evalSettings)
{
evalSettings.addPrimOp(primops::getFlake(*this));
}
} // namespace nix

View file

@ -1,21 +1,24 @@
#pragma once
///@file
#include "types.hh"
#include "config.hh"
#include "util.hh"
#include <map>
#include <limits>
#include <sys/types.h>
namespace nix {
// Forward declarations
struct EvalSettings;
} // namespace nix
namespace nix::flake {
struct Settings : public Config
{
Settings();
void configureEvalSettings(nix::EvalSettings & evalSettings);
Setting<bool> useRegistries{
this,
true,

View file

@ -44,6 +44,7 @@ sources = files(
'flake/flake.cc',
'flake/flakeref.cc',
'flake/lockfile.cc',
'flake/flake-primops.cc',
'flake/settings.cc',
'flake/url-name.cc',
)

View file

@ -18,6 +18,7 @@
#include "network-proxy.hh"
#include "eval-cache.hh"
#include "flake/flake.hh"
#include "flake/settings.hh"
#include "self-exe.hh"
#include "json-utils.hh"
#include "crash-handler.hh"
@ -368,7 +369,7 @@ void mainWrapped(int argc, char * * argv)
initNix();
initGC();
flake::initLib(flakeSettings);
flakeSettings.configureEvalSettings(evalSettings);
/* Set the build hook location