mirror of
https://github.com/NixOS/nix
synced 2025-06-24 22:11:15 +02:00
nix-flake-c: Add lock flags
Going with a slightly more limited, high level API supporting the three main use cases. This should allow the underlying code to evolve more freely.
This commit is contained in:
parent
1a3789e222
commit
8c903e0402
3 changed files with 328 additions and 26 deletions
|
@ -97,7 +97,16 @@ nix_flake_lock_flags * nix_flake_lock_flags_new(nix_c_context * context, nix_fla
|
|||
{
|
||||
nix_clear_err(context);
|
||||
try {
|
||||
auto lockSettings = nix::make_ref<nix::flake::LockFlags>();
|
||||
auto lockSettings = nix::make_ref<nix::flake::LockFlags>(nix::flake::LockFlags{
|
||||
.recreateLockFile = false,
|
||||
.updateLockFile = true, // == `nix_flake_lock_flags_set_mode_write_as_needed`
|
||||
.writeLockFile = true, // == `nix_flake_lock_flags_set_mode_write_as_needed`
|
||||
.failOnUnlocked = false, // == `nix_flake_lock_flags_set_mode_write_as_needed`
|
||||
.useRegistries = false,
|
||||
.allowUnlocked = false, // == `nix_flake_lock_flags_set_mode_write_as_needed`
|
||||
.commitLockFile = false,
|
||||
|
||||
});
|
||||
return new nix_flake_lock_flags{lockSettings};
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
|
@ -108,16 +117,68 @@ void nix_flake_lock_flags_free(nix_flake_lock_flags * flags)
|
|||
delete flags;
|
||||
}
|
||||
|
||||
nix_err nix_flake_lock_flags_set_mode_virtual(nix_c_context * context, nix_flake_lock_flags * flags)
|
||||
{
|
||||
nix_clear_err(context);
|
||||
try {
|
||||
flags->lockFlags->updateLockFile = true;
|
||||
flags->lockFlags->writeLockFile = false;
|
||||
flags->lockFlags->failOnUnlocked = false;
|
||||
flags->lockFlags->allowUnlocked = true;
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_flake_lock_flags_set_mode_write_as_needed(nix_c_context * context, nix_flake_lock_flags * flags)
|
||||
{
|
||||
nix_clear_err(context);
|
||||
try {
|
||||
flags->lockFlags->updateLockFile = true;
|
||||
flags->lockFlags->writeLockFile = true;
|
||||
flags->lockFlags->failOnUnlocked = false;
|
||||
flags->lockFlags->allowUnlocked = true;
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_flake_lock_flags_set_mode_check(nix_c_context * context, nix_flake_lock_flags * flags)
|
||||
{
|
||||
nix_clear_err(context);
|
||||
try {
|
||||
flags->lockFlags->updateLockFile = false;
|
||||
flags->lockFlags->writeLockFile = false;
|
||||
flags->lockFlags->failOnUnlocked = true;
|
||||
flags->lockFlags->allowUnlocked = false;
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_flake_lock_flags_add_input_override(
|
||||
nix_c_context * context, nix_flake_lock_flags * flags, const char * inputPath, nix_flake_reference * flakeRef)
|
||||
{
|
||||
nix_clear_err(context);
|
||||
try {
|
||||
auto path = nix::flake::parseInputAttrPath(inputPath);
|
||||
flags->lockFlags->inputOverrides.emplace(path, *flakeRef->flakeRef);
|
||||
if (flags->lockFlags->writeLockFile) {
|
||||
return nix_flake_lock_flags_set_mode_virtual(context, flags);
|
||||
}
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_locked_flake * nix_flake_lock(
|
||||
nix_c_context * context,
|
||||
nix_flake_settings * settings,
|
||||
nix_fetchers_settings * fetchSettings,
|
||||
nix_flake_settings * flakeSettings,
|
||||
EvalState * eval_state,
|
||||
nix_flake_lock_flags * flags,
|
||||
nix_flake_reference * flakeReference)
|
||||
{
|
||||
nix_clear_err(context);
|
||||
try {
|
||||
auto lockedFlake = nix::make_ref<nix::flake::LockedFlake>(nix::flake::lockFlake(
|
||||
*settings->settings, eval_state->state, *flakeReference->flakeRef, *flags->lockFlags));
|
||||
*flakeSettings->settings, eval_state->state, *flakeReference->flakeRef, *flags->lockFlags));
|
||||
return new nix_locked_flake{lockedFlake};
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
|
|
|
@ -126,6 +126,49 @@ nix_flake_lock_flags * nix_flake_lock_flags_new(nix_c_context * context, nix_fla
|
|||
*/
|
||||
void nix_flake_lock_flags_free(nix_flake_lock_flags * settings);
|
||||
|
||||
/**
|
||||
* @brief Put the lock flags in a mode that checks whether the lock is up to date.
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] flags The flags to modify
|
||||
* @return NIX_OK on success, NIX_ERR on failure
|
||||
*
|
||||
* This causes `nix_flake_lock` to fail if the lock needs to be updated.
|
||||
*/
|
||||
nix_err nix_flake_lock_flags_set_mode_check(nix_c_context * context, nix_flake_lock_flags * flags);
|
||||
|
||||
/**
|
||||
* @brief Put the lock flags in a mode that updates the lock file in memory, if needed.
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] flags The flags to modify
|
||||
* @param[in] update Whether to allow updates
|
||||
*
|
||||
* This will cause `nix_flake_lock` to update the lock file in memory, if needed.
|
||||
*/
|
||||
nix_err nix_flake_lock_flags_set_mode_virtual(nix_c_context * context, nix_flake_lock_flags * flags);
|
||||
|
||||
/**
|
||||
* @brief Put the lock flags in a mode that updates the lock file on disk, if needed.
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] flags The flags to modify
|
||||
* @param[in] update Whether to allow updates
|
||||
*
|
||||
* This will cause `nix_flake_lock` to update the lock file on disk, if needed.
|
||||
*/
|
||||
nix_err nix_flake_lock_flags_set_mode_write_as_needed(nix_c_context * context, nix_flake_lock_flags * flags);
|
||||
|
||||
/**
|
||||
* @brief Add input overrides to the lock flags
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] flags The flags to modify
|
||||
* @param[in] inputPath The input path to override
|
||||
* @param[in] flakeRef The flake reference to use as the override
|
||||
*
|
||||
* This switches the `flags` to `nix_flake_lock_flags_set_mode_virtual` if not in mode
|
||||
* `nix_flake_lock_flags_set_mode_check`.
|
||||
*/
|
||||
nix_err nix_flake_lock_flags_add_input_override(
|
||||
nix_c_context * context, nix_flake_lock_flags * flags, const char * inputPath, nix_flake_reference * flakeRef);
|
||||
|
||||
/**
|
||||
* @brief Lock a flake, if not already locked.
|
||||
* @param[out] context Optional, stores error information
|
||||
|
@ -135,6 +178,7 @@ void nix_flake_lock_flags_free(nix_flake_lock_flags * settings);
|
|||
*/
|
||||
nix_locked_flake * nix_flake_lock(
|
||||
nix_c_context * context,
|
||||
nix_fetchers_settings * fetchSettings,
|
||||
nix_flake_settings * settings,
|
||||
EvalState * eval_state,
|
||||
nix_flake_lock_flags * flags,
|
||||
|
|
|
@ -71,15 +71,8 @@ TEST_F(nix_api_store_test, nix_api_flake_reference_not_absolute_no_basedir_fail)
|
|||
std::string fragment;
|
||||
nix_flake_reference * flakeReference = nullptr;
|
||||
auto r = nix_flake_reference_and_fragment_from_string(
|
||||
ctx,
|
||||
fetchSettings,
|
||||
settings,
|
||||
parseFlags,
|
||||
str.data(),
|
||||
str.size(),
|
||||
&flakeReference,
|
||||
OBSERVE_STRING(fragment));
|
||||
|
||||
ctx, fetchSettings, settings, parseFlags, str.data(), str.size(), &flakeReference, OBSERVE_STRING(fragment));
|
||||
|
||||
ASSERT_NE(NIX_OK, r);
|
||||
ASSERT_EQ(nullptr, flakeReference);
|
||||
|
||||
|
@ -126,11 +119,7 @@ TEST_F(nix_api_store_test, nix_api_load_flake)
|
|||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, parseFlags);
|
||||
|
||||
auto r0 = nix_flake_reference_parse_flags_set_base_directory(
|
||||
ctx,
|
||||
parseFlags,
|
||||
tmpDir.c_str(),
|
||||
tmpDir.size());
|
||||
auto r0 = nix_flake_reference_parse_flags_set_base_directory(ctx, parseFlags, tmpDir.c_str(), tmpDir.size());
|
||||
assert_ctx_ok();
|
||||
ASSERT_EQ(NIX_OK, r0);
|
||||
|
||||
|
@ -138,14 +127,7 @@ TEST_F(nix_api_store_test, nix_api_load_flake)
|
|||
const std::string ref = ".#legacyPackages.aarch127-unknown...orion";
|
||||
nix_flake_reference * flakeReference = nullptr;
|
||||
auto r = nix_flake_reference_and_fragment_from_string(
|
||||
ctx,
|
||||
fetchSettings,
|
||||
settings,
|
||||
parseFlags,
|
||||
ref.data(),
|
||||
ref.size(),
|
||||
&flakeReference,
|
||||
OBSERVE_STRING(fragment));
|
||||
ctx, fetchSettings, settings, parseFlags, ref.data(), ref.size(), &flakeReference, OBSERVE_STRING(fragment));
|
||||
assert_ctx_ok();
|
||||
ASSERT_EQ(NIX_OK, r);
|
||||
ASSERT_NE(nullptr, flakeReference);
|
||||
|
@ -157,7 +139,7 @@ TEST_F(nix_api_store_test, nix_api_load_flake)
|
|||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, lockFlags);
|
||||
|
||||
auto lockedFlake = nix_flake_lock(ctx, settings, state, lockFlags, flakeReference);
|
||||
auto lockedFlake = nix_flake_lock(ctx, fetchSettings, settings, state, lockFlags, flakeReference);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, lockedFlake);
|
||||
|
||||
|
@ -183,4 +165,219 @@ TEST_F(nix_api_store_test, nix_api_load_flake)
|
|||
nix_flake_settings_free(settings);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_store_test, nix_api_load_flake_with_flags)
|
||||
{
|
||||
nix_libstore_init(ctx);
|
||||
assert_ctx_ok();
|
||||
nix_libexpr_init(ctx);
|
||||
assert_ctx_ok();
|
||||
|
||||
auto tmpDir = nix::createTempDir();
|
||||
nix::AutoDelete delTmpDir(tmpDir, true);
|
||||
|
||||
nix::createDirs(tmpDir + "/b");
|
||||
nix::writeFile(tmpDir + "/b/flake.nix", R"(
|
||||
{
|
||||
outputs = { ... }: {
|
||||
hello = "BOB";
|
||||
};
|
||||
}
|
||||
)");
|
||||
|
||||
nix::createDirs(tmpDir + "/a");
|
||||
nix::writeFile(tmpDir + "/a/flake.nix", R"(
|
||||
{
|
||||
inputs.b.url = ")" + tmpDir + R"(/b";
|
||||
outputs = { b, ... }: {
|
||||
hello = b.hello;
|
||||
};
|
||||
}
|
||||
)");
|
||||
|
||||
nix::createDirs(tmpDir + "/c");
|
||||
nix::writeFile(tmpDir + "/c/flake.nix", R"(
|
||||
{
|
||||
outputs = { ... }: {
|
||||
hello = "Claire";
|
||||
};
|
||||
}
|
||||
)");
|
||||
|
||||
nix_libstore_init(ctx);
|
||||
assert_ctx_ok();
|
||||
|
||||
auto fetchSettings = nix_fetchers_settings_new(ctx);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, fetchSettings);
|
||||
|
||||
auto settings = nix_flake_settings_new(ctx);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, settings);
|
||||
|
||||
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 parseFlags = nix_flake_reference_parse_flags_new(ctx, settings);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, parseFlags);
|
||||
|
||||
auto r0 = nix_flake_reference_parse_flags_set_base_directory(ctx, parseFlags, tmpDir.c_str(), tmpDir.size());
|
||||
assert_ctx_ok();
|
||||
ASSERT_EQ(NIX_OK, r0);
|
||||
|
||||
std::string fragment;
|
||||
const std::string ref = "./a";
|
||||
nix_flake_reference * flakeReference = nullptr;
|
||||
auto r = nix_flake_reference_and_fragment_from_string(
|
||||
ctx, fetchSettings, settings, parseFlags, ref.data(), ref.size(), &flakeReference, OBSERVE_STRING(fragment));
|
||||
assert_ctx_ok();
|
||||
ASSERT_EQ(NIX_OK, r);
|
||||
ASSERT_NE(nullptr, flakeReference);
|
||||
ASSERT_EQ(fragment, "");
|
||||
|
||||
// Step 1: Do not update, fails
|
||||
|
||||
auto lockFlags = nix_flake_lock_flags_new(ctx, settings);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, lockFlags);
|
||||
|
||||
nix_flake_lock_flags_set_mode_check(ctx, lockFlags);
|
||||
assert_ctx_ok();
|
||||
|
||||
// Step 2: Update but do not write, succeeds
|
||||
|
||||
auto lockedFlake = nix_flake_lock(ctx, fetchSettings, settings, state, lockFlags, flakeReference);
|
||||
assert_ctx_err();
|
||||
ASSERT_EQ(nullptr, lockedFlake);
|
||||
|
||||
nix_flake_lock_flags_set_mode_virtual(ctx, lockFlags);
|
||||
assert_ctx_ok();
|
||||
|
||||
lockedFlake = nix_flake_lock(ctx, fetchSettings, settings, state, lockFlags, flakeReference);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, lockedFlake);
|
||||
|
||||
// Get the output attrs
|
||||
auto value = nix_locked_flake_get_output_attrs(ctx, settings, state, lockedFlake);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, value);
|
||||
|
||||
auto helloAttr = nix_get_attr_byname(ctx, value, state, "hello");
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, helloAttr);
|
||||
|
||||
std::string helloStr;
|
||||
nix_get_string(ctx, helloAttr, OBSERVE_STRING(helloStr));
|
||||
assert_ctx_ok();
|
||||
ASSERT_EQ("BOB", helloStr);
|
||||
|
||||
nix_value_decref(ctx, value);
|
||||
nix_locked_flake_free(lockedFlake);
|
||||
|
||||
// Step 3: Lock was not written, so Step 1 would fail again
|
||||
|
||||
nix_flake_lock_flags_set_mode_check(ctx, lockFlags);
|
||||
|
||||
lockedFlake = nix_flake_lock(ctx, fetchSettings, settings, state, lockFlags, flakeReference);
|
||||
assert_ctx_err();
|
||||
ASSERT_EQ(nullptr, lockedFlake);
|
||||
|
||||
// Step 4: Update and write, succeeds
|
||||
|
||||
nix_flake_lock_flags_set_mode_write_as_needed(ctx, lockFlags);
|
||||
assert_ctx_ok();
|
||||
|
||||
lockedFlake = nix_flake_lock(ctx, fetchSettings, settings, state, lockFlags, flakeReference);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, lockedFlake);
|
||||
|
||||
// Get the output attrs
|
||||
value = nix_locked_flake_get_output_attrs(ctx, settings, state, lockedFlake);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, value);
|
||||
|
||||
helloAttr = nix_get_attr_byname(ctx, value, state, "hello");
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, helloAttr);
|
||||
|
||||
helloStr.clear();
|
||||
nix_get_string(ctx, helloAttr, OBSERVE_STRING(helloStr));
|
||||
assert_ctx_ok();
|
||||
ASSERT_EQ("BOB", helloStr);
|
||||
|
||||
nix_value_decref(ctx, value);
|
||||
nix_locked_flake_free(lockedFlake);
|
||||
|
||||
// Step 5: Lock was written, so Step 1 would succeed
|
||||
|
||||
nix_flake_lock_flags_set_mode_check(ctx, lockFlags);
|
||||
assert_ctx_ok();
|
||||
|
||||
lockedFlake = nix_flake_lock(ctx, fetchSettings, settings, state, lockFlags, flakeReference);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, lockedFlake);
|
||||
|
||||
// Get the output attrs
|
||||
value = nix_locked_flake_get_output_attrs(ctx, settings, state, lockedFlake);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, value);
|
||||
|
||||
helloAttr = nix_get_attr_byname(ctx, value, state, "hello");
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, helloAttr);
|
||||
|
||||
helloStr.clear();
|
||||
nix_get_string(ctx, helloAttr, OBSERVE_STRING(helloStr));
|
||||
assert_ctx_ok();
|
||||
ASSERT_EQ("BOB", helloStr);
|
||||
|
||||
nix_value_decref(ctx, value);
|
||||
nix_locked_flake_free(lockedFlake);
|
||||
|
||||
// Step 6: Lock with override, do not write
|
||||
|
||||
nix_flake_lock_flags_set_mode_write_as_needed(ctx, lockFlags);
|
||||
assert_ctx_ok();
|
||||
|
||||
nix_flake_reference * overrideFlakeReference = nullptr;
|
||||
nix_flake_reference_and_fragment_from_string(
|
||||
ctx, fetchSettings, settings, parseFlags, "./c", 3, &overrideFlakeReference, OBSERVE_STRING(fragment));
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, overrideFlakeReference);
|
||||
|
||||
nix_flake_lock_flags_add_input_override(ctx, lockFlags, "b", overrideFlakeReference);
|
||||
assert_ctx_ok();
|
||||
|
||||
lockedFlake = nix_flake_lock(ctx, fetchSettings, settings, state, lockFlags, flakeReference);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, lockedFlake);
|
||||
|
||||
// Get the output attrs
|
||||
value = nix_locked_flake_get_output_attrs(ctx, settings, state, lockedFlake);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, value);
|
||||
|
||||
helloAttr = nix_get_attr_byname(ctx, value, state, "hello");
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, helloAttr);
|
||||
|
||||
helloStr.clear();
|
||||
nix_get_string(ctx, helloAttr, OBSERVE_STRING(helloStr));
|
||||
assert_ctx_ok();
|
||||
ASSERT_EQ("Claire", helloStr);
|
||||
|
||||
nix_flake_reference_parse_flags_free(parseFlags);
|
||||
nix_flake_lock_flags_free(lockFlags);
|
||||
nix_flake_reference_free(flakeReference);
|
||||
nix_state_free(state);
|
||||
nix_flake_settings_free(settings);
|
||||
}
|
||||
|
||||
} // namespace nixC
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue