1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-07-06 21:41:48 +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:
Robert Hensing 2025-04-02 16:59:07 +02:00
parent 1a3789e222
commit 8c903e0402
3 changed files with 328 additions and 26 deletions

View file

@ -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