1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-27 21:01:16 +02:00

libexpr-c: Add nix_eval_state_builder

This commit is contained in:
Robert Hensing 2024-11-22 16:24:20 +01:00
parent 838d3c1ad0
commit 82a23d9b6b
4 changed files with 183 additions and 9 deletions

View file

@ -6,6 +6,7 @@
#include "eval-gc.hh" #include "eval-gc.hh"
#include "globals.hh" #include "globals.hh"
#include "eval-settings.hh" #include "eval-settings.hh"
#include "ref.hh"
#include "nix_api_expr.h" #include "nix_api_expr.h"
#include "nix_api_expr_internal.h" #include "nix_api_expr_internal.h"
@ -93,7 +94,46 @@ nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, nix_val
NIXC_CATCH_ERRS NIXC_CATCH_ERRS
} }
EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath_c, Store * store) nix_eval_state_builder * nix_eval_state_builder_new(nix_c_context * context, Store * store)
{
if (context)
context->last_err_code = NIX_OK;
try {
// Allocate ahead of time, because .settings needs self-reference
void * p = ::operator new(
sizeof(nix_eval_state_builder),
static_cast<std::align_val_t>(alignof(nix_eval_state_builder)));
auto * p2 = static_cast<nix_eval_state_builder *>(p);
new (p) nix_eval_state_builder{
.store = nix::ref<nix::Store>(store->ptr),
.settings = nix::EvalSettings{/* &bool */ p2->readOnlyMode},
.fetchSettings = nix::fetchers::Settings{},
.readOnlyMode = true,
};
return p2;
}
NIXC_CATCH_ERRS_NULL
}
void nix_eval_state_builder_free(nix_eval_state_builder * builder)
{
delete builder;
}
nix_err nix_eval_state_builder_load(nix_c_context * context, nix_eval_state_builder * builder)
{
if (context)
context->last_err_code = NIX_OK;
try {
// TODO: load in one go?
builder->settings.readOnlyMode = nix::settings.readOnlyMode;
loadConfFile(builder->settings);
loadConfFile(builder->fetchSettings);
}
NIXC_CATCH_ERRS
}
nix_err nix_eval_state_builder_set_lookup_path(nix_c_context * context, nix_eval_state_builder * builder, const char ** lookupPath_c)
{ {
if (context) if (context)
context->last_err_code = NIX_OK; context->last_err_code = NIX_OK;
@ -102,28 +142,51 @@ EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath_c
if (lookupPath_c != nullptr) if (lookupPath_c != nullptr)
for (size_t i = 0; lookupPath_c[i] != nullptr; i++) for (size_t i = 0; lookupPath_c[i] != nullptr; i++)
lookupPath.push_back(lookupPath_c[i]); lookupPath.push_back(lookupPath_c[i]);
builder->lookupPath = nix::LookupPath::parse(lookupPath);
}
NIXC_CATCH_ERRS
}
EvalState * nix_eval_state_build(nix_c_context * context, nix_eval_state_builder * builder)
{
if (context)
context->last_err_code = NIX_OK;
try {
// Allocate ahead of time, because .state init needs self-reference
void * p = ::operator new( void * p = ::operator new(
sizeof(EvalState), sizeof(EvalState),
static_cast<std::align_val_t>(alignof(EvalState))); static_cast<std::align_val_t>(alignof(EvalState)));
auto * p2 = static_cast<EvalState *>(p); auto * p2 = static_cast<EvalState *>(p);
new (p) EvalState { new (p) EvalState {
.fetchSettings = nix::fetchers::Settings{}, .fetchSettings = std::move(builder->fetchSettings),
.settings = nix::EvalSettings{ .settings = std::move(builder->settings),
nix::settings.readOnlyMode,
},
.state = nix::EvalState( .state = nix::EvalState(
nix::LookupPath::parse(lookupPath), builder->lookupPath,
store->ptr, builder->store,
p2->fetchSettings, p2->fetchSettings,
p2->settings), p2->settings),
}; };
loadConfFile(p2->settings);
return p2; return p2;
} }
NIXC_CATCH_ERRS_NULL NIXC_CATCH_ERRS_NULL
} }
EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath_c, Store * store)
{
auto builder = nix_eval_state_builder_new(context, store);
if (builder == nullptr)
return nullptr;
if (nix_eval_state_builder_load(context, builder) != NIX_OK)
return nullptr;
if (nix_eval_state_builder_set_lookup_path(context, builder, lookupPath_c)
!= NIX_OK)
return nullptr;
return nix_eval_state_build(context, builder);
}
void nix_state_free(EvalState * state) void nix_state_free(EvalState * state)
{ {
delete state; delete state;

View file

@ -30,6 +30,11 @@ extern "C" {
// cffi start // cffi start
// Type definitions // Type definitions
/**
* @brief Builder for EvalState
*/
typedef struct nix_eval_state_builder nix_eval_state_builder;
/** /**
* @brief Represents a state of the Nix language evaluator. * @brief Represents a state of the Nix language evaluator.
* *
@ -174,12 +179,70 @@ nix_err nix_value_force(nix_c_context * context, EvalState * state, nix_value *
nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, nix_value * value); nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, nix_value * value);
/** /**
* @brief Create a new Nix language evaluator state. * @brief Create a new nix_eval_state_builder
*
* The settings are initialized to their default value.
* Values can be sourced elsewhere with nix_eval_state_builder_load.
*
* @param[out] context Optional, stores error information
* @param[in] store The Nix store to use.
* @return A new nix_eval_state_builder or NULL on failure.
*/
nix_eval_state_builder * nix_eval_state_builder_new(nix_c_context * context, Store * store);
/**
* @brief Read settings from the ambient environment
*
* Settings are sourced from environment variables and configuration files,
* as documented in the Nix manual.
*
* @param[out] context Optional, stores error information
* @param[out] builder The builder to modify.
* @return NIX_OK if successful, an error code otherwise.
*/
nix_err nix_eval_state_builder_load(nix_c_context * context, nix_eval_state_builder * builder);
/**
* @brief Set the lookup path for `<...>` expressions
*
* @param[in] context Optional, stores error information
* @param[in] builder The builder to modify.
* @param[in] lookupPath Null-terminated array of strings corresponding to entries in NIX_PATH.
*/
nix_err nix_eval_state_builder_set_lookup_path(
nix_c_context * context, nix_eval_state_builder * builder, const char ** lookupPath);
/**
* @brief Create a new Nix language evaluator state
*
* Remember to nix_eval_state_builder_free after building the state.
*
* @param[out] context Optional, stores error information
* @param[in] builder The builder to use and free
* @return A new Nix state or NULL on failure.
* @see nix_eval_state_builder_new, nix_eval_state_builder_free
*/
EvalState * nix_eval_state_build(nix_c_context * context, nix_eval_state_builder * builder);
/**
* @brief Free a nix_eval_state_builder
*
* Does not fail.
*
* @param[in] builder The builder to free.
*/
void nix_eval_state_builder_free(nix_eval_state_builder * builder);
/**
* @brief Create a new Nix language evaluator state
*
* For more control, use nix_eval_state_builder
* *
* @param[out] context Optional, stores error information * @param[out] context Optional, stores error information
* @param[in] lookupPath Null-terminated array of strings corresponding to entries in NIX_PATH. * @param[in] lookupPath Null-terminated array of strings corresponding to entries in NIX_PATH.
* @param[in] store The Nix store to use. * @param[in] store The Nix store to use.
* @return A new Nix state or NULL on failure. * @return A new Nix state or NULL on failure.
* @see nix_state_builder_new
*/ */
EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath, Store * store); EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath, Store * store);

View file

@ -6,6 +6,17 @@
#include "eval-settings.hh" #include "eval-settings.hh"
#include "attr-set.hh" #include "attr-set.hh"
#include "nix_api_value.h" #include "nix_api_value.h"
#include "search-path.hh"
struct nix_eval_state_builder
{
nix::ref<nix::Store> store;
nix::EvalSettings settings;
nix::fetchers::Settings fetchSettings;
nix::LookupPath lookupPath;
// TODO: make an EvalSettings setting own this instead?
bool readOnlyMode;
};
struct EvalState struct EvalState
{ {

View file

@ -7,12 +7,49 @@
#include "tests/nix_api_expr.hh" #include "tests/nix_api_expr.hh"
#include "tests/string_callback.hh" #include "tests/string_callback.hh"
#include "file-system.hh"
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
namespace nixC { namespace nixC {
TEST_F(nix_api_store_test, nix_eval_state_lookup_path)
{
auto tmpDir = nix::createTempDir();
auto delTmpDir = std::make_unique<nix::AutoDelete>(tmpDir, true);
auto nixpkgs = tmpDir + "/pkgs";
auto nixos = tmpDir + "/cfg";
std::filesystem::create_directories(nixpkgs);
std::filesystem::create_directories(nixos);
std::string nixpkgsEntry = "nixpkgs=" + nixpkgs;
std::string nixosEntry = "nixos-config=" + nixos;
const char * lookupPath[] = {nixpkgsEntry.c_str(), nixosEntry.c_str(), nullptr};
auto builder = nix_eval_state_builder_new(ctx, store);
assert_ctx_ok();
ASSERT_EQ(NIX_OK, nix_eval_state_builder_set_lookup_path(ctx, builder, lookupPath));
assert_ctx_ok();
auto state = nix_eval_state_build(ctx, builder);
assert_ctx_ok();
nix_eval_state_builder_free(builder);
Value * value = nix_alloc_value(ctx, state);
nix_expr_eval_from_string(ctx, state, "builtins.seq <nixos-config> <nixpkgs>", ".", value);
assert_ctx_ok();
ASSERT_EQ(nix_get_type(ctx, value), NIX_TYPE_PATH);
assert_ctx_ok();
auto pathStr = nix_get_path_string(ctx, value);
assert_ctx_ok();
ASSERT_EQ(0, strcmp(pathStr, nixpkgs.c_str()));
}
TEST_F(nix_api_expr_test, nix_expr_eval_from_string) TEST_F(nix_api_expr_test, nix_expr_eval_from_string)
{ {
nix_expr_eval_from_string(nullptr, state, "builtins.nixVersion", ".", value); nix_expr_eval_from_string(nullptr, state, "builtins.nixVersion", ".", value);