Skip to content

Commit 05990fb

Browse files
authored
Merge pull request #14555 from NixOS/more-store-ffi
libstore-c: Add new derivation and store path functions
2 parents c72f3dc + 1c10ce6 commit 05990fb

File tree

6 files changed

+330
-3
lines changed

6 files changed

+330
-3
lines changed

src/libstore-c/nix_api_store.cc

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#include <cstring>
2+
#include <span>
3+
14
#include "nix_api_store.h"
25
#include "nix_api_store_internal.h"
36
#include "nix_api_util.h"
@@ -8,6 +11,7 @@
811
#include "nix/store/store-open.hh"
912
#include "nix/store/build-result.hh"
1013
#include "nix/store/local-fs-store.hh"
14+
#include "nix/util/base-nix-32.hh"
1115

1216
#include "nix/store/globals.hh"
1317

@@ -215,7 +219,65 @@ void nix_derivation_free(nix_derivation * drv)
215219

216220
StorePath * nix_store_path_clone(const StorePath * p)
217221
{
218-
return new StorePath{p->path};
222+
try {
223+
return new StorePath{p->path};
224+
} catch (...) {
225+
return nullptr;
226+
}
227+
}
228+
229+
} // extern "C"
230+
231+
template<size_t S>
232+
static auto to_cpp_array(const uint8_t (&r)[S])
233+
{
234+
return reinterpret_cast<const std::array<std::byte, S> &>(r);
235+
}
236+
237+
extern "C" {
238+
239+
nix_err
240+
nix_store_path_hash(nix_c_context * context, const StorePath * store_path, nix_store_path_hash_part * hash_part_out)
241+
{
242+
try {
243+
auto hashPart = store_path->path.hashPart();
244+
// Decode from Nix32 (base32) encoding to raw bytes
245+
auto decoded = nix::BaseNix32::decode(hashPart);
246+
247+
assert(decoded.size() == sizeof(hash_part_out->bytes));
248+
std::memcpy(hash_part_out->bytes, decoded.data(), sizeof(hash_part_out->bytes));
249+
return NIX_OK;
250+
}
251+
NIXC_CATCH_ERRS
252+
}
253+
254+
StorePath * nix_store_create_from_parts(
255+
nix_c_context * context, const nix_store_path_hash_part * hash, const char * name, size_t name_len)
256+
{
257+
if (context)
258+
context->last_err_code = NIX_OK;
259+
try {
260+
// Encode the 20 raw bytes to Nix32 (base32) format
261+
auto hashStr = nix::BaseNix32::encode(std::span<const std::byte>{to_cpp_array(hash->bytes)});
262+
263+
// Construct the store path basename: <hash>-<name>
264+
std::string baseName;
265+
baseName += hashStr;
266+
baseName += "-";
267+
baseName += std::string_view{name, name_len};
268+
269+
return new StorePath{nix::StorePath(std::move(baseName))};
270+
}
271+
NIXC_CATCH_ERRS_NULL
272+
}
273+
274+
nix_derivation * nix_derivation_clone(const nix_derivation * d)
275+
{
276+
try {
277+
return new nix_derivation{d->drv};
278+
} catch (...) {
279+
return nullptr;
280+
}
219281
}
220282

221283
nix_derivation * nix_derivation_from_json(nix_c_context * context, Store * store, const char * json)
@@ -228,6 +290,20 @@ nix_derivation * nix_derivation_from_json(nix_c_context * context, Store * store
228290
NIXC_CATCH_ERRS_NULL
229291
}
230292

293+
nix_err nix_derivation_to_json(
294+
nix_c_context * context, const nix_derivation * drv, nix_get_string_callback callback, void * userdata)
295+
{
296+
if (context)
297+
context->last_err_code = NIX_OK;
298+
try {
299+
auto result = static_cast<nlohmann::json>(drv->drv).dump();
300+
if (callback) {
301+
callback(result.data(), result.size(), userdata);
302+
}
303+
}
304+
NIXC_CATCH_ERRS
305+
}
306+
231307
StorePath * nix_add_derivation(nix_c_context * context, Store * store, nix_derivation * derivation)
232308
{
233309
if (context)
@@ -252,4 +328,14 @@ nix_err nix_store_copy_closure(nix_c_context * context, Store * srcStore, Store
252328
NIXC_CATCH_ERRS
253329
}
254330

331+
nix_derivation * nix_store_drv_from_store_path(nix_c_context * context, Store * store, const StorePath * path)
332+
{
333+
if (context)
334+
context->last_err_code = NIX_OK;
335+
try {
336+
return new nix_derivation{store->ptr->derivationFromPath(path->path)};
337+
}
338+
NIXC_CATCH_ERRS_NULL
339+
}
340+
255341
} // extern "C"

src/libstore-c/nix_api_store.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ nix_err
106106
nix_store_get_storedir(nix_c_context * context, Store * store, nix_get_string_callback callback, void * user_data);
107107

108108
/**
109-
* @brief Parse a Nix store path into a StorePath
109+
* @brief Parse a Nix store path that includes the store dir into a StorePath
110110
*
111111
* @note Don't forget to free this path using nix_store_path_free()!
112112
* @param[out] context Optional, stores error information
@@ -188,9 +188,16 @@ nix_store_get_version(nix_c_context * context, Store * store, nix_get_string_cal
188188
/**
189189
* @brief Create a `nix_derivation` from a JSON representation of that derivation.
190190
*
191+
* @note Unlike `nix_derivation_to_json`, this needs a `Store`. This is because
192+
* over time we expect the internal representation of derivations in Nix to
193+
* differ from accepted derivation formats. The store argument is here to help
194+
* any logic needed to convert from JSON to the internal representation, in
195+
* excess of just parsing.
196+
*
191197
* @param[out] context Optional, stores error information.
192198
* @param[in] store nix store reference.
193199
* @param[in] json JSON of the derivation as a string.
200+
* @return A new derivation, or NULL on error. Free with `nix_derivation_free` when done using the `nix_derivation`.
194201
*/
195202
nix_derivation * nix_derivation_from_json(nix_c_context * context, Store * store, const char * json);
196203

@@ -242,6 +249,16 @@ nix_err nix_store_get_fs_closure(
242249
void * userdata,
243250
void (*callback)(nix_c_context * context, void * userdata, const StorePath * store_path));
244251

252+
/**
253+
* @brief Returns the derivation associated with the store path
254+
*
255+
* @param[out] context Optional, stores error information
256+
* @param[in] store The nix store
257+
* @param[in] path The nix store path
258+
* @return A new derivation, or NULL on error. Free with `nix_derivation_free` when done using the `nix_derivation`.
259+
*/
260+
nix_derivation * nix_store_drv_from_store_path(nix_c_context * context, Store * store, const StorePath * path);
261+
245262
// cffi end
246263
#ifdef __cplusplus
247264
}

src/libstore-c/nix_api_store/derivation.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ extern "C" {
2020
/** @brief Nix Derivation */
2121
typedef struct nix_derivation nix_derivation;
2222

23+
/**
24+
* @brief Copy a `nix_derivation`
25+
*
26+
* @param[in] d the derivation to copy
27+
* @return a new `nix_derivation`
28+
*/
29+
nix_derivation * nix_derivation_clone(const nix_derivation * d);
30+
2331
/**
2432
* @brief Deallocate a `nix_derivation`
2533
*
@@ -28,6 +36,17 @@ typedef struct nix_derivation nix_derivation;
2836
*/
2937
void nix_derivation_free(nix_derivation * drv);
3038

39+
/**
40+
* @brief Gets the derivation as a JSON string
41+
*
42+
* @param[out] context Optional, stores error information
43+
* @param[in] drv The derivation
44+
* @param[in] callback Called with the JSON string
45+
* @param[in] userdata Arbitrary data passed to the callback
46+
*/
47+
nix_err nix_derivation_to_json(
48+
nix_c_context * context, const nix_derivation * drv, nix_get_string_callback callback, void * userdata);
49+
3150
// cffi end
3251
#ifdef __cplusplus
3352
}

src/libstore-c/nix_api_store/store_path.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
* @brief Store path operations
1111
*/
1212

13+
#include <stddef.h>
14+
#include <stdint.h>
15+
1316
#include "nix_api_util.h"
1417

1518
#ifdef __cplusplus
@@ -44,6 +47,45 @@ void nix_store_path_free(StorePath * p);
4447
*/
4548
void nix_store_path_name(const StorePath * store_path, nix_get_string_callback callback, void * user_data);
4649

50+
/**
51+
* @brief A store path hash
52+
*
53+
* Once decoded from "nix32" encoding, a store path hash is 20 raw bytes.
54+
*/
55+
typedef struct nix_store_path_hash_part
56+
{
57+
uint8_t bytes[20];
58+
} nix_store_path_hash_part;
59+
60+
/**
61+
* @brief Get the path hash (e.g. "<hash>" in /nix/store/<hash>-<name>)
62+
*
63+
* The hash is returned as raw bytes, decoded from "nix32" encoding.
64+
*
65+
* @param[out] context Optional, stores error information
66+
* @param[in] store_path the path to get the hash from
67+
* @param[out] hash_part_out the decoded hash as 20 raw bytes
68+
* @return NIX_OK on success, error code on failure
69+
*/
70+
nix_err
71+
nix_store_path_hash(nix_c_context * context, const StorePath * store_path, nix_store_path_hash_part * hash_part_out);
72+
73+
/**
74+
* @brief Create a StorePath from its constituent parts (hash and name)
75+
*
76+
* This function constructs a store path from a hash and name, without needing
77+
* a Store reference or the store directory prefix.
78+
*
79+
* @note Don't forget to free this path using nix_store_path_free()!
80+
* @param[out] context Optional, stores error information
81+
* @param[in] hash The store path hash (20 raw bytes)
82+
* @param[in] name The store path name (the part after the hash)
83+
* @param[in] name_len Length of the name string
84+
* @return owned store path, NULL on error
85+
*/
86+
StorePath * nix_store_create_from_parts(
87+
nix_c_context * context, const nix_store_path_hash_part * hash, const char name[/*name_len*/], size_t name_len);
88+
4789
// cffi end
4890
#ifdef __cplusplus
4991
}

0 commit comments

Comments
 (0)