mirror of
https://github.com/NixOS/nix
synced 2025-06-25 19:01:16 +02:00
Merge pull request #12759 from roberth/c-api-libflake-settings
C API / settings: remove nix-flake-c global init
This commit is contained in:
commit
a26a15d05c
20 changed files with 277 additions and 189 deletions
20
doc/manual/rl-next/c-api-flake-init.md
Normal file
20
doc/manual/rl-next/c-api-flake-init.md
Normal 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);
|
||||||
|
```
|
|
@ -103,4 +103,4 @@ Path getNixDefExpr()
|
||||||
: getHome() + "/.nix-defexpr";
|
: getHome() + "/.nix-defexpr";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace nix
|
|
@ -7,6 +7,7 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
class EvalState;
|
class EvalState;
|
||||||
|
struct PrimOp;
|
||||||
|
|
||||||
struct EvalSettings : Config
|
struct EvalSettings : Config
|
||||||
{
|
{
|
||||||
|
@ -50,6 +51,8 @@ struct EvalSettings : Config
|
||||||
|
|
||||||
LookupPathHooks lookupPathHooks;
|
LookupPathHooks lookupPathHooks;
|
||||||
|
|
||||||
|
std::vector<PrimOp> extraPrimOps;
|
||||||
|
|
||||||
Setting<bool> enableNativeCode{this, false, "allow-unsafe-native-code-during-evaluation", R"(
|
Setting<bool> enableNativeCode{this, false, "allow-unsafe-native-code-during-evaluation", R"(
|
||||||
Enable built-in functions that allow executing native code.
|
Enable built-in functions that allow executing native code.
|
||||||
|
|
||||||
|
|
|
@ -288,10 +288,6 @@ EvalState::EvalState(
|
||||||
CanonPath("derivation-internal.nix"),
|
CanonPath("derivation-internal.nix"),
|
||||||
#include "primops/derivation.nix.gen.hh"
|
#include "primops/derivation.nix.gen.hh"
|
||||||
)}
|
)}
|
||||||
, callFlakeInternal{internalFS->addFile(
|
|
||||||
CanonPath("call-flake.nix"),
|
|
||||||
#include "call-flake.nix.gen.hh"
|
|
||||||
)}
|
|
||||||
, store(store)
|
, store(store)
|
||||||
, buildStore(buildStore ? buildStore : store)
|
, buildStore(buildStore ? buildStore : store)
|
||||||
, debugRepl(nullptr)
|
, debugRepl(nullptr)
|
||||||
|
@ -353,7 +349,7 @@ EvalState::EvalState(
|
||||||
#include "fetchurl.nix.gen.hh"
|
#include "fetchurl.nix.gen.hh"
|
||||||
);
|
);
|
||||||
|
|
||||||
createBaseEnv();
|
createBaseEnv(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -274,14 +274,12 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In-memory filesystem for internal, non-user-callable Nix
|
* In-memory filesystem for internal, non-user-callable Nix
|
||||||
* expressions like call-flake.nix.
|
* expressions like `derivation.nix`.
|
||||||
*/
|
*/
|
||||||
const ref<MemorySourceAccessor> internalFS;
|
const ref<MemorySourceAccessor> internalFS;
|
||||||
|
|
||||||
const SourcePath derivationInternal;
|
const SourcePath derivationInternal;
|
||||||
|
|
||||||
const SourcePath callFlakeInternal;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store used to materialise .drv files.
|
* Store used to materialise .drv files.
|
||||||
*/
|
*/
|
||||||
|
@ -633,7 +631,7 @@ private:
|
||||||
|
|
||||||
unsigned int baseEnvDispl = 0;
|
unsigned int baseEnvDispl = 0;
|
||||||
|
|
||||||
void createBaseEnv();
|
void createBaseEnv(const EvalSettings & settings);
|
||||||
|
|
||||||
Value * addConstant(const std::string & name, Value & v, Constant info);
|
Value * addConstant(const std::string & name, Value & v, Constant info);
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,6 @@ generated_headers = []
|
||||||
foreach header : [
|
foreach header : [
|
||||||
'imported-drv-to-derivation.nix',
|
'imported-drv-to-derivation.nix',
|
||||||
'fetchurl.nix',
|
'fetchurl.nix',
|
||||||
'call-flake.nix',
|
|
||||||
]
|
]
|
||||||
generated_headers += gen_header.process(header)
|
generated_headers += gen_header.process(header)
|
||||||
endforeach
|
endforeach
|
||||||
|
|
|
@ -4675,7 +4675,7 @@ RegisterPrimOp::RegisterPrimOp(PrimOp && primOp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EvalState::createBaseEnv()
|
void EvalState::createBaseEnv(const EvalSettings & evalSettings)
|
||||||
{
|
{
|
||||||
baseEnv.up = 0;
|
baseEnv.up = 0;
|
||||||
|
|
||||||
|
@ -4934,6 +4934,12 @@ void EvalState::createBaseEnv()
|
||||||
addPrimOp(std::move(primOpAdjusted));
|
addPrimOp(std::move(primOpAdjusted));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto & primOp : evalSettings.extraPrimOps) {
|
||||||
|
auto primOpAdjusted = primOp;
|
||||||
|
primOpAdjusted.arity = std::max(primOp.args.size(), primOp.arity);
|
||||||
|
addPrimOp(std::move(primOpAdjusted));
|
||||||
|
}
|
||||||
|
|
||||||
/* 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.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "nix_api_flake.h"
|
#include "nix_api_flake.h"
|
||||||
#include "nix_api_flake_internal.hh"
|
#include "nix_api_flake_internal.hh"
|
||||||
#include "nix_api_util_internal.h"
|
#include "nix_api_util_internal.h"
|
||||||
|
#include "nix_api_expr_internal.h"
|
||||||
|
|
||||||
#include "flake/flake.hh"
|
#include "flake/flake.hh"
|
||||||
|
|
||||||
|
@ -18,15 +19,11 @@ void nix_flake_settings_free(nix_flake_settings * settings)
|
||||||
delete 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 {
|
try {
|
||||||
if (registeredSettings)
|
settings->settings->configureEvalSettings(builder->settings);
|
||||||
throw nix::Error("nix_flake_init_global already initialized");
|
|
||||||
|
|
||||||
registeredSettings = settings->settings;
|
|
||||||
nix::flake::initLib(*registeredSettings);
|
|
||||||
}
|
}
|
||||||
NIXC_CATCH_ERRS
|
NIXC_CATCH_ERRS
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,9 +35,15 @@ nix_flake_settings * nix_flake_settings_new(nix_c_context * context);
|
||||||
void nix_flake_settings_free(nix_flake_settings * settings);
|
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
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
|
@ -25,13 +25,13 @@ TEST_F(nix_api_store_test, nix_api_init_global_getFlake_exists)
|
||||||
assert_ctx_ok();
|
assert_ctx_ok();
|
||||||
ASSERT_NE(nullptr, settings);
|
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);
|
nix_eval_state_builder * builder = nix_eval_state_builder_new(ctx, store);
|
||||||
ASSERT_NE(nullptr, builder);
|
ASSERT_NE(nullptr, builder);
|
||||||
assert_ctx_ok();
|
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);
|
auto state = nix_eval_state_build(ctx, builder);
|
||||||
assert_ctx_ok();
|
assert_ctx_ok();
|
||||||
ASSERT_NE(nullptr, state);
|
ASSERT_NE(nullptr, state);
|
||||||
|
|
160
src/libflake/flake/flake-primops.cc
Normal file
160
src/libflake/flake/flake-primops.cc
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
#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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prim_parseFlakeRef(EvalState & state, const PosIdx pos, Value ** args, Value & v)
|
||||||
|
{
|
||||||
|
std::string flakeRefS(
|
||||||
|
state.forceStringNoCtx(*args[0], pos, "while evaluating the argument passed to builtins.parseFlakeRef"));
|
||||||
|
auto attrs = nix::parseFlakeRef(state.fetchSettings, flakeRefS, {}, true).toAttrs();
|
||||||
|
auto binds = state.buildBindings(attrs.size());
|
||||||
|
for (const auto & [key, value] : attrs) {
|
||||||
|
auto s = state.symbols.create(key);
|
||||||
|
auto & vv = binds.alloc(s);
|
||||||
|
std::visit(
|
||||||
|
overloaded{
|
||||||
|
[&vv](const std::string & value) { vv.mkString(value); },
|
||||||
|
[&vv](const uint64_t & value) { vv.mkInt(value); },
|
||||||
|
[&vv](const Explicit<bool> & value) { vv.mkBool(value.t); }},
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
v.mkAttrs(binds);
|
||||||
|
}
|
||||||
|
|
||||||
|
nix::PrimOp parseFlakeRef({
|
||||||
|
.name = "__parseFlakeRef",
|
||||||
|
.args = {"flake-ref"},
|
||||||
|
.doc = R"(
|
||||||
|
Parse a flake reference, and return its exploded form.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
builtins.parseFlakeRef "github:NixOS/nixpkgs/23.05?dir=lib"
|
||||||
|
```
|
||||||
|
|
||||||
|
evaluates to:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ dir = "lib"; owner = "NixOS"; ref = "23.05"; repo = "nixpkgs"; type = "github"; }
|
||||||
|
```
|
||||||
|
)",
|
||||||
|
.fun = prim_parseFlakeRef,
|
||||||
|
.experimentalFeature = Xp::Flakes,
|
||||||
|
});
|
||||||
|
|
||||||
|
static void prim_flakeRefToString(EvalState & state, const PosIdx pos, Value ** args, Value & v)
|
||||||
|
{
|
||||||
|
state.forceAttrs(*args[0], noPos, "while evaluating the argument passed to builtins.flakeRefToString");
|
||||||
|
fetchers::Attrs attrs;
|
||||||
|
for (const auto & attr : *args[0]->attrs()) {
|
||||||
|
auto t = attr.value->type();
|
||||||
|
if (t == nInt) {
|
||||||
|
auto intValue = attr.value->integer().value;
|
||||||
|
|
||||||
|
if (intValue < 0) {
|
||||||
|
state
|
||||||
|
.error<EvalError>(
|
||||||
|
"negative value given for flake ref attr %1%: %2%", state.symbols[attr.name], intValue)
|
||||||
|
.atPos(pos)
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs.emplace(state.symbols[attr.name], uint64_t(intValue));
|
||||||
|
} else if (t == nBool) {
|
||||||
|
attrs.emplace(state.symbols[attr.name], Explicit<bool>{attr.value->boolean()});
|
||||||
|
} else if (t == nString) {
|
||||||
|
attrs.emplace(state.symbols[attr.name], std::string(attr.value->string_view()));
|
||||||
|
} else {
|
||||||
|
state
|
||||||
|
.error<EvalError>(
|
||||||
|
"flake reference attribute sets may only contain integers, Booleans, "
|
||||||
|
"and strings, but attribute '%s' is %s",
|
||||||
|
state.symbols[attr.name],
|
||||||
|
showType(*attr.value))
|
||||||
|
.debugThrow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto flakeRef = FlakeRef::fromAttrs(state.fetchSettings, attrs);
|
||||||
|
v.mkString(flakeRef.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
nix::PrimOp flakeRefToString({
|
||||||
|
.name = "__flakeRefToString",
|
||||||
|
.args = {"attrs"},
|
||||||
|
.doc = R"(
|
||||||
|
Convert a flake reference from attribute set format to URL format.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
builtins.flakeRefToString {
|
||||||
|
dir = "lib"; owner = "NixOS"; ref = "23.05"; repo = "nixpkgs"; type = "github";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
evaluates to
|
||||||
|
|
||||||
|
```nix
|
||||||
|
"github:NixOS/nixpkgs/23.05?dir=lib"
|
||||||
|
```
|
||||||
|
)",
|
||||||
|
.fun = prim_flakeRefToString,
|
||||||
|
.experimentalFeature = Xp::Flakes,
|
||||||
|
});
|
||||||
|
|
||||||
|
} // namespace nix::flake::primops
|
16
src/libflake/flake/flake-primops.hh
Normal file
16
src/libflake/flake/flake-primops.hh
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#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);
|
||||||
|
|
||||||
|
extern nix::PrimOp parseFlakeRef;
|
||||||
|
extern nix::PrimOp flakeRefToString;
|
||||||
|
|
||||||
|
} // namespace nix::flake
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include "memory-source-accessor.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
using namespace flake;
|
using namespace flake;
|
||||||
|
@ -921,6 +923,25 @@ LockedFlake lockFlake(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ref<SourceAccessor> makeInternalFS() {
|
||||||
|
auto internalFS = make_ref<MemorySourceAccessor>(MemorySourceAccessor {});
|
||||||
|
internalFS->setPathDisplay("«flakes-internal»", "");
|
||||||
|
internalFS->addFile(
|
||||||
|
CanonPath("call-flake.nix"),
|
||||||
|
#include "call-flake.nix.gen.hh"
|
||||||
|
);
|
||||||
|
return internalFS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto internalFS = makeInternalFS();
|
||||||
|
|
||||||
|
static Value * requireInternalFile(EvalState & state, CanonPath path) {
|
||||||
|
SourcePath p {internalFS, path};
|
||||||
|
auto v = state.allocValue();
|
||||||
|
state.evalFile(p, *v); // has caching
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
void callFlake(EvalState & state,
|
void callFlake(EvalState & state,
|
||||||
const LockedFlake & lockedFlake,
|
const LockedFlake & lockedFlake,
|
||||||
Value & vRes)
|
Value & vRes)
|
||||||
|
@ -960,8 +981,7 @@ void callFlake(EvalState & state,
|
||||||
|
|
||||||
auto & vOverrides = state.allocValue()->mkAttrs(overrides);
|
auto & vOverrides = state.allocValue()->mkAttrs(overrides);
|
||||||
|
|
||||||
auto vCallFlake = state.allocValue();
|
Value * vCallFlake = requireInternalFile(state, CanonPath("call-flake.nix"));
|
||||||
state.evalFile(state.callFlakeInternal, *vCallFlake);
|
|
||||||
|
|
||||||
auto vLocks = state.allocValue();
|
auto vLocks = state.allocValue();
|
||||||
vLocks->mkString(lockFileStr);
|
vLocks->mkString(lockFileStr);
|
||||||
|
@ -973,155 +993,6 @@ void callFlake(EvalState & state,
|
||||||
state.callFunction(*vCallFlake, args, vRes, noPos);
|
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,
|
|
||||||
Value * * args,
|
|
||||||
Value & v)
|
|
||||||
{
|
|
||||||
std::string flakeRefS(state.forceStringNoCtx(*args[0], pos,
|
|
||||||
"while evaluating the argument passed to builtins.parseFlakeRef"));
|
|
||||||
auto attrs = parseFlakeRef(state.fetchSettings, flakeRefS, {}, true).toAttrs();
|
|
||||||
auto binds = state.buildBindings(attrs.size());
|
|
||||||
for (const auto & [key, value] : attrs) {
|
|
||||||
auto s = state.symbols.create(key);
|
|
||||||
auto & vv = binds.alloc(s);
|
|
||||||
std::visit(overloaded {
|
|
||||||
[&vv](const std::string & value) { vv.mkString(value); },
|
|
||||||
[&vv](const uint64_t & value) { vv.mkInt(value); },
|
|
||||||
[&vv](const Explicit<bool> & value) { vv.mkBool(value.t); }
|
|
||||||
}, value);
|
|
||||||
}
|
|
||||||
v.mkAttrs(binds);
|
|
||||||
}
|
|
||||||
|
|
||||||
static RegisterPrimOp r3({
|
|
||||||
.name = "__parseFlakeRef",
|
|
||||||
.args = {"flake-ref"},
|
|
||||||
.doc = R"(
|
|
||||||
Parse a flake reference, and return its exploded form.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
builtins.parseFlakeRef "github:NixOS/nixpkgs/23.05?dir=lib"
|
|
||||||
```
|
|
||||||
|
|
||||||
evaluates to:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{ dir = "lib"; owner = "NixOS"; ref = "23.05"; repo = "nixpkgs"; type = "github"; }
|
|
||||||
```
|
|
||||||
)",
|
|
||||||
.fun = prim_parseFlakeRef,
|
|
||||||
.experimentalFeature = Xp::Flakes,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
static void prim_flakeRefToString(
|
|
||||||
EvalState & state,
|
|
||||||
const PosIdx pos,
|
|
||||||
Value * * args,
|
|
||||||
Value & v)
|
|
||||||
{
|
|
||||||
state.forceAttrs(*args[0], noPos,
|
|
||||||
"while evaluating the argument passed to builtins.flakeRefToString");
|
|
||||||
fetchers::Attrs attrs;
|
|
||||||
for (const auto & attr : *args[0]->attrs()) {
|
|
||||||
auto t = attr.value->type();
|
|
||||||
if (t == nInt) {
|
|
||||||
auto intValue = attr.value->integer().value;
|
|
||||||
|
|
||||||
if (intValue < 0) {
|
|
||||||
state.error<EvalError>("negative value given for flake ref attr %1%: %2%", state.symbols[attr.name], intValue).atPos(pos).debugThrow();
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs.emplace(state.symbols[attr.name], uint64_t(intValue));
|
|
||||||
} else if (t == nBool) {
|
|
||||||
attrs.emplace(state.symbols[attr.name],
|
|
||||||
Explicit<bool> { attr.value->boolean() });
|
|
||||||
} else if (t == nString) {
|
|
||||||
attrs.emplace(state.symbols[attr.name],
|
|
||||||
std::string(attr.value->string_view()));
|
|
||||||
} else {
|
|
||||||
state.error<EvalError>(
|
|
||||||
"flake reference attribute sets may only contain integers, Booleans, "
|
|
||||||
"and strings, but attribute '%s' is %s",
|
|
||||||
state.symbols[attr.name],
|
|
||||||
showType(*attr.value)).debugThrow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto flakeRef = FlakeRef::fromAttrs(state.fetchSettings, attrs);
|
|
||||||
v.mkString(flakeRef.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
static RegisterPrimOp r4({
|
|
||||||
.name = "__flakeRefToString",
|
|
||||||
.args = {"attrs"},
|
|
||||||
.doc = R"(
|
|
||||||
Convert a flake reference from attribute set format to URL format.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
builtins.flakeRefToString {
|
|
||||||
dir = "lib"; owner = "NixOS"; ref = "23.05"; repo = "nixpkgs"; type = "github";
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
evaluates to
|
|
||||||
|
|
||||||
```nix
|
|
||||||
"github:NixOS/nixpkgs/23.05?dir=lib"
|
|
||||||
```
|
|
||||||
)",
|
|
||||||
.fun = prim_flakeRefToString,
|
|
||||||
.experimentalFeature = Xp::Flakes,
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Fingerprint> LockedFlake::getFingerprint(
|
std::optional<Fingerprint> LockedFlake::getFingerprint(
|
||||||
|
|
|
@ -14,14 +14,6 @@ namespace flake {
|
||||||
|
|
||||||
struct Settings;
|
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;
|
struct FlakeInput;
|
||||||
|
|
||||||
typedef std::map<FlakeId, FlakeInput> FlakeInputs;
|
typedef std::map<FlakeId, FlakeInput> FlakeInputs;
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
#include "flake/settings.hh"
|
#include "flake/settings.hh"
|
||||||
|
#include "flake/flake-primops.hh"
|
||||||
|
|
||||||
namespace nix::flake {
|
namespace nix::flake {
|
||||||
|
|
||||||
Settings::Settings() {}
|
Settings::Settings() {}
|
||||||
|
|
||||||
|
void Settings::configureEvalSettings(nix::EvalSettings & evalSettings) const
|
||||||
|
{
|
||||||
|
evalSettings.extraPrimOps.emplace_back(primops::getFlake(*this));
|
||||||
|
evalSettings.extraPrimOps.emplace_back(primops::parseFlakeRef);
|
||||||
|
evalSettings.extraPrimOps.emplace_back(primops::flakeRefToString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace nix
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
///@file
|
///@file
|
||||||
|
|
||||||
#include "types.hh"
|
|
||||||
#include "config.hh"
|
#include "config.hh"
|
||||||
#include "util.hh"
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
// Forward declarations
|
||||||
|
struct EvalSettings;
|
||||||
|
|
||||||
|
} // namespace nix
|
||||||
|
|
||||||
namespace nix::flake {
|
namespace nix::flake {
|
||||||
|
|
||||||
struct Settings : public Config
|
struct Settings : public Config
|
||||||
{
|
{
|
||||||
Settings();
|
Settings();
|
||||||
|
|
||||||
|
void configureEvalSettings(nix::EvalSettings & evalSettings) const;
|
||||||
|
|
||||||
Setting<bool> useRegistries{
|
Setting<bool> useRegistries{
|
||||||
this,
|
this,
|
||||||
true,
|
true,
|
||||||
|
|
|
@ -39,11 +39,21 @@ add_project_arguments(
|
||||||
|
|
||||||
subdir('nix-meson-build-support/common')
|
subdir('nix-meson-build-support/common')
|
||||||
|
|
||||||
|
subdir('nix-meson-build-support/generate-header')
|
||||||
|
|
||||||
|
generated_headers = []
|
||||||
|
foreach header : [
|
||||||
|
'call-flake.nix',
|
||||||
|
]
|
||||||
|
generated_headers += gen_header.process(header)
|
||||||
|
endforeach
|
||||||
|
|
||||||
sources = files(
|
sources = files(
|
||||||
'flake/config.cc',
|
'flake/config.cc',
|
||||||
'flake/flake.cc',
|
'flake/flake.cc',
|
||||||
'flake/flakeref.cc',
|
'flake/flakeref.cc',
|
||||||
'flake/lockfile.cc',
|
'flake/lockfile.cc',
|
||||||
|
'flake/flake-primops.cc',
|
||||||
'flake/settings.cc',
|
'flake/settings.cc',
|
||||||
'flake/url-name.cc',
|
'flake/url-name.cc',
|
||||||
)
|
)
|
||||||
|
@ -61,6 +71,7 @@ headers = files(
|
||||||
this_library = library(
|
this_library = library(
|
||||||
'nixflake',
|
'nixflake',
|
||||||
sources,
|
sources,
|
||||||
|
generated_headers,
|
||||||
dependencies : deps_public + deps_private + deps_other,
|
dependencies : deps_public + deps_private + deps_other,
|
||||||
prelink : true, # For C++ static initializers
|
prelink : true, # For C++ static initializers
|
||||||
install : true,
|
install : true,
|
||||||
|
|
|
@ -28,6 +28,7 @@ mkMesonLibrary (finalAttrs: {
|
||||||
../../.version
|
../../.version
|
||||||
./.version
|
./.version
|
||||||
./meson.build
|
./meson.build
|
||||||
|
./call-flake.nix
|
||||||
(fileset.fileFilter (file: file.hasExt "cc") ./.)
|
(fileset.fileFilter (file: file.hasExt "cc") ./.)
|
||||||
(fileset.fileFilter (file: file.hasExt "hh") ./.)
|
(fileset.fileFilter (file: file.hasExt "hh") ./.)
|
||||||
];
|
];
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "network-proxy.hh"
|
#include "network-proxy.hh"
|
||||||
#include "eval-cache.hh"
|
#include "eval-cache.hh"
|
||||||
#include "flake/flake.hh"
|
#include "flake/flake.hh"
|
||||||
|
#include "flake/settings.hh"
|
||||||
#include "self-exe.hh"
|
#include "self-exe.hh"
|
||||||
#include "json-utils.hh"
|
#include "json-utils.hh"
|
||||||
#include "crash-handler.hh"
|
#include "crash-handler.hh"
|
||||||
|
@ -368,7 +369,7 @@ void mainWrapped(int argc, char * * argv)
|
||||||
|
|
||||||
initNix();
|
initNix();
|
||||||
initGC();
|
initGC();
|
||||||
flake::initLib(flakeSettings);
|
flakeSettings.configureEvalSettings(evalSettings);
|
||||||
|
|
||||||
/* Set the build hook location
|
/* Set the build hook location
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue