mirror of
https://github.com/NixOS/nix
synced 2025-07-08 02:43:54 +02:00
Merge remote-tracking branch 'origin/master' into relative-flakes
This commit is contained in:
commit
8534c4222c
263 changed files with 2129 additions and 805 deletions
|
@ -40,6 +40,7 @@ GENERATE_LATEX = NO
|
|||
INPUT = \
|
||||
@src@/src/libutil-c \
|
||||
@src@/src/libexpr-c \
|
||||
@src@/src/libflake-c \
|
||||
@src@/src/libstore-c \
|
||||
@src@/src/external-api-docs/README.md
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ mkMesonDerivation (finalAttrs: {
|
|||
# Source is not compiled, but still must be available for Doxygen
|
||||
# to gather comments.
|
||||
(cpp ../libexpr-c)
|
||||
(cpp ../libflake-c)
|
||||
(cpp ../libstore-c)
|
||||
(cpp ../libutil-c)
|
||||
];
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../build-utils-meson
|
|
@ -858,7 +858,7 @@ std::vector<FlakeRef> RawInstallablesCommand::getFlakeRefsForCompletion()
|
|||
applyDefaultInstallables(rawInstallables);
|
||||
std::vector<FlakeRef> res;
|
||||
res.reserve(rawInstallables.size());
|
||||
for (auto i : rawInstallables)
|
||||
for (const auto & i : rawInstallables)
|
||||
res.push_back(parseFlakeRefWithFragment(
|
||||
fetchSettings,
|
||||
expandTilde(i),
|
||||
|
|
|
@ -14,7 +14,7 @@ project('nix-cmd', 'cpp',
|
|||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('build-utils-meson/deps-lists')
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
configdata = configuration_data()
|
||||
|
||||
|
@ -28,7 +28,7 @@ deps_public_maybe_subproject = [
|
|||
dependency('nix-flake'),
|
||||
dependency('nix-main'),
|
||||
]
|
||||
subdir('build-utils-meson/subprojects')
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
nlohmann_json = dependency('nlohmann_json', version : '>= 3.9')
|
||||
deps_public += nlohmann_json
|
||||
|
@ -70,7 +70,7 @@ add_project_arguments(
|
|||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/common')
|
||||
subdir('nix-meson-build-support/common')
|
||||
|
||||
sources = files(
|
||||
'built-path.cc',
|
||||
|
@ -125,4 +125,4 @@ install_headers(headers, subdir : 'nix', preserve_path : true)
|
|||
|
||||
libraries_private = []
|
||||
|
||||
subdir('build-utils-meson/export')
|
||||
subdir('nix-meson-build-support/export')
|
||||
|
|
1
src/libcmd/nix-meson-build-support
Symbolic link
1
src/libcmd/nix-meson-build-support
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
|
@ -39,8 +39,8 @@ mkMesonLibrary (finalAttrs: {
|
|||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../build-utils-meson
|
||||
./build-utils-meson
|
||||
../../nix-meson-build-support
|
||||
./nix-meson-build-support
|
||||
../../.version
|
||||
./.version
|
||||
./meson.build
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../build-utils-meson
|
|
@ -14,7 +14,7 @@ project('nix-expr-c', 'cpp',
|
|||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('build-utils-meson/deps-lists')
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
configdata = configuration_data()
|
||||
|
||||
|
@ -27,7 +27,7 @@ deps_public_maybe_subproject = [
|
|||
dependency('nix-util-c'),
|
||||
dependency('nix-store-c'),
|
||||
]
|
||||
subdir('build-utils-meson/subprojects')
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
# TODO rename, because it will conflict with downstream projects
|
||||
configdata.set_quoted('PACKAGE_VERSION', meson.project_version())
|
||||
|
@ -53,7 +53,7 @@ add_project_arguments(
|
|||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/common')
|
||||
subdir('nix-meson-build-support/common')
|
||||
|
||||
sources = files(
|
||||
'nix_api_expr.cc',
|
||||
|
@ -72,8 +72,8 @@ headers = [config_h] + files(
|
|||
# TODO move this header to libexpr, maybe don't use it in tests?
|
||||
headers += files('nix_api_expr_internal.h')
|
||||
|
||||
subdir('build-utils-meson/export-all-symbols')
|
||||
subdir('build-utils-meson/windows-version')
|
||||
subdir('nix-meson-build-support/export-all-symbols')
|
||||
subdir('nix-meson-build-support/windows-version')
|
||||
|
||||
this_library = library(
|
||||
'nixexprc',
|
||||
|
@ -89,4 +89,4 @@ install_headers(headers, subdir : 'nix', preserve_path : true)
|
|||
|
||||
libraries_private = []
|
||||
|
||||
subdir('build-utils-meson/export')
|
||||
subdir('nix-meson-build-support/export')
|
||||
|
|
1
src/libexpr-c/nix-meson-build-support
Symbolic link
1
src/libexpr-c/nix-meson-build-support
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
|
@ -6,6 +6,7 @@
|
|||
#include "eval-gc.hh"
|
||||
#include "globals.hh"
|
||||
#include "eval-settings.hh"
|
||||
#include "ref.hh"
|
||||
|
||||
#include "nix_api_expr.h"
|
||||
#include "nix_api_expr_internal.h"
|
||||
|
@ -18,6 +19,29 @@
|
|||
# include <mutex>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Allocate and initialize using self-reference
|
||||
*
|
||||
* This allows a brace initializer to reference the object being constructed.
|
||||
*
|
||||
* @warning Use with care, as the pointer points to an object that is not fully constructed yet.
|
||||
*
|
||||
* @tparam T Type to allocate
|
||||
* @tparam F A function type for `init`, taking a T* and returning the initializer for T
|
||||
* @param init Function that takes a T* and returns the initializer for T
|
||||
* @return Pointer to allocated and initialized object
|
||||
*/
|
||||
template <typename T, typename F>
|
||||
static T * unsafe_new_with_self(F && init)
|
||||
{
|
||||
// Allocate
|
||||
void * p = ::operator new(
|
||||
sizeof(T),
|
||||
static_cast<std::align_val_t>(alignof(T)));
|
||||
// Initialize with placement new
|
||||
return new (p) T(init(static_cast<T *>(p)));
|
||||
}
|
||||
|
||||
nix_err nix_libexpr_init(nix_c_context * context)
|
||||
{
|
||||
if (context)
|
||||
|
@ -93,7 +117,42 @@ nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, nix_val
|
|||
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 {
|
||||
return unsafe_new_with_self<nix_eval_state_builder>([&](auto * self) {
|
||||
return nix_eval_state_builder{
|
||||
.store = nix::ref<nix::Store>(store->ptr),
|
||||
.settings = nix::EvalSettings{/* &bool */ self->readOnlyMode},
|
||||
.fetchSettings = nix::fetchers::Settings{},
|
||||
.readOnlyMode = true,
|
||||
};
|
||||
});
|
||||
}
|
||||
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)
|
||||
context->last_err_code = NIX_OK;
|
||||
|
@ -102,28 +161,47 @@ EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath_c
|
|||
if (lookupPath_c != nullptr)
|
||||
for (size_t i = 0; lookupPath_c[i] != nullptr; i++)
|
||||
lookupPath.push_back(lookupPath_c[i]);
|
||||
builder->lookupPath = nix::LookupPath::parse(lookupPath);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
void * p = ::operator new(
|
||||
sizeof(EvalState),
|
||||
static_cast<std::align_val_t>(alignof(EvalState)));
|
||||
auto * p2 = static_cast<EvalState *>(p);
|
||||
new (p) EvalState {
|
||||
.fetchSettings = nix::fetchers::Settings{},
|
||||
.settings = nix::EvalSettings{
|
||||
nix::settings.readOnlyMode,
|
||||
},
|
||||
.state = nix::EvalState(
|
||||
nix::LookupPath::parse(lookupPath),
|
||||
store->ptr,
|
||||
p2->fetchSettings,
|
||||
p2->settings),
|
||||
};
|
||||
loadConfFile(p2->settings);
|
||||
return p2;
|
||||
EvalState * nix_eval_state_build(nix_c_context * context, nix_eval_state_builder * builder)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
return unsafe_new_with_self<EvalState>([&](auto * self) {
|
||||
return EvalState{
|
||||
.fetchSettings = std::move(builder->fetchSettings),
|
||||
.settings = std::move(builder->settings),
|
||||
.state = nix::EvalState(
|
||||
builder->lookupPath,
|
||||
builder->store,
|
||||
self->fetchSettings,
|
||||
self->settings),
|
||||
};
|
||||
});
|
||||
}
|
||||
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)
|
||||
{
|
||||
delete state;
|
||||
|
|
|
@ -30,6 +30,11 @@ extern "C" {
|
|||
// cffi start
|
||||
|
||||
// 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.
|
||||
*
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
* @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[in] lookupPath Null-terminated array of strings corresponding to entries in NIX_PATH.
|
||||
* @param[in] store The Nix store to use.
|
||||
* @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);
|
||||
|
||||
|
|
|
@ -6,6 +6,17 @@
|
|||
#include "eval-settings.hh"
|
||||
#include "attr-set.hh"
|
||||
#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
|
||||
{
|
||||
|
|
|
@ -213,7 +213,7 @@ nix_get_string(nix_c_context * context, const nix_value * value, nix_get_string_
|
|||
/** @brief Get path as string
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return string
|
||||
* @return string, if the type is NIX_TYPE_PATH
|
||||
* @return NULL in case of error.
|
||||
*/
|
||||
const char * nix_get_path_string(nix_c_context * context, const nix_value * value);
|
||||
|
|
|
@ -20,8 +20,8 @@ mkMesonLibrary (finalAttrs: {
|
|||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../build-utils-meson
|
||||
./build-utils-meson
|
||||
../../nix-meson-build-support
|
||||
./nix-meson-build-support
|
||||
../../.version
|
||||
./.version
|
||||
./meson.build
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../build-utils-meson
|
|
@ -14,7 +14,7 @@ project('nix-expr-test-support', 'cpp',
|
|||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('build-utils-meson/deps-lists')
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
deps_private_maybe_subproject = [
|
||||
]
|
||||
|
@ -24,8 +24,9 @@ deps_public_maybe_subproject = [
|
|||
dependency('nix-store'),
|
||||
dependency('nix-store-test-support'),
|
||||
dependency('nix-expr'),
|
||||
dependency('nix-expr-c'),
|
||||
]
|
||||
subdir('build-utils-meson/subprojects')
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
rapidcheck = dependency('rapidcheck')
|
||||
deps_public += rapidcheck
|
||||
|
@ -39,7 +40,7 @@ add_project_arguments(
|
|||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/common')
|
||||
subdir('nix-meson-build-support/common')
|
||||
|
||||
sources = files(
|
||||
'tests/value/context.cc',
|
||||
|
@ -53,8 +54,8 @@ headers = files(
|
|||
'tests/value/context.hh',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/export-all-symbols')
|
||||
subdir('build-utils-meson/windows-version')
|
||||
subdir('nix-meson-build-support/export-all-symbols')
|
||||
subdir('nix-meson-build-support/windows-version')
|
||||
|
||||
this_library = library(
|
||||
'nix-expr-test-support',
|
||||
|
@ -72,4 +73,4 @@ install_headers(headers, subdir : 'nix', preserve_path : true)
|
|||
|
||||
libraries_private = []
|
||||
|
||||
subdir('build-utils-meson/export')
|
||||
subdir('nix-meson-build-support/export')
|
||||
|
|
1
src/libexpr-test-support/nix-meson-build-support
Symbolic link
1
src/libexpr-test-support/nix-meson-build-support
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
, nix-store-test-support
|
||||
, nix-expr
|
||||
, nix-expr-c
|
||||
|
||||
, rapidcheck
|
||||
|
||||
|
@ -22,8 +23,8 @@ mkMesonLibrary (finalAttrs: {
|
|||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../build-utils-meson
|
||||
./build-utils-meson
|
||||
../../nix-meson-build-support
|
||||
./nix-meson-build-support
|
||||
../../.version
|
||||
./.version
|
||||
./meson.build
|
||||
|
@ -35,6 +36,7 @@ mkMesonLibrary (finalAttrs: {
|
|||
propagatedBuildInputs = [
|
||||
nix-store-test-support
|
||||
nix-expr
|
||||
nix-expr-c
|
||||
rapidcheck
|
||||
];
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../build-utils-meson
|
|
@ -691,15 +691,15 @@ namespace nix {
|
|||
ASSERT_TRACE2("elemAt \"foo\" (-1)",
|
||||
TypeError,
|
||||
HintFmt("expected a list but found %s: %s", "a string", Uncolored(ANSI_MAGENTA "\"foo\"" ANSI_NORMAL)),
|
||||
HintFmt("while evaluating the first argument passed to builtins.elemAt"));
|
||||
HintFmt("while evaluating the first argument passed to 'builtins.elemAt'"));
|
||||
|
||||
ASSERT_TRACE1("elemAt [] (-1)",
|
||||
Error,
|
||||
HintFmt("list index %d is out of bounds", -1));
|
||||
HintFmt("'builtins.elemAt' called with index %d on a list of size %d", -1, 0));
|
||||
|
||||
ASSERT_TRACE1("elemAt [\"foo\"] 3",
|
||||
Error,
|
||||
HintFmt("list index %d is out of bounds", 3));
|
||||
HintFmt("'builtins.elemAt' called with index %d on a list of size %d", 3, 1));
|
||||
|
||||
}
|
||||
|
||||
|
@ -708,11 +708,11 @@ namespace nix {
|
|||
ASSERT_TRACE2("head 1",
|
||||
TypeError,
|
||||
HintFmt("expected a list but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)),
|
||||
HintFmt("while evaluating the first argument passed to builtins.elemAt"));
|
||||
HintFmt("while evaluating the first argument passed to 'builtins.head'"));
|
||||
|
||||
ASSERT_TRACE1("head []",
|
||||
Error,
|
||||
HintFmt("list index %d is out of bounds", 0));
|
||||
HintFmt("'builtins.head' called on an empty list"));
|
||||
|
||||
}
|
||||
|
||||
|
@ -721,11 +721,11 @@ namespace nix {
|
|||
ASSERT_TRACE2("tail 1",
|
||||
TypeError,
|
||||
HintFmt("expected a list but found %s: %s", "an integer", Uncolored(ANSI_CYAN "1" ANSI_NORMAL)),
|
||||
HintFmt("while evaluating the first argument passed to builtins.tail"));
|
||||
HintFmt("while evaluating the first argument passed to 'builtins.tail'"));
|
||||
|
||||
ASSERT_TRACE1("tail []",
|
||||
Error,
|
||||
HintFmt("'tail' called on an empty list"));
|
||||
HintFmt("'builtins.tail' called on an empty list"));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ project('nix-expr-tests', 'cpp',
|
|||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('build-utils-meson/deps-lists')
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
deps_private_maybe_subproject = [
|
||||
dependency('nix-expr'),
|
||||
|
@ -23,10 +23,10 @@ deps_private_maybe_subproject = [
|
|||
]
|
||||
deps_public_maybe_subproject = [
|
||||
]
|
||||
subdir('build-utils-meson/subprojects')
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
subdir('build-utils-meson/export-all-symbols')
|
||||
subdir('build-utils-meson/windows-version')
|
||||
subdir('nix-meson-build-support/export-all-symbols')
|
||||
subdir('nix-meson-build-support/windows-version')
|
||||
|
||||
rapidcheck = dependency('rapidcheck')
|
||||
deps_private += rapidcheck
|
||||
|
@ -49,7 +49,7 @@ add_project_arguments(
|
|||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/common')
|
||||
subdir('nix-meson-build-support/common')
|
||||
|
||||
sources = files(
|
||||
'derived-path.cc',
|
||||
|
|
1
src/libexpr-tests/nix-meson-build-support
Symbolic link
1
src/libexpr-tests/nix-meson-build-support
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
|
@ -7,12 +7,49 @@
|
|||
|
||||
#include "tests/nix_api_expr.hh"
|
||||
#include "tests/string_callback.hh"
|
||||
#include "file-system.hh"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
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)
|
||||
{
|
||||
nix_expr_eval_from_string(nullptr, state, "builtins.nixVersion", ".", value);
|
||||
|
|
|
@ -27,8 +27,8 @@ mkMesonExecutable (finalAttrs: {
|
|||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../build-utils-meson
|
||||
./build-utils-meson
|
||||
../../nix-meson-build-support
|
||||
./nix-meson-build-support
|
||||
../../.version
|
||||
./.version
|
||||
./meson.build
|
||||
|
|
|
@ -177,6 +177,57 @@ namespace nix {
|
|||
)
|
||||
);
|
||||
|
||||
// The following macros ultimately define 48 tests (16 variations on three
|
||||
// templates). Each template tests an expression that can be written in 2^4
|
||||
// different ways, by making four choices about whether to write a particular
|
||||
// attribute path segment as `x.y = ...;` (collapsed) or `x = { y = ...; };`
|
||||
// (expanded).
|
||||
//
|
||||
// The nestedAttrsetMergeXXXX tests check that the expression
|
||||
// `{ a.b.c = 1; a.b.d = 2; }` has the same value regardless of how it is
|
||||
// expanded. (That exact expression is exercised in test
|
||||
// nestedAttrsetMerge0000, because it is fully collapsed. The test
|
||||
// nestedAttrsetMerge1001 would instead examine
|
||||
// `{ a = { b.c = 1; }; a.b = { d = 2; }; }`.)
|
||||
//
|
||||
// The nestedAttrsetMergeDupXXXX tests check that the expression
|
||||
// `{ a.b.c = 1; a.b.c = 2; }` throws a duplicate attribute error, again
|
||||
// regardless of how it is expanded.
|
||||
//
|
||||
// The nestedAttrsetMergeLetXXXX tests check that the expression
|
||||
// `let a.b.c = 1; a.b.d = 2; in a` has the same value regardless of how it is
|
||||
// expanded.
|
||||
#define X_EXPAND_IF0(k, v) k "." v
|
||||
#define X_EXPAND_IF1(k, v) k " = { " v " };"
|
||||
#define X4(w, x, y, z) \
|
||||
TEST_F(TrivialExpressionTest, nestedAttrsetMerge##w##x##y##z) { \
|
||||
auto v = eval("{ a.b = { c = 1; d = 2; }; } == { " \
|
||||
X_EXPAND_IF##w("a", X_EXPAND_IF##x("b", "c = 1;")) " " \
|
||||
X_EXPAND_IF##y("a", X_EXPAND_IF##z("b", "d = 2;")) " }"); \
|
||||
ASSERT_THAT(v, IsTrue()); \
|
||||
}; \
|
||||
TEST_F(TrivialExpressionTest, nestedAttrsetMergeDup##w##x##y##z) { \
|
||||
ASSERT_THROW(eval("{ " \
|
||||
X_EXPAND_IF##w("a", X_EXPAND_IF##x("b", "c = 1;")) " " \
|
||||
X_EXPAND_IF##y("a", X_EXPAND_IF##z("b", "c = 2;")) " }"), Error); \
|
||||
}; \
|
||||
TEST_F(TrivialExpressionTest, nestedAttrsetMergeLet##w##x##y##z) { \
|
||||
auto v = eval("{ b = { c = 1; d = 2; }; } == (let " \
|
||||
X_EXPAND_IF##w("a", X_EXPAND_IF##x("b", "c = 1;")) " " \
|
||||
X_EXPAND_IF##y("a", X_EXPAND_IF##z("b", "d = 2;")) " in a)"); \
|
||||
ASSERT_THAT(v, IsTrue()); \
|
||||
};
|
||||
#define X3(...) X4(__VA_ARGS__, 0) X4(__VA_ARGS__, 1)
|
||||
#define X2(...) X3(__VA_ARGS__, 0) X3(__VA_ARGS__, 1)
|
||||
#define X1(...) X2(__VA_ARGS__, 0) X2(__VA_ARGS__, 1)
|
||||
X1(0) X1(1)
|
||||
#undef X_EXPAND_IF0
|
||||
#undef X_EXPAND_IF1
|
||||
#undef X1
|
||||
#undef X2
|
||||
#undef X3
|
||||
#undef X4
|
||||
|
||||
TEST_F(TrivialExpressionTest, functor) {
|
||||
auto v = eval("{ __functor = self: arg: self.v + arg; v = 10; } 5");
|
||||
ASSERT_THAT(v, IsIntEq(15));
|
||||
|
|
|
@ -129,7 +129,6 @@ std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v
|
|||
try {
|
||||
auto colon = fn.rfind(':');
|
||||
if (colon == std::string::npos) fail();
|
||||
std::string filename(fn, 0, colon);
|
||||
auto lineno = std::stoi(std::string(fn, colon + 1, std::string::npos));
|
||||
return {SourcePath{path.accessor, CanonPath(fn.substr(0, colon))}, lineno};
|
||||
} catch (std::invalid_argument & e) {
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../build-utils-meson
|
|
@ -347,6 +347,16 @@ void EvalState::allowPath(const StorePath & storePath)
|
|||
rootFS2->allowPrefix(CanonPath(store->toRealPath(storePath)));
|
||||
}
|
||||
|
||||
void EvalState::allowClosure(const StorePath & storePath)
|
||||
{
|
||||
if (!rootFS.dynamic_pointer_cast<AllowListSourceAccessor>()) return;
|
||||
|
||||
StorePathSet closure;
|
||||
store->computeFSClosure(storePath, closure);
|
||||
for (auto & p : closure)
|
||||
allowPath(p);
|
||||
}
|
||||
|
||||
void EvalState::allowAndSetStorePathString(const StorePath & storePath, Value & v)
|
||||
{
|
||||
allowPath(storePath);
|
||||
|
@ -3099,10 +3109,7 @@ std::optional<SourcePath> EvalState::resolveLookupPathPath(const LookupPath::Pat
|
|||
allowPath(path.path.abs());
|
||||
if (store->isInStore(path.path.abs())) {
|
||||
try {
|
||||
StorePathSet closure;
|
||||
store->computeFSClosure(store->toStorePath(path.path.abs()).first, closure);
|
||||
for (auto & p : closure)
|
||||
allowPath(p);
|
||||
allowClosure(store->toStorePath(path.path.abs()).first);
|
||||
} catch (InvalidPath &) { }
|
||||
}
|
||||
}
|
||||
|
@ -3178,5 +3185,14 @@ std::ostream & operator << (std::ostream & str, const ExternalValueBase & v) {
|
|||
return v.print(str);
|
||||
}
|
||||
|
||||
void forceNoNullByte(std::string_view s)
|
||||
{
|
||||
if (s.find('\0') != s.npos) {
|
||||
using namespace std::string_view_literals;
|
||||
auto str = replaceStrings(std::string(s), "\0"sv, "␀"sv);
|
||||
throw Error("input string '%s' cannot be represented as Nix string because it contains null bytes", str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -400,6 +400,11 @@ public:
|
|||
*/
|
||||
void allowPath(const StorePath & storePath);
|
||||
|
||||
/**
|
||||
* Allow access to the closure of a store path.
|
||||
*/
|
||||
void allowClosure(const StorePath & storePath);
|
||||
|
||||
/**
|
||||
* Allow access to a store path and return it as a string.
|
||||
*/
|
||||
|
|
|
@ -50,6 +50,7 @@ class JSONSax : nlohmann::json_sax<json> {
|
|||
public:
|
||||
void key(string_t & name, EvalState & state)
|
||||
{
|
||||
forceNoNullByte(name);
|
||||
attrs.insert_or_assign(state.symbols.create(name), &value(state));
|
||||
}
|
||||
};
|
||||
|
@ -122,6 +123,7 @@ public:
|
|||
|
||||
bool string(string_t & val) override
|
||||
{
|
||||
forceNoNullByte(val);
|
||||
rs->value(state).mkString(val);
|
||||
rs->add();
|
||||
return true;
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
// inluding the generated headers twice leads to errors
|
||||
#ifndef BISON_HEADER
|
||||
# include "lexer-tab.hh"
|
||||
# include "parser-tab.hh"
|
||||
#endif
|
||||
|
||||
namespace nix::lexer::internal {
|
||||
|
||||
void initLoc(YYLTYPE * loc);
|
||||
|
|
|
@ -14,7 +14,7 @@ project('nix-expr', 'cpp',
|
|||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('build-utils-meson/deps-lists')
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
configdata = configuration_data()
|
||||
|
||||
|
@ -25,7 +25,7 @@ deps_public_maybe_subproject = [
|
|||
dependency('nix-store'),
|
||||
dependency('nix-fetchers'),
|
||||
]
|
||||
subdir('build-utils-meson/subprojects')
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
boost = dependency(
|
||||
'boost',
|
||||
|
@ -77,7 +77,7 @@ add_project_arguments(
|
|||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/common')
|
||||
subdir('nix-meson-build-support/common')
|
||||
|
||||
parser_tab = custom_target(
|
||||
input : 'parser.y',
|
||||
|
@ -121,7 +121,7 @@ lexer_tab = custom_target(
|
|||
install_dir : get_option('includedir') / 'nix',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/generate-header')
|
||||
subdir('nix-meson-build-support/generate-header')
|
||||
|
||||
generated_headers = []
|
||||
foreach header : [
|
||||
|
@ -205,4 +205,4 @@ install_headers(headers, subdir : 'nix', preserve_path : true)
|
|||
|
||||
libraries_private = []
|
||||
|
||||
subdir('build-utils-meson/export')
|
||||
subdir('nix-meson-build-support/export')
|
||||
|
|
1
src/libexpr/nix-meson-build-support
Symbolic link
1
src/libexpr/nix-meson-build-support
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
|
@ -168,7 +168,7 @@ struct ExprVar : Expr
|
|||
the set stored in the environment that is `level` levels up
|
||||
from the current one.*/
|
||||
Level level;
|
||||
Displacement displ;
|
||||
Displacement displ = 0;
|
||||
|
||||
ExprVar(Symbol name) : name(name) { };
|
||||
ExprVar(const PosIdx & pos, Symbol name) : pos(pos), name(name) { };
|
||||
|
@ -242,7 +242,7 @@ struct ExprAttrs : Expr
|
|||
Kind kind;
|
||||
Expr * e;
|
||||
PosIdx pos;
|
||||
Displacement displ; // displacement
|
||||
Displacement displ = 0; // displacement
|
||||
AttrDef(Expr * e, const PosIdx & pos, Kind kind = Kind::Plain)
|
||||
: kind(kind), e(e), pos(pos) { };
|
||||
AttrDef() { };
|
||||
|
|
|
@ -40,8 +40,8 @@ mkMesonLibrary (finalAttrs: {
|
|||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../build-utils-meson
|
||||
./build-utils-meson
|
||||
../../nix-meson-build-support
|
||||
./nix-meson-build-support
|
||||
../../.version
|
||||
./.version
|
||||
./meson.build
|
||||
|
|
|
@ -88,6 +88,7 @@ struct ParserState
|
|||
void dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos);
|
||||
void dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos);
|
||||
void addAttr(ExprAttrs * attrs, AttrPath && attrPath, const ParserLocation & loc, Expr * e, const ParserLocation & exprLoc);
|
||||
void addAttr(ExprAttrs * attrs, AttrPath & attrPath, const Symbol & symbol, ExprAttrs::AttrDef && def);
|
||||
Formals * validateFormals(Formals * formals, PosIdx pos = noPos, Symbol arg = {});
|
||||
Expr * stripIndentation(const PosIdx pos,
|
||||
std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken>>> && es);
|
||||
|
@ -120,64 +121,29 @@ inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, const
|
|||
// Checking attrPath validity.
|
||||
// ===========================
|
||||
for (i = attrPath.begin(); i + 1 < attrPath.end(); i++) {
|
||||
ExprAttrs * nested;
|
||||
if (i->symbol) {
|
||||
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
|
||||
if (j != attrs->attrs.end()) {
|
||||
if (j->second.kind != ExprAttrs::AttrDef::Kind::Inherited) {
|
||||
ExprAttrs * attrs2 = dynamic_cast<ExprAttrs *>(j->second.e);
|
||||
if (!attrs2) dupAttr(attrPath, pos, j->second.pos);
|
||||
attrs = attrs2;
|
||||
} else
|
||||
nested = dynamic_cast<ExprAttrs *>(j->second.e);
|
||||
if (!nested) {
|
||||
attrPath.erase(i + 1, attrPath.end());
|
||||
dupAttr(attrPath, pos, j->second.pos);
|
||||
}
|
||||
} else {
|
||||
ExprAttrs * nested = new ExprAttrs;
|
||||
nested = new ExprAttrs;
|
||||
attrs->attrs[i->symbol] = ExprAttrs::AttrDef(nested, pos);
|
||||
attrs = nested;
|
||||
}
|
||||
} else {
|
||||
ExprAttrs *nested = new ExprAttrs;
|
||||
nested = new ExprAttrs;
|
||||
attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, nested, pos));
|
||||
attrs = nested;
|
||||
}
|
||||
attrs = nested;
|
||||
}
|
||||
// Expr insertion.
|
||||
// ==========================
|
||||
if (i->symbol) {
|
||||
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(i->symbol);
|
||||
if (j != attrs->attrs.end()) {
|
||||
// This attr path is already defined. However, if both
|
||||
// e and the expr pointed by the attr path are two attribute sets,
|
||||
// we want to merge them.
|
||||
// Otherwise, throw an error.
|
||||
auto ae = dynamic_cast<ExprAttrs *>(e);
|
||||
auto jAttrs = dynamic_cast<ExprAttrs *>(j->second.e);
|
||||
if (jAttrs && ae) {
|
||||
if (ae->inheritFromExprs && !jAttrs->inheritFromExprs)
|
||||
jAttrs->inheritFromExprs = std::make_unique<std::vector<Expr *>>();
|
||||
for (auto & ad : ae->attrs) {
|
||||
auto j2 = jAttrs->attrs.find(ad.first);
|
||||
if (j2 != jAttrs->attrs.end()) // Attr already defined in iAttrs, error.
|
||||
dupAttr(ad.first, j2->second.pos, ad.second.pos);
|
||||
jAttrs->attrs.emplace(ad.first, ad.second);
|
||||
if (ad.second.kind == ExprAttrs::AttrDef::Kind::InheritedFrom) {
|
||||
auto & sel = dynamic_cast<ExprSelect &>(*ad.second.e);
|
||||
auto & from = dynamic_cast<ExprInheritFrom &>(*sel.e);
|
||||
from.displ += jAttrs->inheritFromExprs->size();
|
||||
}
|
||||
}
|
||||
jAttrs->dynamicAttrs.insert(jAttrs->dynamicAttrs.end(), ae->dynamicAttrs.begin(), ae->dynamicAttrs.end());
|
||||
if (ae->inheritFromExprs) {
|
||||
jAttrs->inheritFromExprs->insert(jAttrs->inheritFromExprs->end(),
|
||||
ae->inheritFromExprs->begin(), ae->inheritFromExprs->end());
|
||||
}
|
||||
} else {
|
||||
dupAttr(attrPath, pos, j->second.pos);
|
||||
}
|
||||
} else {
|
||||
// This attr path is not defined. Let's create it.
|
||||
attrs->attrs.emplace(i->symbol, ExprAttrs::AttrDef(e, pos));
|
||||
e->setName(i->symbol);
|
||||
}
|
||||
addAttr(attrs, attrPath, i->symbol, ExprAttrs::AttrDef(e, pos));
|
||||
} else {
|
||||
attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, e, pos));
|
||||
}
|
||||
|
@ -189,6 +155,60 @@ inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, const
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Precondition: attrPath is used for error messages and should already contain
|
||||
* symbol as its last element.
|
||||
*/
|
||||
inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath & attrPath, const Symbol & symbol, ExprAttrs::AttrDef && def)
|
||||
{
|
||||
ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(symbol);
|
||||
if (j != attrs->attrs.end()) {
|
||||
// This attr path is already defined. However, if both
|
||||
// e and the expr pointed by the attr path are two attribute sets,
|
||||
// we want to merge them.
|
||||
// Otherwise, throw an error.
|
||||
auto ae = dynamic_cast<ExprAttrs *>(def.e);
|
||||
auto jAttrs = dynamic_cast<ExprAttrs *>(j->second.e);
|
||||
|
||||
// N.B. In a world in which we are less bound by our past mistakes, we
|
||||
// would also test that jAttrs and ae are not recursive. The effect of
|
||||
// not doing so is that any `rec` marker on ae is discarded, and any
|
||||
// `rec` marker on jAttrs will apply to the attributes in ae.
|
||||
// See https://github.com/NixOS/nix/issues/9020.
|
||||
if (jAttrs && ae) {
|
||||
if (ae->inheritFromExprs && !jAttrs->inheritFromExprs)
|
||||
jAttrs->inheritFromExprs = std::make_unique<std::vector<Expr *>>();
|
||||
for (auto & ad : ae->attrs) {
|
||||
if (ad.second.kind == ExprAttrs::AttrDef::Kind::InheritedFrom) {
|
||||
auto & sel = dynamic_cast<ExprSelect &>(*ad.second.e);
|
||||
auto & from = dynamic_cast<ExprInheritFrom &>(*sel.e);
|
||||
from.displ += jAttrs->inheritFromExprs->size();
|
||||
}
|
||||
attrPath.emplace_back(AttrName(ad.first));
|
||||
addAttr(jAttrs, attrPath, ad.first, std::move(ad.second));
|
||||
attrPath.pop_back();
|
||||
}
|
||||
ae->attrs.clear();
|
||||
jAttrs->dynamicAttrs.insert(jAttrs->dynamicAttrs.end(),
|
||||
std::make_move_iterator(ae->dynamicAttrs.begin()),
|
||||
std::make_move_iterator(ae->dynamicAttrs.end()));
|
||||
ae->dynamicAttrs.clear();
|
||||
if (ae->inheritFromExprs) {
|
||||
jAttrs->inheritFromExprs->insert(jAttrs->inheritFromExprs->end(),
|
||||
std::make_move_iterator(ae->inheritFromExprs->begin()),
|
||||
std::make_move_iterator(ae->inheritFromExprs->end()));
|
||||
ae->inheritFromExprs = nullptr;
|
||||
}
|
||||
} else {
|
||||
dupAttr(attrPath, def.pos, j->second.pos);
|
||||
}
|
||||
} else {
|
||||
// This attr path is not defined. Let's create it.
|
||||
attrs->attrs.emplace(symbol, def);
|
||||
def.e->setName(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
inline Formals * ParserState::validateFormals(Formals * formals, PosIdx pos, Symbol arg)
|
||||
{
|
||||
std::sort(formals->formals.begin(), formals->formals.end(),
|
||||
|
|
|
@ -66,14 +66,12 @@ StringMap EvalState::realiseContext(const NixStringContext & context, StorePathS
|
|||
ensureValid(b.drvPath->getBaseStorePath());
|
||||
},
|
||||
[&](const NixStringContextElem::Opaque & o) {
|
||||
auto ctxS = store->printStorePath(o.path);
|
||||
ensureValid(o.path);
|
||||
if (maybePathsOut)
|
||||
maybePathsOut->emplace(o.path);
|
||||
},
|
||||
[&](const NixStringContextElem::DrvDeep & d) {
|
||||
/* Treat same as Opaque */
|
||||
auto ctxS = store->printStorePath(d.drvPath);
|
||||
ensureValid(d.drvPath);
|
||||
if (maybePathsOut)
|
||||
maybePathsOut->emplace(d.drvPath);
|
||||
|
@ -121,11 +119,9 @@ StringMap EvalState::realiseContext(const NixStringContext & context, StorePathS
|
|||
if (store != buildStore) copyClosure(*buildStore, *store, outputsToCopyAndAllow);
|
||||
|
||||
if (isIFD) {
|
||||
for (auto & outputPath : outputsToCopyAndAllow) {
|
||||
/* Add the output of this derivations to the allowed
|
||||
paths. */
|
||||
allowPath(outputPath);
|
||||
}
|
||||
/* Allow access to the output closures of this derivation. */
|
||||
for (auto & outputPath : outputsToCopyAndAllow)
|
||||
allowClosure(outputPath);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -1102,7 +1098,7 @@ static RegisterPrimOp primop_warn({
|
|||
.name = "__warn",
|
||||
.args = {"e1", "e2"},
|
||||
.doc = R"(
|
||||
Evaluate *e1*, which must be a string and print iton standard error as a warning.
|
||||
Evaluate *e1*, which must be a string, and print it on standard error as a warning.
|
||||
Then return *e2*.
|
||||
This function is useful for non-critical situations where attention is advisable.
|
||||
|
||||
|
@ -3261,23 +3257,19 @@ static RegisterPrimOp primop_isList({
|
|||
.fun = prim_isList,
|
||||
});
|
||||
|
||||
static void elemAt(EvalState & state, const PosIdx pos, Value & list, int n, Value & v)
|
||||
{
|
||||
state.forceList(list, pos, "while evaluating the first argument passed to builtins.elemAt");
|
||||
if (n < 0 || (unsigned int) n >= list.listSize())
|
||||
state.error<EvalError>(
|
||||
"list index %1% is out of bounds",
|
||||
n
|
||||
).atPos(pos).debugThrow();
|
||||
state.forceValue(*list.listElems()[n], pos);
|
||||
v = *list.listElems()[n];
|
||||
}
|
||||
|
||||
/* Return the n-1'th element of a list. */
|
||||
static void prim_elemAt(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
NixInt::Inner elem = state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.elemAt").value;
|
||||
elemAt(state, pos, *args[0], elem, v);
|
||||
NixInt::Inner n = state.forceInt(*args[1], pos, "while evaluating the second argument passed to 'builtins.elemAt'").value;
|
||||
state.forceList(*args[0], pos, "while evaluating the first argument passed to 'builtins.elemAt'");
|
||||
if (n < 0 || (unsigned int) n >= args[0]->listSize())
|
||||
state.error<EvalError>(
|
||||
"'builtins.elemAt' called with index %d on a list of size %d",
|
||||
n,
|
||||
args[0]->listSize()
|
||||
).atPos(pos).debugThrow();
|
||||
state.forceValue(*args[0]->listElems()[n], pos);
|
||||
v = *args[0]->listElems()[n];
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_elemAt({
|
||||
|
@ -3293,7 +3285,13 @@ static RegisterPrimOp primop_elemAt({
|
|||
/* Return the first element of a list. */
|
||||
static void prim_head(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
elemAt(state, pos, *args[0], 0, v);
|
||||
state.forceList(*args[0], pos, "while evaluating the first argument passed to 'builtins.head'");
|
||||
if (args[0]->listSize() == 0)
|
||||
state.error<EvalError>(
|
||||
"'builtins.head' called on an empty list"
|
||||
).atPos(pos).debugThrow();
|
||||
state.forceValue(*args[0]->listElems()[0], pos);
|
||||
v = *args[0]->listElems()[0];
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_head({
|
||||
|
@ -3312,9 +3310,9 @@ static RegisterPrimOp primop_head({
|
|||
don't want to use it! */
|
||||
static void prim_tail(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
state.forceList(*args[0], pos, "while evaluating the first argument passed to builtins.tail");
|
||||
state.forceList(*args[0], pos, "while evaluating the first argument passed to 'builtins.tail'");
|
||||
if (args[0]->listSize() == 0)
|
||||
state.error<EvalError>("'tail' called on an empty list").atPos(pos).debugThrow();
|
||||
state.error<EvalError>("'builtins.tail' called on an empty list").atPos(pos).debugThrow();
|
||||
|
||||
auto list = state.buildList(args[0]->listSize() - 1);
|
||||
for (const auto & [n, v] : enumerate(list))
|
||||
|
@ -4385,7 +4383,7 @@ void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
|||
|
||||
for (auto i = begin; i != end; ++i) {
|
||||
assert(idx <= 2 * len + 1 - 3);
|
||||
auto match = *i;
|
||||
const auto & match = *i;
|
||||
|
||||
// Add a string for non-matched characters.
|
||||
list[idx++] = mkString(state, match.prefix());
|
||||
|
|
|
@ -132,6 +132,8 @@ static void prim_addDrvOutputDependencies(EvalState & state, const PosIdx pos, V
|
|||
},
|
||||
[&](const NixStringContextElem::DrvDeep & c) -> NixStringContextElem::DrvDeep {
|
||||
/* Reuse original item because we want this to be idempotent. */
|
||||
/* FIXME: Suspicious move out of const. This is actually a copy, so the comment
|
||||
above does not make much sense. */
|
||||
return std::move(c);
|
||||
},
|
||||
}, context.begin()->raw) }),
|
||||
|
|
|
@ -40,7 +40,7 @@ static void runFetchClosureWithRewrite(EvalState & state, const PosIdx pos, Stor
|
|||
});
|
||||
}
|
||||
|
||||
auto toPath = *toPathMaybe;
|
||||
const auto & toPath = *toPathMaybe;
|
||||
|
||||
// check and return
|
||||
|
||||
|
|
|
@ -28,8 +28,10 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value * * args, V
|
|||
|
||||
auto attrs = state.buildBindings(size);
|
||||
|
||||
for(auto & elem : table)
|
||||
for(auto & elem : table) {
|
||||
forceNoNullByte(elem.first);
|
||||
visit(attrs.alloc(elem.first), elem.second);
|
||||
}
|
||||
|
||||
v.mkAttrs(attrs);
|
||||
}
|
||||
|
@ -54,7 +56,11 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value * * args, V
|
|||
v.mkFloat(toml::get<NixFloat>(t));
|
||||
break;;
|
||||
case toml::value_t::string:
|
||||
v.mkString(toml::get<std::string>(t));
|
||||
{
|
||||
auto s = toml::get<std::string_view>(t);
|
||||
forceNoNullByte(s);
|
||||
v.mkString(s);
|
||||
}
|
||||
break;;
|
||||
case toml::value_t::local_datetime:
|
||||
case toml::value_t::offset_datetime:
|
||||
|
@ -66,7 +72,9 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value * * args, V
|
|||
attrs.alloc("_type").mkString("timestamp");
|
||||
std::ostringstream s;
|
||||
s << t;
|
||||
attrs.alloc("value").mkString(toView(s));
|
||||
auto str = toView(s);
|
||||
forceNoNullByte(str);
|
||||
attrs.alloc("value").mkString(str);
|
||||
v.mkAttrs(attrs);
|
||||
} else {
|
||||
throw std::runtime_error("Dates and times are not supported");
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <limits>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
|
@ -510,4 +510,6 @@ typedef std::shared_ptr<Value *> RootValue;
|
|||
|
||||
RootValue allocRootValue(Value * v);
|
||||
|
||||
void forceNoNullByte(std::string_view s);
|
||||
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../build-utils-meson
|
|
@ -14,7 +14,7 @@ project('nix-fetchers-tests', 'cpp',
|
|||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('build-utils-meson/deps-lists')
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
deps_private_maybe_subproject = [
|
||||
dependency('nix-store-test-support'),
|
||||
|
@ -22,10 +22,10 @@ deps_private_maybe_subproject = [
|
|||
]
|
||||
deps_public_maybe_subproject = [
|
||||
]
|
||||
subdir('build-utils-meson/subprojects')
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
subdir('build-utils-meson/export-all-symbols')
|
||||
subdir('build-utils-meson/windows-version')
|
||||
subdir('nix-meson-build-support/export-all-symbols')
|
||||
subdir('nix-meson-build-support/windows-version')
|
||||
|
||||
rapidcheck = dependency('rapidcheck')
|
||||
deps_private += rapidcheck
|
||||
|
@ -42,7 +42,7 @@ add_project_arguments(
|
|||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/common')
|
||||
subdir('nix-meson-build-support/common')
|
||||
|
||||
sources = files(
|
||||
'public-key.cc',
|
||||
|
|
1
src/libfetchers-tests/nix-meson-build-support
Symbolic link
1
src/libfetchers-tests/nix-meson-build-support
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
|
@ -26,8 +26,8 @@ mkMesonExecutable (finalAttrs: {
|
|||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../build-utils-meson
|
||||
./build-utils-meson
|
||||
../../nix-meson-build-support
|
||||
./nix-meson-build-support
|
||||
../../.version
|
||||
./.version
|
||||
./meson.build
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../build-utils-meson
|
|
@ -113,7 +113,15 @@ Input Input::fromAttrs(const Settings & settings, Attrs && attrs)
|
|||
|
||||
std::optional<std::string> Input::getFingerprint(ref<Store> store) const
|
||||
{
|
||||
return scheme ? scheme->getFingerprint(store, *this) : std::nullopt;
|
||||
if (!scheme) return std::nullopt;
|
||||
|
||||
if (cachedFingerprint) return *cachedFingerprint;
|
||||
|
||||
auto fingerprint = scheme->getFingerprint(store, *this);
|
||||
|
||||
cachedFingerprint = fingerprint;
|
||||
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
ParsedURL Input::toURL() const
|
||||
|
@ -313,7 +321,7 @@ std::pair<ref<SourceAccessor>, Input> Input::getAccessorUnchecked(ref<Store> sto
|
|||
|
||||
auto accessor = makeStorePathAccessor(store, storePath);
|
||||
|
||||
accessor->fingerprint = scheme->getFingerprint(store, *this);
|
||||
accessor->fingerprint = getFingerprint(store);
|
||||
|
||||
return {accessor, *this};
|
||||
} catch (Error & e) {
|
||||
|
@ -324,7 +332,7 @@ std::pair<ref<SourceAccessor>, Input> Input::getAccessorUnchecked(ref<Store> sto
|
|||
auto [accessor, result] = scheme->getAccessor(store, *this);
|
||||
|
||||
assert(!accessor->fingerprint);
|
||||
accessor->fingerprint = scheme->getFingerprint(store, result);
|
||||
accessor->fingerprint = result.getFingerprint(store);
|
||||
|
||||
return {accessor, std::move(result)};
|
||||
}
|
||||
|
|
|
@ -41,6 +41,11 @@ struct Input
|
|||
std::shared_ptr<InputScheme> scheme; // note: can be null
|
||||
Attrs attrs;
|
||||
|
||||
/**
|
||||
* Cached result of getFingerprint().
|
||||
*/
|
||||
mutable std::optional<std::optional<std::string>> cachedFingerprint;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create an `Input` from a URL.
|
||||
|
@ -105,6 +110,11 @@ public:
|
|||
|
||||
bool operator ==(const Input & other) const noexcept;
|
||||
|
||||
bool operator <(const Input & other) const
|
||||
{
|
||||
return attrs < other.attrs;
|
||||
}
|
||||
|
||||
bool contains(const Input & other) const;
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "signals.hh"
|
||||
#include "users.hh"
|
||||
#include "fs-sink.hh"
|
||||
#include "sync.hh"
|
||||
|
||||
#include <git2/attr.h>
|
||||
#include <git2/blob.h>
|
||||
|
@ -437,7 +438,12 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
|||
{
|
||||
if (!(statusFlags & GIT_STATUS_INDEX_DELETED) &&
|
||||
!(statusFlags & GIT_STATUS_WT_DELETED))
|
||||
{
|
||||
info.files.insert(CanonPath(path));
|
||||
if (statusFlags != GIT_STATUS_CURRENT)
|
||||
info.dirtyFiles.insert(CanonPath(path));
|
||||
} else
|
||||
info.deletedFiles.insert(CanonPath(path));
|
||||
if (statusFlags != GIT_STATUS_CURRENT)
|
||||
info.isDirty = true;
|
||||
return 0;
|
||||
|
@ -1262,4 +1268,17 @@ ref<GitRepo> getTarballCache()
|
|||
return GitRepo::openRepo(repoDir, true, true);
|
||||
}
|
||||
|
||||
GitRepo::WorkdirInfo GitRepo::getCachedWorkdirInfo(const std::filesystem::path & path)
|
||||
{
|
||||
static Sync<std::map<std::filesystem::path, WorkdirInfo>> _cache;
|
||||
{
|
||||
auto cache(_cache.lock());
|
||||
auto i = cache->find(path);
|
||||
if (i != cache->end()) return i->second;
|
||||
}
|
||||
auto workdirInfo = GitRepo::openRepo(path)->getWorkdirInfo();
|
||||
_cache.lock()->emplace(path, workdirInfo);
|
||||
return workdirInfo;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,12 +59,20 @@ struct GitRepo
|
|||
modified or added, but excluding deleted files. */
|
||||
std::set<CanonPath> files;
|
||||
|
||||
/* All modified or added files. */
|
||||
std::set<CanonPath> dirtyFiles;
|
||||
|
||||
/* The deleted files. */
|
||||
std::set<CanonPath> deletedFiles;
|
||||
|
||||
/* The submodules listed in .gitmodules of this workdir. */
|
||||
std::vector<Submodule> submodules;
|
||||
};
|
||||
|
||||
virtual WorkdirInfo getWorkdirInfo() = 0;
|
||||
|
||||
static WorkdirInfo getCachedWorkdirInfo(const std::filesystem::path & path);
|
||||
|
||||
/* Get the ref that HEAD points to. */
|
||||
virtual std::optional<std::string> getWorkdirRef() = 0;
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "finally.hh"
|
||||
#include "fetch-settings.hh"
|
||||
#include "json-utils.hh"
|
||||
#include "archive.hh"
|
||||
|
||||
#include <regex>
|
||||
#include <string.h>
|
||||
|
@ -430,7 +431,7 @@ struct GitInputScheme : InputScheme
|
|||
// If this is a local directory and no ref or revision is
|
||||
// given, then allow the use of an unclean working tree.
|
||||
if (!input.getRef() && !input.getRev() && repoInfo.isLocal)
|
||||
repoInfo.workdirInfo = GitRepo::openRepo(repoInfo.url)->getWorkdirInfo();
|
||||
repoInfo.workdirInfo = GitRepo::getCachedWorkdirInfo(repoInfo.url);
|
||||
|
||||
return repoInfo;
|
||||
}
|
||||
|
@ -514,8 +515,6 @@ struct GitInputScheme : InputScheme
|
|||
|
||||
auto origRev = input.getRev();
|
||||
|
||||
std::string name = input.getName();
|
||||
|
||||
auto originalRef = input.getRef();
|
||||
auto ref = originalRef ? *originalRef : getDefaultRef(repoInfo);
|
||||
input.attrs.insert_or_assign("ref", ref);
|
||||
|
@ -795,10 +794,33 @@ struct GitInputScheme : InputScheme
|
|||
|
||||
std::optional<std::string> getFingerprint(ref<Store> store, const Input & input) const override
|
||||
{
|
||||
auto makeFingerprint = [&](const Hash & rev)
|
||||
{
|
||||
return rev.gitRev() + (getSubmodulesAttr(input) ? ";s" : "") + (getExportIgnoreAttr(input) ? ";e" : "");
|
||||
};
|
||||
|
||||
if (auto rev = input.getRev())
|
||||
return rev->gitRev() + (getSubmodulesAttr(input) ? ";s" : "") + (getExportIgnoreAttr(input) ? ";e" : "");
|
||||
else
|
||||
return makeFingerprint(*rev);
|
||||
else {
|
||||
auto repoInfo = getRepoInfo(input);
|
||||
if (repoInfo.isLocal && repoInfo.workdirInfo.headRev && repoInfo.workdirInfo.submodules.empty()) {
|
||||
/* Calculate a fingerprint that takes into account the
|
||||
deleted and modified/added files. */
|
||||
HashSink hashSink{HashAlgorithm::SHA512};
|
||||
for (auto & file : repoInfo.workdirInfo.dirtyFiles) {
|
||||
writeString("modified:", hashSink);
|
||||
writeString(file.abs(), hashSink);
|
||||
dumpPath(repoInfo.url + "/" + file.abs(), hashSink);
|
||||
}
|
||||
for (auto & file : repoInfo.workdirInfo.deletedFiles) {
|
||||
writeString("deleted:", hashSink);
|
||||
writeString(file.abs(), hashSink);
|
||||
}
|
||||
return makeFingerprint(*repoInfo.workdirInfo.headRev)
|
||||
+ ";d=" + hashSink.finish().first.to_string(HashFormat::Base16, false);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
bool isLocked(const Input & input) const override
|
||||
|
|
|
@ -14,7 +14,7 @@ project('nix-fetchers', 'cpp',
|
|||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('build-utils-meson/deps-lists')
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
configdata = configuration_data()
|
||||
|
||||
|
@ -24,7 +24,7 @@ deps_public_maybe_subproject = [
|
|||
dependency('nix-util'),
|
||||
dependency('nix-store'),
|
||||
]
|
||||
subdir('build-utils-meson/subprojects')
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
nlohmann_json = dependency('nlohmann_json', version : '>= 3.9')
|
||||
deps_public += nlohmann_json
|
||||
|
@ -41,7 +41,7 @@ add_project_arguments(
|
|||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/common')
|
||||
subdir('nix-meson-build-support/common')
|
||||
|
||||
sources = files(
|
||||
'attrs.cc',
|
||||
|
@ -90,4 +90,4 @@ install_headers(headers, subdir : 'nix', preserve_path : true)
|
|||
|
||||
libraries_private = []
|
||||
|
||||
subdir('build-utils-meson/export')
|
||||
subdir('nix-meson-build-support/export')
|
||||
|
|
1
src/libfetchers/nix-meson-build-support
Symbolic link
1
src/libfetchers/nix-meson-build-support
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
|
@ -22,8 +22,8 @@ mkMesonLibrary (finalAttrs: {
|
|||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../build-utils-meson
|
||||
./build-utils-meson
|
||||
../../nix-meson-build-support
|
||||
./nix-meson-build-support
|
||||
../../.version
|
||||
./.version
|
||||
./meson.build
|
||||
|
|
|
@ -94,12 +94,9 @@ void Registry::add(
|
|||
|
||||
void Registry::remove(const Input & input)
|
||||
{
|
||||
// FIXME: use C++20 std::erase.
|
||||
for (auto i = entries.begin(); i != entries.end(); )
|
||||
if (i->from == input)
|
||||
i = entries.erase(i);
|
||||
else
|
||||
++i;
|
||||
entries.erase(
|
||||
std::remove_if(entries.begin(), entries.end(), [&](const Entry & entry) { return entry.from == input; }),
|
||||
entries.end());
|
||||
}
|
||||
|
||||
static Path getSystemRegistryPath()
|
||||
|
@ -181,7 +178,8 @@ Registries getRegistries(const Settings & settings, ref<Store> store)
|
|||
|
||||
std::pair<Input, Attrs> lookupInRegistries(
|
||||
ref<Store> store,
|
||||
const Input & _input)
|
||||
const Input & _input,
|
||||
const RegistryFilter & filter)
|
||||
{
|
||||
Attrs extraAttrs;
|
||||
int n = 0;
|
||||
|
@ -193,6 +191,7 @@ std::pair<Input, Attrs> lookupInRegistries(
|
|||
if (n > 100) throw Error("cycle detected in flake registry for '%s'", input.to_string());
|
||||
|
||||
for (auto & registry : getRegistries(*input.settings, store)) {
|
||||
if (filter && !filter(registry->type)) continue;
|
||||
// FIXME: O(n)
|
||||
for (auto & entry : registry->entries) {
|
||||
if (entry.exact) {
|
||||
|
|
|
@ -65,8 +65,15 @@ void overrideRegistry(
|
|||
const Input & to,
|
||||
const Attrs & extraAttrs);
|
||||
|
||||
using RegistryFilter = std::function<bool(Registry::RegistryType)>;
|
||||
|
||||
/**
|
||||
* Rewrite a flakeref using the registries. If `filter` is set, only
|
||||
* use the registries for which the filter function returns true.
|
||||
*/
|
||||
std::pair<Input, Attrs> lookupInRegistries(
|
||||
ref<Store> store,
|
||||
const Input & input);
|
||||
const Input & input,
|
||||
const RegistryFilter & filter = {});
|
||||
|
||||
}
|
||||
|
|
1
src/libflake-c/.version
Symbolic link
1
src/libflake-c/.version
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../.version
|
93
src/libflake-c/meson.build
Normal file
93
src/libflake-c/meson.build
Normal file
|
@ -0,0 +1,93 @@
|
|||
project('nix-flake-c', 'cpp',
|
||||
version : files('.version'),
|
||||
default_options : [
|
||||
'cpp_std=c++2a',
|
||||
# TODO(Qyriad): increase the warning level
|
||||
'warning_level=1',
|
||||
'debug=true',
|
||||
'optimization=2',
|
||||
'errorlogs=true', # Please print logs for tests that fail
|
||||
],
|
||||
meson_version : '>= 1.1',
|
||||
license : 'LGPL-2.1-or-later',
|
||||
)
|
||||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
configdata = configuration_data()
|
||||
|
||||
deps_private_maybe_subproject = [
|
||||
dependency('nix-util'),
|
||||
dependency('nix-store'),
|
||||
dependency('nix-expr'),
|
||||
dependency('nix-flake'),
|
||||
]
|
||||
deps_public_maybe_subproject = [
|
||||
dependency('nix-util-c'),
|
||||
dependency('nix-store-c'),
|
||||
dependency('nix-expr-c'),
|
||||
]
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
# TODO rename, because it will conflict with downstream projects
|
||||
configdata.set_quoted('PACKAGE_VERSION', meson.project_version())
|
||||
|
||||
config_h = configure_file(
|
||||
configuration : configdata,
|
||||
output : 'config-flake.h',
|
||||
)
|
||||
|
||||
add_project_arguments(
|
||||
# TODO(Qyriad): Yes this is how the autoconf+Make system did it.
|
||||
# It would be nice for our headers to be idempotent instead.
|
||||
|
||||
# From C++ libraries, only for internals
|
||||
'-include', 'config-util.hh',
|
||||
'-include', 'config-store.hh',
|
||||
'-include', 'config-expr.hh',
|
||||
# not generated (yet?)
|
||||
# '-include', 'config-flake.hh',
|
||||
|
||||
# From C libraries, for our public, installed headers too
|
||||
'-include', 'config-util.h',
|
||||
'-include', 'config-store.h',
|
||||
'-include', 'config-expr.h',
|
||||
'-include', 'config-flake.h',
|
||||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
|
||||
sources = files(
|
||||
'nix_api_flake.cc',
|
||||
)
|
||||
|
||||
include_dirs = [include_directories('.')]
|
||||
|
||||
headers = [config_h] + files(
|
||||
'nix_api_flake.h',
|
||||
)
|
||||
|
||||
# TODO move this header to libexpr, maybe don't use it in tests?
|
||||
headers += files('nix_api_flake.h')
|
||||
|
||||
subdir('nix-meson-build-support/export-all-symbols')
|
||||
subdir('nix-meson-build-support/windows-version')
|
||||
|
||||
this_library = library(
|
||||
'nixflakec',
|
||||
sources,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
link_args: linker_export_flags,
|
||||
prelink : true, # For C++ static initializers
|
||||
install : true,
|
||||
)
|
||||
|
||||
install_headers(headers, subdir : 'nix', preserve_path : true)
|
||||
|
||||
libraries_private = []
|
||||
|
||||
subdir('nix-meson-build-support/export')
|
1
src/libflake-c/nix-meson-build-support
Symbolic link
1
src/libflake-c/nix-meson-build-support
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
32
src/libflake-c/nix_api_flake.cc
Normal file
32
src/libflake-c/nix_api_flake.cc
Normal file
|
@ -0,0 +1,32 @@
|
|||
#include "nix_api_flake.h"
|
||||
#include "nix_api_flake_internal.hh"
|
||||
#include "nix_api_util_internal.h"
|
||||
|
||||
#include "flake/flake.hh"
|
||||
|
||||
nix_flake_settings * nix_flake_settings_new(nix_c_context * context)
|
||||
{
|
||||
try {
|
||||
auto settings = nix::make_ref<nix::flake::Settings>();
|
||||
return new nix_flake_settings{settings};
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
46
src/libflake-c/nix_api_flake.h
Normal file
46
src/libflake-c/nix_api_flake.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
#ifndef NIX_API_FLAKE_H
|
||||
#define NIX_API_FLAKE_H
|
||||
/** @defgroup libflake libflake
|
||||
* @brief Bindings to the Nix Flakes library
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
/** @file
|
||||
* @brief Main entry for the libflake C bindings
|
||||
*/
|
||||
|
||||
#include "nix_api_store.h"
|
||||
#include "nix_api_util.h"
|
||||
#include "nix_api_expr.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// cffi start
|
||||
|
||||
typedef struct nix_flake_settings nix_flake_settings;
|
||||
|
||||
// Function prototypes
|
||||
/**
|
||||
* Create a nix_flake_settings initialized with default values.
|
||||
* @param[out] context Optional, stores error information
|
||||
* @return A new nix_flake_settings or NULL on failure.
|
||||
* @see nix_flake_settings_free
|
||||
*/
|
||||
nix_flake_settings * nix_flake_settings_new(nix_c_context * context);
|
||||
|
||||
/**
|
||||
* @brief Release the resources associated with a nix_flake_settings.
|
||||
*/
|
||||
void nix_flake_settings_free(nix_flake_settings * settings);
|
||||
|
||||
/**
|
||||
* @brief Register Flakes support process-wide.
|
||||
*/
|
||||
nix_err nix_flake_init_global(nix_c_context * context, nix_flake_settings * settings);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
9
src/libflake-c/nix_api_flake_internal.hh
Normal file
9
src/libflake-c/nix_api_flake_internal.hh
Normal file
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "ref.hh"
|
||||
#include "flake/settings.hh"
|
||||
|
||||
struct nix_flake_settings
|
||||
{
|
||||
nix::ref<nix::flake::Settings> settings;
|
||||
};
|
60
src/libflake-c/package.nix
Normal file
60
src/libflake-c/package.nix
Normal file
|
@ -0,0 +1,60 @@
|
|||
{ lib
|
||||
, stdenv
|
||||
, mkMesonLibrary
|
||||
|
||||
, nix-store-c
|
||||
, nix-expr-c
|
||||
, nix-flake
|
||||
|
||||
# Configuration Options
|
||||
|
||||
, version
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (lib) fileset;
|
||||
in
|
||||
|
||||
mkMesonLibrary (finalAttrs: {
|
||||
pname = "nix-flake-c";
|
||||
inherit version;
|
||||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../nix-meson-build-support
|
||||
./nix-meson-build-support
|
||||
../../.version
|
||||
./.version
|
||||
./meson.build
|
||||
# ./meson.options
|
||||
(fileset.fileFilter (file: file.hasExt "cc") ./.)
|
||||
(fileset.fileFilter (file: file.hasExt "hh") ./.)
|
||||
(fileset.fileFilter (file: file.hasExt "h") ./.)
|
||||
];
|
||||
|
||||
propagatedBuildInputs = [
|
||||
nix-expr-c
|
||||
nix-store-c
|
||||
nix-flake
|
||||
];
|
||||
|
||||
preConfigure =
|
||||
# "Inline" .version so it's not a symlink, and includes the suffix.
|
||||
# Do the meson utils, without modification.
|
||||
''
|
||||
chmod u+w ./.version
|
||||
echo ${version} > ../../.version
|
||||
'';
|
||||
|
||||
mesonFlags = [
|
||||
];
|
||||
|
||||
env = lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")) {
|
||||
LDFLAGS = "-fuse-ld=gold";
|
||||
};
|
||||
|
||||
meta = {
|
||||
platforms = lib.platforms.unix ++ lib.platforms.windows;
|
||||
};
|
||||
|
||||
})
|
|
@ -1 +0,0 @@
|
|||
../../build-utils-meson
|
|
@ -14,18 +14,19 @@ project('nix-flake-tests', 'cpp',
|
|||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('build-utils-meson/deps-lists')
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
deps_private_maybe_subproject = [
|
||||
dependency('nix-expr-test-support'),
|
||||
dependency('nix-flake'),
|
||||
dependency('nix-flake-c'),
|
||||
]
|
||||
deps_public_maybe_subproject = [
|
||||
]
|
||||
subdir('build-utils-meson/subprojects')
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
subdir('build-utils-meson/export-all-symbols')
|
||||
subdir('build-utils-meson/windows-version')
|
||||
subdir('nix-meson-build-support/export-all-symbols')
|
||||
subdir('nix-meson-build-support/windows-version')
|
||||
|
||||
rapidcheck = dependency('rapidcheck')
|
||||
deps_private += rapidcheck
|
||||
|
@ -42,10 +43,11 @@ add_project_arguments(
|
|||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/common')
|
||||
subdir('nix-meson-build-support/common')
|
||||
|
||||
sources = files(
|
||||
'flakeref.cc',
|
||||
'nix_api_flake.cc',
|
||||
'url-name.cc',
|
||||
)
|
||||
|
||||
|
@ -68,6 +70,7 @@ test(
|
|||
this_exe,
|
||||
env : {
|
||||
'_NIX_TEST_UNIT_DATA': meson.current_source_dir() / 'data',
|
||||
'NIX_CONFIG': 'extra-experimental-features = flakes',
|
||||
},
|
||||
protocol : 'gtest',
|
||||
)
|
||||
|
|
1
src/libflake-tests/nix-meson-build-support
Symbolic link
1
src/libflake-tests/nix-meson-build-support
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
51
src/libflake-tests/nix_api_flake.cc
Normal file
51
src/libflake-tests/nix_api_flake.cc
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include "nix_api_store.h"
|
||||
#include "nix_api_store_internal.h"
|
||||
#include "nix_api_util.h"
|
||||
#include "nix_api_util_internal.h"
|
||||
#include "nix_api_expr.h"
|
||||
#include "nix_api_value.h"
|
||||
#include "nix_api_flake.h"
|
||||
|
||||
#include "tests/nix_api_expr.hh"
|
||||
#include "tests/string_callback.hh"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace nixC {
|
||||
|
||||
TEST_F(nix_api_store_test, nix_api_init_global_getFlake_exists)
|
||||
{
|
||||
nix_libstore_init(ctx);
|
||||
assert_ctx_ok();
|
||||
nix_libexpr_init(ctx);
|
||||
assert_ctx_ok();
|
||||
|
||||
auto settings = nix_flake_settings_new(ctx);
|
||||
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();
|
||||
|
||||
auto state = nix_eval_state_build(ctx, builder);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, state);
|
||||
|
||||
nix_eval_state_builder_free(builder);
|
||||
|
||||
auto value = nix_alloc_value(ctx, state);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, value);
|
||||
|
||||
nix_err err = nix_expr_eval_from_string(ctx, state, "builtins.getFlake", ".", value);
|
||||
assert_ctx_ok();
|
||||
ASSERT_EQ(NIX_OK, err);
|
||||
ASSERT_EQ(NIX_TYPE_FUNCTION, nix_get_type(ctx, value));
|
||||
}
|
||||
|
||||
} // namespace nixC
|
|
@ -4,6 +4,7 @@
|
|||
, mkMesonExecutable
|
||||
|
||||
, nix-flake
|
||||
, nix-flake-c
|
||||
, nix-expr-test-support
|
||||
|
||||
, rapidcheck
|
||||
|
@ -26,8 +27,8 @@ mkMesonExecutable (finalAttrs: {
|
|||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../build-utils-meson
|
||||
./build-utils-meson
|
||||
../../nix-meson-build-support
|
||||
./nix-meson-build-support
|
||||
../../.version
|
||||
./.version
|
||||
./meson.build
|
||||
|
@ -38,6 +39,7 @@ mkMesonExecutable (finalAttrs: {
|
|||
|
||||
buildInputs = [
|
||||
nix-flake
|
||||
nix-flake-c
|
||||
nix-expr-test-support
|
||||
rapidcheck
|
||||
gtest
|
||||
|
@ -67,6 +69,7 @@ mkMesonExecutable (finalAttrs: {
|
|||
mkdir -p "$HOME"
|
||||
'' + ''
|
||||
export _NIX_TEST_UNIT_DATA=${resolvePath ./data}
|
||||
export NIX_CONFIG="extra-experimental-features = flakes"
|
||||
${stdenv.hostPlatform.emulator buildPackages} ${lib.getExe finalAttrs.finalPackage}
|
||||
touch $out
|
||||
'');
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../build-utils-meson
|
|
@ -21,23 +21,23 @@ using namespace flake;
|
|||
|
||||
namespace flake {
|
||||
|
||||
typedef std::pair<StorePath, FlakeRef> FetchedFlake;
|
||||
typedef std::vector<std::pair<FlakeRef, FetchedFlake>> FlakeCache;
|
||||
struct FetchedFlake
|
||||
{
|
||||
FlakeRef lockedRef;
|
||||
StorePath storePath;
|
||||
};
|
||||
|
||||
typedef std::map<FlakeRef, FetchedFlake> FlakeCache;
|
||||
|
||||
static std::optional<FetchedFlake> lookupInFlakeCache(
|
||||
const FlakeCache & flakeCache,
|
||||
const FlakeRef & flakeRef)
|
||||
{
|
||||
// FIXME: inefficient.
|
||||
for (auto & i : flakeCache) {
|
||||
if (flakeRef == i.first) {
|
||||
debug("mapping '%s' to previously seen input '%s' -> '%s",
|
||||
flakeRef, i.first, i.second.second);
|
||||
return i.second;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
auto i = flakeCache.find(flakeRef);
|
||||
if (i == flakeCache.end()) return std::nullopt;
|
||||
debug("mapping '%s' to previously seen input '%s' -> '%s",
|
||||
flakeRef, i->first, i->second.lockedRef);
|
||||
return i->second;
|
||||
}
|
||||
|
||||
static std::tuple<StorePath, FlakeRef, FlakeRef> fetchOrSubstituteTree(
|
||||
|
@ -51,32 +51,39 @@ static std::tuple<StorePath, FlakeRef, FlakeRef> fetchOrSubstituteTree(
|
|||
|
||||
if (!fetched) {
|
||||
if (originalRef.input.isDirect()) {
|
||||
fetched.emplace(originalRef.fetchTree(state.store));
|
||||
auto [storePath, lockedRef] = originalRef.fetchTree(state.store);
|
||||
fetched.emplace(FetchedFlake{.lockedRef = lockedRef, .storePath = storePath});
|
||||
} else {
|
||||
if (allowLookup) {
|
||||
resolvedRef = originalRef.resolve(state.store);
|
||||
auto fetchedResolved = lookupInFlakeCache(flakeCache, originalRef);
|
||||
if (!fetchedResolved) fetchedResolved.emplace(resolvedRef.fetchTree(state.store));
|
||||
flakeCache.push_back({resolvedRef, *fetchedResolved});
|
||||
fetched.emplace(*fetchedResolved);
|
||||
resolvedRef = originalRef.resolve(
|
||||
state.store,
|
||||
[](fetchers::Registry::RegistryType type) {
|
||||
/* Only use the global registry and CLI flags
|
||||
to resolve indirect flakerefs. */
|
||||
return type == fetchers::Registry::Flag || type == fetchers::Registry::Global;
|
||||
});
|
||||
fetched = lookupInFlakeCache(flakeCache, originalRef);
|
||||
if (!fetched) {
|
||||
auto [storePath, lockedRef] = resolvedRef.fetchTree(state.store);
|
||||
fetched.emplace(FetchedFlake{.lockedRef = lockedRef, .storePath = storePath});
|
||||
}
|
||||
flakeCache.insert_or_assign(resolvedRef, *fetched);
|
||||
}
|
||||
else {
|
||||
throw Error("'%s' is an indirect flake reference, but registry lookups are not allowed", originalRef);
|
||||
}
|
||||
}
|
||||
flakeCache.push_back({originalRef, *fetched});
|
||||
flakeCache.insert_or_assign(originalRef, *fetched);
|
||||
}
|
||||
|
||||
auto [storePath, lockedRef] = *fetched;
|
||||
|
||||
debug("got tree '%s' from '%s'",
|
||||
state.store->printStorePath(storePath), lockedRef);
|
||||
state.store->printStorePath(fetched->storePath), fetched->lockedRef);
|
||||
|
||||
state.allowPath(storePath);
|
||||
state.allowPath(fetched->storePath);
|
||||
|
||||
assert(!originalRef.input.getNarHash() || storePath == originalRef.input.computeStorePath(*state.store));
|
||||
assert(!originalRef.input.getNarHash() || fetched->storePath == originalRef.input.computeStorePath(*state.store));
|
||||
|
||||
return {std::move(storePath), resolvedRef, lockedRef};
|
||||
return {fetched->storePath, resolvedRef, fetched->lockedRef};
|
||||
}
|
||||
|
||||
static void forceTrivialValue(EvalState & state, Value & value, const PosIdx pos)
|
||||
|
@ -752,6 +759,8 @@ LockedFlake lockFlake(
|
|||
if (lockFlags.writeLockFile) {
|
||||
if (sourcePath || lockFlags.outputLockFilePath) {
|
||||
if (auto unlockedInput = newLockFile.isUnlocked()) {
|
||||
if (lockFlags.failOnUnlocked)
|
||||
throw Error("cannot write lock file of flake '%s' because it has an unlocked input ('%s').\n", topRef, *unlockedInput);
|
||||
if (state.fetchSettings.warnDirty)
|
||||
warn("will not write lock file of flake '%s' because it has an unlocked input ('%s')", topRef, *unlockedInput);
|
||||
} else {
|
||||
|
|
|
@ -156,6 +156,11 @@ struct LockFlags
|
|||
*/
|
||||
bool writeLockFile = true;
|
||||
|
||||
/**
|
||||
* Throw an exception when the flake has an unlocked input.
|
||||
*/
|
||||
bool failOnUnlocked = false;
|
||||
|
||||
/**
|
||||
* Whether to use the registries to lookup indirect flake
|
||||
* references like 'nixpkgs'.
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "url.hh"
|
||||
#include "url-parts.hh"
|
||||
#include "fetchers.hh"
|
||||
#include "registry.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
@ -36,7 +35,9 @@ std::ostream & operator << (std::ostream & str, const FlakeRef & flakeRef)
|
|||
return str;
|
||||
}
|
||||
|
||||
FlakeRef FlakeRef::resolve(ref<Store> store) const
|
||||
FlakeRef FlakeRef::resolve(
|
||||
ref<Store> store,
|
||||
const fetchers::RegistryFilter & filter) const
|
||||
{
|
||||
auto [input2, extraAttrs] = lookupInRegistries(store, input);
|
||||
return FlakeRef(std::move(input2), fetchers::maybeGetStrAttr(extraAttrs, "dir").value_or(subdir));
|
||||
|
@ -265,8 +266,6 @@ std::pair<FlakeRef, std::string> parseFlakeRefWithFragment(
|
|||
{
|
||||
using namespace fetchers;
|
||||
|
||||
std::smatch match;
|
||||
|
||||
if (auto res = parseFlakeIdRef(fetchSettings, url, isFlake)) {
|
||||
return *res;
|
||||
} else if (auto res = parseURLFlakeRef(fetchSettings, url, baseDir, isFlake)) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "types.hh"
|
||||
#include "fetchers.hh"
|
||||
#include "outputs-spec.hh"
|
||||
#include "registry.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
@ -48,6 +49,11 @@ struct FlakeRef
|
|||
|
||||
bool operator ==(const FlakeRef & other) const = default;
|
||||
|
||||
bool operator <(const FlakeRef & other) const
|
||||
{
|
||||
return std::tie(input, subdir) < std::tie(other.input, other.subdir);
|
||||
}
|
||||
|
||||
FlakeRef(fetchers::Input && input, const Path & subdir)
|
||||
: input(std::move(input)), subdir(subdir)
|
||||
{ }
|
||||
|
@ -57,7 +63,9 @@ struct FlakeRef
|
|||
|
||||
fetchers::Attrs toAttrs() const;
|
||||
|
||||
FlakeRef resolve(ref<Store> store) const;
|
||||
FlakeRef resolve(
|
||||
ref<Store> store,
|
||||
const fetchers::RegistryFilter & filter = {}) const;
|
||||
|
||||
static FlakeRef fromAttrs(
|
||||
const fetchers::Settings & fetchSettings,
|
||||
|
|
|
@ -14,7 +14,7 @@ project('nix-flake', 'cpp',
|
|||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('build-utils-meson/deps-lists')
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
deps_private_maybe_subproject = [
|
||||
]
|
||||
|
@ -24,7 +24,7 @@ deps_public_maybe_subproject = [
|
|||
dependency('nix-fetchers'),
|
||||
dependency('nix-expr'),
|
||||
]
|
||||
subdir('build-utils-meson/subprojects')
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
nlohmann_json = dependency('nlohmann_json', version : '>= 3.9')
|
||||
deps_public += nlohmann_json
|
||||
|
@ -39,7 +39,7 @@ add_project_arguments(
|
|||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/common')
|
||||
subdir('nix-meson-build-support/common')
|
||||
|
||||
sources = files(
|
||||
'flake/config.cc',
|
||||
|
@ -72,4 +72,4 @@ install_headers(headers, subdir : 'nix', preserve_path : true)
|
|||
|
||||
libraries_private = []
|
||||
|
||||
subdir('build-utils-meson/export')
|
||||
subdir('nix-meson-build-support/export')
|
||||
|
|
1
src/libflake/nix-meson-build-support
Symbolic link
1
src/libflake/nix-meson-build-support
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
|
@ -23,8 +23,8 @@ mkMesonLibrary (finalAttrs: {
|
|||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../build-utils-meson
|
||||
./build-utils-meson
|
||||
../../nix-meson-build-support
|
||||
./nix-meson-build-support
|
||||
../../.version
|
||||
./.version
|
||||
./meson.build
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../build-utils-meson
|
|
@ -14,7 +14,7 @@ project('nix-main-c', 'cpp',
|
|||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('build-utils-meson/deps-lists')
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
configdata = configuration_data()
|
||||
|
||||
|
@ -27,7 +27,7 @@ deps_public_maybe_subproject = [
|
|||
dependency('nix-util-c'),
|
||||
dependency('nix-store-c'),
|
||||
]
|
||||
subdir('build-utils-meson/subprojects')
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
# TODO rename, because it will conflict with downstream projects
|
||||
configdata.set_quoted('PACKAGE_VERSION', meson.project_version())
|
||||
|
@ -53,7 +53,7 @@ add_project_arguments(
|
|||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/common')
|
||||
subdir('nix-meson-build-support/common')
|
||||
|
||||
sources = files(
|
||||
'nix_api_main.cc',
|
||||
|
@ -65,8 +65,8 @@ headers = [config_h] + files(
|
|||
'nix_api_main.h',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/export-all-symbols')
|
||||
subdir('build-utils-meson/windows-version')
|
||||
subdir('nix-meson-build-support/export-all-symbols')
|
||||
subdir('nix-meson-build-support/windows-version')
|
||||
|
||||
this_library = library(
|
||||
'nixmainc',
|
||||
|
@ -82,4 +82,4 @@ install_headers(headers, subdir : 'nix', preserve_path : true)
|
|||
|
||||
libraries_private = []
|
||||
|
||||
subdir('build-utils-meson/export')
|
||||
subdir('nix-meson-build-support/export')
|
||||
|
|
1
src/libmain-c/nix-meson-build-support
Symbolic link
1
src/libmain-c/nix-meson-build-support
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
|
@ -22,8 +22,8 @@ mkMesonLibrary (finalAttrs: {
|
|||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../build-utils-meson
|
||||
./build-utils-meson
|
||||
../../nix-meson-build-support
|
||||
./nix-meson-build-support
|
||||
../../.version
|
||||
./.version
|
||||
./meson.build
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../build-utils-meson
|
|
@ -14,7 +14,7 @@ project('nix-main', 'cpp',
|
|||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('build-utils-meson/deps-lists')
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
configdata = configuration_data()
|
||||
|
||||
|
@ -24,7 +24,7 @@ deps_public_maybe_subproject = [
|
|||
dependency('nix-util'),
|
||||
dependency('nix-store'),
|
||||
]
|
||||
subdir('build-utils-meson/subprojects')
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
pubsetbuf_test = '''
|
||||
#include <iostream>
|
||||
|
@ -58,7 +58,7 @@ add_project_arguments(
|
|||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/common')
|
||||
subdir('nix-meson-build-support/common')
|
||||
|
||||
sources = files(
|
||||
'common-args.cc',
|
||||
|
@ -96,4 +96,4 @@ install_headers(headers, subdir : 'nix', preserve_path : true)
|
|||
|
||||
libraries_private = []
|
||||
|
||||
subdir('build-utils-meson/export')
|
||||
subdir('nix-meson-build-support/export')
|
||||
|
|
1
src/libmain/nix-meson-build-support
Symbolic link
1
src/libmain/nix-meson-build-support
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
|
@ -22,8 +22,8 @@ mkMesonLibrary (finalAttrs: {
|
|||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../build-utils-meson
|
||||
./build-utils-meson
|
||||
../../nix-meson-build-support
|
||||
./nix-meson-build-support
|
||||
../../.version
|
||||
./.version
|
||||
./meson.build
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../build-utils-meson
|
|
@ -14,7 +14,7 @@ project('nix-store-c', 'cpp',
|
|||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('build-utils-meson/deps-lists')
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
configdata = configuration_data()
|
||||
|
||||
|
@ -25,7 +25,7 @@ deps_private_maybe_subproject = [
|
|||
deps_public_maybe_subproject = [
|
||||
dependency('nix-util-c'),
|
||||
]
|
||||
subdir('build-utils-meson/subprojects')
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
# TODO rename, because it will conflict with downstream projects
|
||||
configdata.set_quoted('PACKAGE_VERSION', meson.project_version())
|
||||
|
@ -49,7 +49,7 @@ add_project_arguments(
|
|||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/common')
|
||||
subdir('nix-meson-build-support/common')
|
||||
|
||||
sources = files(
|
||||
'nix_api_store.cc',
|
||||
|
@ -64,8 +64,8 @@ headers = [config_h] + files(
|
|||
# TODO don't install this once tests don't use it and/or move the header into `libstore`, non-`c`
|
||||
headers += files('nix_api_store_internal.h')
|
||||
|
||||
subdir('build-utils-meson/export-all-symbols')
|
||||
subdir('build-utils-meson/windows-version')
|
||||
subdir('nix-meson-build-support/export-all-symbols')
|
||||
subdir('nix-meson-build-support/windows-version')
|
||||
|
||||
this_library = library(
|
||||
'nixstorec',
|
||||
|
@ -81,4 +81,4 @@ install_headers(headers, subdir : 'nix', preserve_path : true)
|
|||
|
||||
libraries_private = []
|
||||
|
||||
subdir('build-utils-meson/export')
|
||||
subdir('nix-meson-build-support/export')
|
||||
|
|
1
src/libstore-c/nix-meson-build-support
Symbolic link
1
src/libstore-c/nix-meson-build-support
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
|
@ -67,6 +67,17 @@ nix_err nix_store_get_uri(nix_c_context * context, Store * store, nix_get_string
|
|||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err
|
||||
nix_store_get_storedir(nix_c_context * context, Store * store, nix_get_string_callback callback, void * user_data)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
return call_nix_get_string_callback(store->ptr->storeDir, callback, user_data);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err
|
||||
nix_store_get_version(nix_c_context * context, Store * store, nix_get_string_callback callback, void * user_data)
|
||||
{
|
||||
|
@ -89,6 +100,18 @@ bool nix_store_is_valid_path(nix_c_context * context, Store * store, StorePath *
|
|||
NIXC_CATCH_ERRS_RES(false);
|
||||
}
|
||||
|
||||
nix_err nix_store_real_path(
|
||||
nix_c_context * context, Store * store, StorePath * path, nix_get_string_callback callback, void * user_data)
|
||||
{
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
auto res = store->ptr->toRealPath(path->path);
|
||||
return call_nix_get_string_callback(res, callback, user_data);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
StorePath * nix_store_parse_path(nix_c_context * context, Store * store, const char * path)
|
||||
{
|
||||
if (context)
|
||||
|
|
|
@ -48,12 +48,27 @@ nix_err nix_libstore_init_no_load_config(nix_c_context * context);
|
|||
* Store instances may share state and resources behind the scenes.
|
||||
*
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] uri URI of the Nix store, copied. See [*Store URL format* in the Nix Reference
|
||||
*
|
||||
* @param[in] uri @parblock
|
||||
* URI of the Nix store, copied.
|
||||
*
|
||||
* If `NULL`, the store from the settings will be used.
|
||||
* Note that `"auto"` holds a strange middle ground, reading part of the general environment, but not all of it. It
|
||||
* ignores `NIX_REMOTE` and the `store` option. For this reason, `NULL` is most likely the better choice.
|
||||
*
|
||||
* For supported store URLs, see [*Store URL format* in the Nix Reference
|
||||
* Manual](https://nixos.org/manual/nix/stable/store/types/#store-url-format).
|
||||
* @param[in] params optional, null-terminated array of key-value pairs, e.g. {{"endpoint",
|
||||
* "https://s3.local"}}. See [*Store Types* in the Nix Reference
|
||||
* Manual](https://nixos.org/manual/nix/stable/store/types).
|
||||
* @endparblock
|
||||
*
|
||||
* @param[in] params @parblock
|
||||
* optional, null-terminated array of key-value pairs, e.g. {{"endpoint",
|
||||
* "https://s3.local"}}.
|
||||
*
|
||||
* See [*Store Types* in the Nix Reference Manual](https://nixos.org/manual/nix/stable/store/types).
|
||||
* @endparblock
|
||||
*
|
||||
* @return a Store pointer, NULL in case of errors
|
||||
*
|
||||
* @see nix_store_free
|
||||
*/
|
||||
Store * nix_store_open(nix_c_context * context, const char * uri, const char *** params);
|
||||
|
@ -78,7 +93,18 @@ void nix_store_free(Store * store);
|
|||
*/
|
||||
nix_err nix_store_get_uri(nix_c_context * context, Store * store, nix_get_string_callback callback, void * user_data);
|
||||
|
||||
// returns: owned StorePath*
|
||||
/**
|
||||
* @brief get the storeDir of a Nix store, typically `"/nix/store"`
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] store nix store reference
|
||||
* @param[in] callback Called with the URI.
|
||||
* @param[in] user_data optional, arbitrary data, passed to the callback when it's called.
|
||||
* @see nix_get_string_callback
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err
|
||||
nix_store_get_storedir(nix_c_context * context, Store * store, nix_get_string_callback callback, void * user_data);
|
||||
|
||||
/**
|
||||
* @brief Parse a Nix store path into a StorePath
|
||||
*
|
||||
|
@ -123,6 +149,26 @@ void nix_store_path_free(StorePath * p);
|
|||
* @return true or false, error info in context
|
||||
*/
|
||||
bool nix_store_is_valid_path(nix_c_context * context, Store * store, StorePath * path);
|
||||
|
||||
/**
|
||||
* @brief Get the physical location of a store path
|
||||
*
|
||||
* A store may reside at a different location than its `storeDir` suggests.
|
||||
* This situation is called a relocated store.
|
||||
* Relocated stores are used during NixOS installation, as well as in restricted computing environments that don't offer
|
||||
* a writable `/nix/store`.
|
||||
*
|
||||
* Not all types of stores support this operation.
|
||||
*
|
||||
* @param[in] context Optional, stores error information
|
||||
* @param[in] store nix store reference
|
||||
* @param[in] path the path to get the real path from
|
||||
* @param[in] callback called with the real path
|
||||
* @param[in] user_data arbitrary data, passed to the callback when it's called.
|
||||
*/
|
||||
nix_err nix_store_real_path(
|
||||
nix_c_context * context, Store * store, StorePath * path, nix_get_string_callback callback, void * user_data);
|
||||
|
||||
// nix_err nix_store_ensure(Store*, const char*);
|
||||
// nix_err nix_store_build_paths(Store*);
|
||||
/**
|
||||
|
|
|
@ -20,8 +20,8 @@ mkMesonLibrary (finalAttrs: {
|
|||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../build-utils-meson
|
||||
./build-utils-meson
|
||||
../../nix-meson-build-support
|
||||
./nix-meson-build-support
|
||||
../../.version
|
||||
./.version
|
||||
./meson.build
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../build-utils-meson
|
|
@ -14,7 +14,7 @@ project('nix-store-test-support', 'cpp',
|
|||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('build-utils-meson/deps-lists')
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
deps_private_maybe_subproject = [
|
||||
]
|
||||
|
@ -22,8 +22,9 @@ deps_public_maybe_subproject = [
|
|||
dependency('nix-util'),
|
||||
dependency('nix-util-test-support'),
|
||||
dependency('nix-store'),
|
||||
dependency('nix-store-c'),
|
||||
]
|
||||
subdir('build-utils-meson/subprojects')
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
rapidcheck = dependency('rapidcheck')
|
||||
deps_public += rapidcheck
|
||||
|
@ -36,7 +37,7 @@ add_project_arguments(
|
|||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/common')
|
||||
subdir('nix-meson-build-support/common')
|
||||
|
||||
sources = files(
|
||||
'tests/derived-path.cc',
|
||||
|
@ -55,8 +56,8 @@ headers = files(
|
|||
'tests/protocol.hh',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/export-all-symbols')
|
||||
subdir('build-utils-meson/windows-version')
|
||||
subdir('nix-meson-build-support/export-all-symbols')
|
||||
subdir('nix-meson-build-support/windows-version')
|
||||
|
||||
this_library = library(
|
||||
'nix-store-test-support',
|
||||
|
@ -74,4 +75,4 @@ install_headers(headers, subdir : 'nix', preserve_path : true)
|
|||
|
||||
libraries_private = []
|
||||
|
||||
subdir('build-utils-meson/export')
|
||||
subdir('nix-meson-build-support/export')
|
||||
|
|
1
src/libstore-test-support/nix-meson-build-support
Symbolic link
1
src/libstore-test-support/nix-meson-build-support
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
, nix-util-test-support
|
||||
, nix-store
|
||||
, nix-store-c
|
||||
|
||||
, rapidcheck
|
||||
|
||||
|
@ -22,8 +23,8 @@ mkMesonLibrary (finalAttrs: {
|
|||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../build-utils-meson
|
||||
./build-utils-meson
|
||||
../../nix-meson-build-support
|
||||
./nix-meson-build-support
|
||||
../../.version
|
||||
./.version
|
||||
./meson.build
|
||||
|
@ -35,6 +36,7 @@ mkMesonLibrary (finalAttrs: {
|
|||
propagatedBuildInputs = [
|
||||
nix-util-test-support
|
||||
nix-store
|
||||
nix-store-c
|
||||
rapidcheck
|
||||
];
|
||||
|
||||
|
|
|
@ -19,12 +19,12 @@ public:
|
|||
protected:
|
||||
LibStoreTest()
|
||||
: store(openStore({
|
||||
.variant =
|
||||
StoreReference::Specified{
|
||||
.scheme = "dummy",
|
||||
},
|
||||
.params = {},
|
||||
}))
|
||||
.variant =
|
||||
StoreReference::Specified{
|
||||
.scheme = "dummy",
|
||||
},
|
||||
.params = {},
|
||||
}))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../build-utils-meson
|
|
@ -14,19 +14,21 @@ project('nix-store-tests', 'cpp',
|
|||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('build-utils-meson/deps-lists')
|
||||
subdir('nix-meson-build-support/deps-lists')
|
||||
|
||||
nix_store = dependency('nix-store')
|
||||
|
||||
deps_private_maybe_subproject = [
|
||||
dependency('nix-store'),
|
||||
nix_store,
|
||||
dependency('nix-store-c'),
|
||||
dependency('nix-store-test-support'),
|
||||
]
|
||||
deps_public_maybe_subproject = [
|
||||
]
|
||||
subdir('build-utils-meson/subprojects')
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
subdir('build-utils-meson/export-all-symbols')
|
||||
subdir('build-utils-meson/windows-version')
|
||||
subdir('nix-meson-build-support/export-all-symbols')
|
||||
subdir('nix-meson-build-support/windows-version')
|
||||
|
||||
sqlite = dependency('sqlite3', 'sqlite', version : '>=3.6.19')
|
||||
deps_private += sqlite
|
||||
|
@ -50,7 +52,7 @@ add_project_arguments(
|
|||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/common')
|
||||
subdir('nix-meson-build-support/common')
|
||||
|
||||
sources = files(
|
||||
'common-protocol.cc',
|
||||
|
@ -90,6 +92,7 @@ this_exe = executable(
|
|||
include_directories : include_dirs,
|
||||
# TODO: -lrapidcheck, see ../libutil-support/build.meson
|
||||
link_args: linker_export_flags + ['-lrapidcheck'],
|
||||
cpp_args : [ '-DNIX_STORE_DIR="' + nix_store.get_variable('storedir') + '"' ],
|
||||
# get main from gtest
|
||||
install : true,
|
||||
)
|
||||
|
|
1
src/libstore-tests/nix-meson-build-support
Symbolic link
1
src/libstore-tests/nix-meson-build-support
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../nix-meson-build-support
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue