From 1d41600498cfa1c19d7bb0ef8b6f6e0cfb232d60 Mon Sep 17 00:00:00 2001 From: Yorick van Pelt Date: Fri, 14 Jul 2023 15:53:01 +0200 Subject: [PATCH] libstore: add C bindings --- src/libstore/globals.cc | 1 + src/libstore/nix_api_store.cc | 117 ++++++++++++++++++++++++ src/libstore/nix_api_store.h | 122 ++++++++++++++++++++++++++ src/libstore/nix_api_store_internal.h | 8 ++ 4 files changed, 248 insertions(+) create mode 100644 src/libstore/nix_api_store.cc create mode 100644 src/libstore/nix_api_store.h create mode 100644 src/libstore/nix_api_store_internal.h diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index fa0938d7b..b9ad8ac18 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -404,6 +404,7 @@ void assertLibStoreInitialized() { } void initLibStore() { + if (initLibStoreDone) return; initLibUtil(); diff --git a/src/libstore/nix_api_store.cc b/src/libstore/nix_api_store.cc new file mode 100644 index 000000000..312e5f2a8 --- /dev/null +++ b/src/libstore/nix_api_store.cc @@ -0,0 +1,117 @@ +#include "nix_api_store.h" +#include "nix_api_store_internal.h" +#include "nix_api_util.h" +#include "nix_api_util_internal.h" + +#include "store-api.hh" + +#include "globals.hh" + +struct StorePath { + nix::StorePath path; +}; + +nix_err nix_libstore_init(nix_c_context *context) { + if (context) + context->last_err_code = NIX_OK; + try { + nix::initLibStore(); + } + NIXC_CATCH_ERRS +} + +Store *nix_store_open(nix_c_context *context, const char *uri, + const char ***params) { + if (context) + context->last_err_code = NIX_OK; + try { + if (!uri) { + return new Store{nix::openStore()}; + } else { + std::string uri_str = uri; + if (!params) + return new Store{nix::openStore(uri_str)}; + + nix::Store::Params params_map; + for (size_t i = 0; params[i] != nullptr; i++) { + params_map[params[i][0]] = params[i][1]; + } + return new Store{nix::openStore(uri_str, params_map)}; + } + } + NIXC_CATCH_ERRS_NULL +} + +void nix_store_unref(Store *store) { delete store; } + +nix_err nix_store_get_uri(nix_c_context *context, Store *store, char *dest, + unsigned int n) { + if (context) + context->last_err_code = NIX_OK; + try { + auto res = store->ptr->getUri(); + return nix_export_std_string(context, res, dest, n); + } + NIXC_CATCH_ERRS +} + +nix_err nix_store_get_version(nix_c_context *context, Store *store, char *dest, + unsigned int n) { + if (context) + context->last_err_code = NIX_OK; + try { + auto res = store->ptr->getVersion(); + if (res) { + return nix_export_std_string(context, *res, dest, n); + } else { + return nix_set_err_msg(context, NIX_ERR_UNKNOWN, + "store does not have a version"); + } + } + NIXC_CATCH_ERRS +} + +bool nix_store_is_valid_path(nix_c_context *context, Store *store, + StorePath *path) { + if (context) + context->last_err_code = NIX_OK; + try { + return store->ptr->isValidPath(path->path); + } + NIXC_CATCH_ERRS_RES(false); +} + +StorePath *nix_store_parse_path(nix_c_context *context, Store *store, + const char *path) { + if (context) + context->last_err_code = NIX_OK; + try { + nix::StorePath s = store->ptr->parseStorePath(path); + return new StorePath{std::move(s)}; + } + NIXC_CATCH_ERRS_NULL +} + +nix_err nix_store_build(nix_c_context *context, Store *store, StorePath *path, + void (*iter)(const char *, const char *)) { + if (context) + context->last_err_code = NIX_OK; + try { + store->ptr->buildPaths({ + nix::DerivedPath::Built{ + .drvPath = path->path, + .outputs = nix::OutputsSpec::All{}, + }, + }); + if (iter) { + for (auto &[outputName, outputPath] : + store->ptr->queryDerivationOutputMap(path->path)) { + auto op = store->ptr->printStorePath(outputPath); + iter(outputName.c_str(), op.c_str()); + } + } + } + NIXC_CATCH_ERRS +} + +void nix_store_path_free(StorePath *sp) { delete sp; } diff --git a/src/libstore/nix_api_store.h b/src/libstore/nix_api_store.h new file mode 100644 index 000000000..1ab7a4eb7 --- /dev/null +++ b/src/libstore/nix_api_store.h @@ -0,0 +1,122 @@ +#ifndef NIX_API_STORE_H +#define NIX_API_STORE_H +/** @file + * @brief Main entry for the libexpr C bindings + */ + +#include "nix_api_util.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif +// cffi start + +/** @brief reference to a nix store */ +typedef struct Store Store; +/** @brief nix store path */ +typedef struct StorePath StorePath; + +/** + * @brief Initializes the Nix store library + * + * This function should be called before creating a Store + * This function can be called multiple times. + * + * @param[out] context Optional, stores error information + * @return NIX_OK if the initialization was successful, an error code otherwise. + */ +nix_err nix_libstore_init(nix_c_context *context); + +/** + * @brief Open a nix store + * @param[out] context Optional, stores error information + * @param[in] uri URI of the nix store, copied + * @param[in] params optional, array of key-value pairs, {{"endpoint", + * "https://s3.local"}} + * @return ref-counted Store pointer, NULL in case of errors + * @see nix_store_unref + */ +Store *nix_store_open(nix_c_context *, const char *uri, const char ***params); + +/** + * @brief Unref a nix store + * + * Does not fail. + * It'll be closed and deallocated when all references are gone. + * @param[in] builder the store to unref + */ +void nix_store_unref(Store *store); + +/** + * @brief get the URI of a nix store + * @param[out] context Optional, stores error information + * @param[in] store nix store reference + * @param[out] dest The allocated area to write the string to. + * @param[in] n Maximum size of the returned string. + * @return error code, NIX_OK on success. + */ +nix_err nix_store_get_uri(nix_c_context *context, Store *store, char *dest, + unsigned int n); + +// returns: owned StorePath* +/** + * @brief parse a nix store path into a StorePath + * + * Don't forget to free this path using nix_store_path_free + * @param[out] context Optional, stores error information + * @param[in] store nix store reference + * @param[in] path Path string to parse, copied + * @return owned store path, NULL on error + */ +StorePath *nix_store_parse_path(nix_c_context *context, Store *store, + const char *path); + +/** @brief Deallocate a nix StorePath + * + * Does not fail. + * @param[in] p the path to free + */ +void nix_store_path_free(StorePath *p); + +/** + * @brief check if a storepath is valid (exists in the store) + * @param[out] context Optional, stores error information + * @param[in] store nix store reference + * @param[in] path Path to check + * @return true or false, error info in context + */ +bool nix_store_is_valid_path(nix_c_context *context, Store *store, + StorePath *path); +// nix_err nix_store_ensure(Store*, const char*); +// nix_err nix_store_build_paths(Store*); +/** + * @brief Build a nix store path + * + * Blocking, calls cb once for each built output + * + * @param[out] context Optional, stores error information + * @param[in] store nix store reference + * @param[in] path Path to build + * @param[in] cb called for every built output + */ +nix_err nix_store_build(nix_c_context *context, Store *store, StorePath *path, + void (*cb)(const char *outname, const char *out)); + +/** + * @brief get the version of a nix store + * @param[out] context Optional, stores error information + * @param[in] store nix store reference + * @param[out] dest The allocated area to write the string to. + * @param[in] n Maximum size of the returned string. + * @return error code, NIX_OK on success. + */ +nix_err nix_store_get_version(nix_c_context *, Store *store, char *dest, + unsigned int n); + +// cffi end +#ifdef __cplusplus +} +#endif + +#endif // NIX_API_STORE_H diff --git a/src/libstore/nix_api_store_internal.h b/src/libstore/nix_api_store_internal.h new file mode 100644 index 000000000..59524ea8e --- /dev/null +++ b/src/libstore/nix_api_store_internal.h @@ -0,0 +1,8 @@ +#ifndef NIX_API_STORE_INTERNAL_H +#define NIX_API_STORE_INTERNAL_H +#include "store-api.hh" + +struct Store { + nix::ref ptr; +}; +#endif