Skip to content

Commit 91bb0a1

Browse files
Ericson2314RossComputerGuyroberth
committed
libstore-c: Add new derivation and store path functions
Add several new functions to the C API: StorePath operations: - nix_store_path_hash: Extract the hash part from a store path - nix_store_create_from_parts: Construct a store path from hash and name Derivation operations: - nix_derivation_clone: Clone a derivation - nix_derivation_to_json: Serialize a derivation to JSON Store operations: - nix_store_drv_from_store_path: Load a derivation from a store path - nix_store_query_path_info: Query path info as JSON - nix_store_build_paths: Build multiple paths and get results Test, and improve documentation of some existing functions to better distinguish them, also. Co-authored-by: Tristan Ross <[email protected]> Co-authored-by: Robert Hensing <[email protected]>
1 parent 09a9e08 commit 91bb0a1

File tree

5 files changed

+343
-1
lines changed

5 files changed

+343
-1
lines changed

src/libstore-c/nix_api_store.cc

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
#include "nix/store/local-fs-store.hh"
1111

1212
#include "nix/store/globals.hh"
13+
#include "nix/util/base-nix-32.hh"
14+
15+
#include <cstring>
16+
#include <span>
1317

1418
extern "C" {
1519

@@ -218,6 +222,46 @@ StorePath * nix_store_path_clone(const StorePath * p)
218222
return new StorePath{p->path};
219223
}
220224

225+
nix_err nix_store_path_hash(nix_c_context * context, const StorePath * store_path, nix_store_path_hash_part * hash_part_out)
226+
{
227+
try {
228+
auto hashPart = store_path->path.hashPart();
229+
// Decode from Nix32 (base32) encoding to raw bytes
230+
auto decoded = nix::BaseNix32::decode(hashPart);
231+
232+
assert(decoded.size() == 20);
233+
std::memcpy(hash_part_out->bytes, decoded.data(), 20);
234+
return NIX_OK;
235+
}
236+
NIXC_CATCH_ERRS
237+
}
238+
239+
StorePath * nix_store_create_from_parts(
240+
nix_c_context * context, const nix_store_path_hash_part * hash, const char * name, size_t name_len)
241+
{
242+
if (context)
243+
context->last_err_code = NIX_OK;
244+
try {
245+
// Encode the 20 raw bytes to Nix32 (base32) format
246+
auto hashStr =
247+
nix::BaseNix32::encode(std::span<const std::byte>(reinterpret_cast<const std::byte *>(hash->bytes), 20));
248+
249+
// Construct the store path basename: <hash>-<name>
250+
std::string baseName;
251+
baseName += hashStr;
252+
baseName += "-";
253+
baseName += std::string_view{name, name_len};
254+
255+
return new StorePath{nix::StorePath(std::move(baseName))};
256+
}
257+
NIXC_CATCH_ERRS_NULL
258+
}
259+
260+
nix_derivation * nix_derivation_clone(const nix_derivation * d)
261+
{
262+
return new nix_derivation{d->drv};
263+
}
264+
221265
nix_derivation * nix_derivation_from_json(nix_c_context * context, Store * store, const char * json)
222266
{
223267
if (context)
@@ -228,6 +272,20 @@ nix_derivation * nix_derivation_from_json(nix_c_context * context, Store * store
228272
NIXC_CATCH_ERRS_NULL
229273
}
230274

275+
nix_err nix_derivation_to_json(
276+
nix_c_context * context, const nix_derivation * drv, nix_get_string_callback callback, void * userdata)
277+
{
278+
if (context)
279+
context->last_err_code = NIX_OK;
280+
try {
281+
auto result = static_cast<nlohmann::json>(drv->drv).dump();
282+
if (callback) {
283+
callback(result.data(), result.size(), userdata);
284+
}
285+
}
286+
NIXC_CATCH_ERRS
287+
}
288+
231289
StorePath * nix_add_derivation(nix_c_context * context, Store * store, nix_derivation * derivation)
232290
{
233291
if (context)
@@ -252,4 +310,67 @@ nix_err nix_store_copy_closure(nix_c_context * context, Store * srcStore, Store
252310
NIXC_CATCH_ERRS
253311
}
254312

313+
nix_derivation * nix_store_drv_from_store_path(
314+
nix_c_context * context,
315+
Store * store,
316+
const StorePath * path)
317+
{
318+
if (context)
319+
context->last_err_code = NIX_OK;
320+
try {
321+
return new nix_derivation{store->ptr->derivationFromPath(path->path)};
322+
}
323+
NIXC_CATCH_ERRS_NULL
324+
}
325+
326+
nix_err nix_store_query_path_info(
327+
nix_c_context * context,
328+
Store * store,
329+
const StorePath * store_path,
330+
void * userdata,
331+
nix_get_string_callback callback)
332+
{
333+
if (context)
334+
context->last_err_code = NIX_OK;
335+
try {
336+
auto info = store->ptr->queryPathInfo(store_path->path);
337+
if (callback) {
338+
auto result = info->toJSON(&*store->ptr, true).dump();
339+
callback(result.data(), result.size(), userdata);
340+
}
341+
}
342+
NIXC_CATCH_ERRS
343+
}
344+
345+
nix_err nix_store_build_paths(
346+
nix_c_context * context,
347+
Store * store,
348+
const StorePath ** store_paths,
349+
unsigned int num_store_paths,
350+
void (*callback)(void * userdata, const char * path, const char * result),
351+
void * userdata)
352+
{
353+
if (context)
354+
context->last_err_code = NIX_OK;
355+
try {
356+
std::span<const StorePath * const> paths_span(store_paths, num_store_paths);
357+
358+
std::vector<nix::DerivedPath> derived_paths;
359+
for (const StorePath * store_path : paths_span) {
360+
derived_paths.push_back(nix::SingleDerivedPath::Opaque{store_path->path});
361+
}
362+
363+
auto results = store->ptr->buildPathsWithResults(derived_paths);
364+
for (auto & result : results) {
365+
if (callback) {
366+
callback(
367+
userdata,
368+
result.path.to_string(store->ptr->config).c_str(),
369+
static_cast<nlohmann::json>(result).dump().c_str());
370+
}
371+
}
372+
}
373+
NIXC_CATCH_ERRS
374+
}
375+
255376
} // extern "C"

src/libstore-c/nix_api_store.h

Lines changed: 60 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,6 +188,12 @@ 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.
@@ -242,6 +248,59 @@ nix_err nix_store_get_fs_closure(
242248
void * userdata,
243249
void (*callback)(nix_c_context * context, void * userdata, const StorePath * store_path));
244250

251+
/**
252+
* @brief Returns the derivation associated with the store path
253+
*
254+
* @param[out] context Optional, stores error information
255+
* @param[in] store The nix store
256+
* @param[in] path The nix store path
257+
* @return A new derivation, or NULL on error
258+
*/
259+
nix_derivation * nix_store_drv_from_store_path(
260+
nix_c_context * context,
261+
Store * store,
262+
const StorePath * path);
263+
264+
/**
265+
* @brief Queries for the nix store path info JSON.
266+
*
267+
* @param[out] context Optional, stores error information
268+
* @param[in] store nix store reference
269+
* @param[in] path A store path
270+
* @param[in] userdata The data to pass to the callback
271+
* @param[in] callback Called for when the path info is resolved
272+
*/
273+
nix_err nix_store_query_path_info(
274+
nix_c_context * context,
275+
Store * store,
276+
const StorePath * store_path,
277+
void * userdata,
278+
nix_get_string_callback callback);
279+
280+
/**
281+
* @brief Builds the paths, if they are a derivation then they get built.
282+
*
283+
* @note Path and result for the callback only exist for the lifetime of
284+
* the call. Result is a string containing the build result in JSON.
285+
*
286+
* @param[out] context Optional, stores error information
287+
* @param[in] store nix store reference
288+
* @param[in] store_paths Pointer to list of nix store paths
289+
* @param[in] num_store_paths Number of nix store paths
290+
* @param[in] callback The callback to trigger for each build result. Called with:
291+
* - userdata: user-provided data
292+
* - path: the path that was built (string, only valid for duration of callback)
293+
* - result: JSON string of the build result (only valid for duration of callback)
294+
* @param[in] userdata User data to pass to the callback
295+
*/
296+
nix_err nix_store_build_paths(
297+
nix_c_context * context,
298+
Store * store,
299+
const StorePath ** store_paths,
300+
unsigned int num_store_paths,
301+
void (*callback)(void * userdata, const char * path, const char * result),
302+
void * userdata);
303+
245304
// cffi end
246305
#ifdef __cplusplus
247306
}

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: 41 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,44 @@ 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 nix_store_path_hash(nix_c_context * context, const StorePath *store_path, nix_store_path_hash_part * hash_part_out);
71+
72+
/**
73+
* @brief Create a StorePath from its constituent parts (hash and name)
74+
*
75+
* This function constructs a store path from a hash and name, without needing
76+
* a Store reference or the store directory prefix.
77+
*
78+
* @note Don't forget to free this path using nix_store_path_free()!
79+
* @param[out] context Optional, stores error information
80+
* @param[in] hash The store path hash (20 raw bytes)
81+
* @param[in] name The store path name (the part after the hash)
82+
* @param[in] name_len Length of the name string
83+
* @return owned store path, NULL on error
84+
*/
85+
StorePath * nix_store_create_from_parts(
86+
nix_c_context * context, const nix_store_path_hash_part * hash, const char name[/*name_len*/], size_t name_len);
87+
4788
// cffi end
4889
#ifdef __cplusplus
4990
}

0 commit comments

Comments
 (0)