Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 5 additions & 34 deletions src/libexpr-tests/main.cc
Original file line number Diff line number Diff line change
@@ -1,43 +1,14 @@
#include <gtest/gtest.h>
#include <cstdlib>
#include "nix/store/globals.hh"
#include "nix/util/logging.hh"

#include "nix/store/tests/test-main.hh"

using namespace nix;

int main(int argc, char ** argv)
{
if (argc > 1 && std::string_view(argv[1]) == "__build-remote") {
printError("test-build-remote: not supported in libexpr unit tests");
return 1;
}

// Disable build hook. We won't be testing remote builds in these unit tests. If we do, fix the above build hook.
settings.buildHook = {};

#ifdef __linux__ // should match the conditional around sandboxBuildDir declaration.

// When building and testing nix within the host's Nix sandbox, our store dir will be located in the host's
// sandboxBuildDir, e.g.: Host
// storeDir = /nix/store
// sandboxBuildDir = /build
// This process
// storeDir = /build/foo/bar/store
// sandboxBuildDir = /build
// However, we have a rule that the store dir must not be inside the storeDir, so we need to pick a different
// sandboxBuildDir.
settings.sandboxBuildDir = "/test-build-dir-instead-of-usual-build-dir";
#endif

#ifdef __APPLE__
// Avoid this error, when already running in a sandbox:
// sandbox-exec: sandbox_apply: Operation not permitted
settings.sandboxMode = smDisabled;
setEnv("_NIX_TEST_NO_SANDBOX", "1");
#endif

// For pipe operator tests in trivial.cc
experimentalFeatureSettings.set("experimental-features", "pipe-operators");
auto res = testMainForBuidingPre(argc, argv);
if (!res)
return res;
Comment on lines +9 to +11
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix the inverted logic condition.

The condition logic appears to be inverted. When testMainForBuidingPre returns 0 (EXIT_SUCCESS), the test should continue rather than exit.

Apply this fix:

    auto res = testMainForBuidingPre(argc, argv);
-    if (!res)
+    if (res)
        return res;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
auto res = testMainForBuidingPre(argc, argv);
if (!res)
return res;
auto res = testMainForBuidingPre(argc, argv);
if (res)
return res;
🤖 Prompt for AI Agents
In src/libexpr-tests/main.cc around lines 9 to 11, the logic is inverted:
currently it returns when testMainForBuidingPre returns 0 (success). Change the
condition to return only on non-zero (error) — e.g. check if (res != 0) or if
(res) and then return res; so the test continues when res == 0.


::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
Expand Down
188 changes: 184 additions & 4 deletions src/libstore-c/nix_api_store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ nix_store_get_version(nix_c_context * context, Store * store, nix_get_string_cal
NIXC_CATCH_ERRS
}

bool nix_store_is_valid_path(nix_c_context * context, Store * store, StorePath * path)
bool nix_store_is_valid_path(nix_c_context * context, Store * store, const StorePath * path)
{
if (context)
context->last_err_code = NIX_OK;
Expand Down Expand Up @@ -129,7 +129,7 @@ nix_err nix_store_realise(
Store * store,
StorePath * path,
void * userdata,
void (*callback)(void * userdata, const char *, const char *))
void (*callback)(void * userdata, const char *, const StorePath *))
{
if (context)
context->last_err_code = NIX_OK;
Expand All @@ -144,8 +144,8 @@ nix_err nix_store_realise(
if (callback) {
for (const auto & result : results) {
for (const auto & [outputName, realisation] : result.builtOutputs) {
auto op = store->ptr->printStorePath(realisation.outPath);
callback(userdata, outputName.c_str(), op.c_str());
StorePath p{realisation.outPath};
callback(userdata, outputName.c_str(), &p);
}
}
}
Expand All @@ -164,11 +164,74 @@ void nix_store_path_free(StorePath * sp)
delete sp;
}

void nix_derivation_free(nix_derivation * drv)
{
delete drv;
}

StorePath * nix_store_path_clone(const StorePath * p)
{
return new StorePath{p->path};
}

nix_derivation * nix_derivation_clone(const nix_derivation * d)
{
return new nix_derivation{d->drv};
}

nix_derivation * nix_derivation_from_json(nix_c_context * context, Store * store, const char * json)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto drv = nix::Derivation::fromJSON(*store->ptr, nlohmann::json::parse(json));

auto drvPath = nix::writeDerivation(*store->ptr, drv, nix::NoRepair, /* read only */ true);

drv.checkInvariants(*store->ptr, drvPath);

return new nix_derivation{drv};
}
NIXC_CATCH_ERRS_NULL
}

nix_err nix_derivation_make_outputs(
nix_c_context * context,
Store * store,
const char * json,
void (*callback)(void * userdata, const char * output_name, const char * path),
void * userdata)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto drv = nix::Derivation::fromJSON(*store->ptr, nlohmann::json::parse(json));
auto hashesModulo = hashDerivationModulo(*store->ptr, drv, true);

for (auto & output : drv.outputs) {
nix::Hash h = hashesModulo.hashes.at(output.first);
auto outPath = store->ptr->makeOutputPath(output.first, h, drv.name);

if (callback) {
callback(userdata, output.first.c_str(), store->ptr->printStorePath(outPath).c_str());
}
}
}
NIXC_CATCH_ERRS
}
Comment on lines +198 to +221
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

make_outputs: avoid temporary C-string; return StorePath

Switch to passing a borrowed StorePath to the callback (consistent with nix_store_realise) to prevent accidental retention of a dangling C-string.

-    void (*callback)(void * userdata, const char * output_name, const char * path),
+    void (*callback)(void * userdata, const char * output_name, const StorePath * path),
@@
-            if (callback) {
-                callback(userdata, output.first.c_str(), store->ptr->printStorePath(outPath).c_str());
-            }
+            if (callback) {
+                const StorePath tmp_path{outPath};
+                callback(userdata, output.first.c_str(), &tmp_path);
+            }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
nix_err nix_derivation_make_outputs(
nix_c_context * context,
Store * store,
const char * json,
void (*callback)(void * userdata, const char * output_name, const char * path),
void * userdata)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto drv = nix::Derivation::fromJSON(*store->ptr, nlohmann::json::parse(json));
auto hashesModulo = hashDerivationModulo(*store->ptr, drv, true);
for (auto & output : drv.outputs) {
nix::Hash h = hashesModulo.hashes.at(output.first);
auto outPath = store->ptr->makeOutputPath(output.first, h, drv.name);
if (callback) {
callback(userdata, output.first.c_str(), store->ptr->printStorePath(outPath).c_str());
}
}
}
NIXC_CATCH_ERRS
}
nix_err nix_derivation_make_outputs(
nix_c_context * context,
Store * store,
const char * json,
void (*callback)(void * userdata, const char * output_name, const StorePath * path),
void * userdata)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto drv = nix::Derivation::fromJSON(*store->ptr, nlohmann::json::parse(json));
auto hashesModulo = hashDerivationModulo(*store->ptr, drv, true);
for (auto & output : drv.outputs) {
nix::Hash h = hashesModulo.hashes.at(output.first);
auto outPath = store->ptr->makeOutputPath(output.first, h, drv.name);
if (callback) {
const StorePath tmp_path{outPath};
callback(userdata, output.first.c_str(), &tmp_path);
}
}
}
NIXC_CATCH_ERRS
}


StorePath * nix_add_derivation(nix_c_context * context, Store * store, nix_derivation * derivation)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto ret = nix::writeDerivation(*store->ptr, derivation->drv, nix::NoRepair);

return new StorePath{ret};
}
NIXC_CATCH_ERRS_NULL
}

nix_err nix_store_copy_closure(nix_c_context * context, Store * srcStore, Store * dstStore, StorePath * path)
{
if (context)
Expand All @@ -180,3 +243,120 @@ nix_err nix_store_copy_closure(nix_c_context * context, Store * srcStore, Store
}
NIXC_CATCH_ERRS
}

nix_err nix_store_drv_from_path(
nix_c_context * context,
Store * store,
const StorePath * path,
void (*callback)(void * userdata, const nix_derivation * drv),
void * userdata)
{
if (context)
context->last_err_code = NIX_OK;
try {
nix::Derivation drv = store->ptr->derivationFromPath(path->path);
if (callback) {
const nix_derivation tmp{drv};
callback(userdata, &tmp);
}
}
NIXC_CATCH_ERRS
}

nix_err nix_store_query_path_info(
nix_c_context * context,
Store * store,
const StorePath * store_path,
void * userdata,
void (*callback)(void * userdata, const StorePath * derived_path))
{
if (context)
context->last_err_code = NIX_OK;
try {
auto info = store->ptr->queryPathInfo(store_path->path);
if (callback) {
if (auto deriver = info->deriver) {
const StorePath deriver_tmp{*info->deriver};
callback(userdata, &deriver_tmp);
} else {
callback(userdata, nullptr);
}
}
}
NIXC_CATCH_ERRS
}

nix_err nix_derivation_get_outputs(
nix_c_context * context,
const nix_derivation * drv,
void (*callback)(void * userdata, const char * name, const nix_derivation_output * drv_output),
void * userdata)
{
if (context)
context->last_err_code = NIX_OK;
try {
if (callback) {
for (const auto & [name, result] : drv->drv.outputs) {
const nix_derivation_output tmp{result};
callback(userdata, name.c_str(), &tmp);
}
}
}
NIXC_CATCH_ERRS
}

nix_err nix_derivation_get_outputs_and_optpaths(
nix_c_context * context,
const nix_derivation * drv,
const Store * store,
void (*callback)(
void * userdata, const char * name, const nix_derivation_output * drv_output, const StorePath * path),
void * userdata)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto value = drv->drv.outputsAndOptPaths(store->ptr->config);
if (callback) {
for (const auto & [name, result] : value) {
const nix_derivation_output tmp_output{result.first};

if (auto store_path = result.second) {
const StorePath tmp_path{*store_path};
callback(userdata, name.c_str(), &tmp_output, &tmp_path);
} else {
callback(userdata, name.c_str(), &tmp_output, nullptr);
}
}
}
}
NIXC_CATCH_ERRS
}

nix_err nix_derivation_to_json(
nix_c_context * context,
const nix_derivation * drv,
const Store * store,
nix_get_string_callback callback,
void * userdata)
{
if (context)
context->last_err_code = NIX_OK;
try {
auto result = drv->drv.toJSON(store->ptr->config).dump();
if (callback) {
callback(result.data(), result.size(), userdata);
}
}
NIXC_CATCH_ERRS
}

nix_derivation_output * nix_derivation_output_clone(const nix_derivation_output * o)
{
return new nix_derivation_output{o->drv_out};
}

void nix_derivation_output_free(nix_derivation_output * o)
{
delete o;
}
Loading