From 0087d2848a11152b5aa0073fc086b717e16cb014 Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 10 Apr 2026 10:11:24 +1000 Subject: [PATCH 01/12] move verbosity.rs -> logging.rs --- nixide/src/lib.rs | 3 +- nixide/src/logging.rs | 76 +++++++++++++++++++++++++++++++++++++++++ nixide/src/verbosity.rs | 36 ------------------- 3 files changed, 77 insertions(+), 38 deletions(-) create mode 100644 nixide/src/logging.rs delete mode 100644 nixide/src/verbosity.rs diff --git a/nixide/src/lib.rs b/nixide/src/lib.rs index 6b336f2..f0b056c 100644 --- a/nixide/src/lib.rs +++ b/nixide/src/lib.rs @@ -8,10 +8,10 @@ pub extern crate nixide_sys as sys; pub(crate) mod errors; mod init; +pub mod logging; mod nix_settings; mod stdext; pub(crate) mod util; -mod verbosity; mod version; #[cfg(feature = "exprs")] @@ -23,7 +23,6 @@ mod store; pub use errors::{NixError, NixideError, NixideResult}; pub use nix_settings::{get_global_setting, set_global_setting}; -pub use verbosity::{NixVerbosity, set_verbosity}; pub use version::NixVersion; #[cfg(feature = "exprs")] diff --git a/nixide/src/logging.rs b/nixide/src/logging.rs new file mode 100644 index 0000000..87386e5 --- /dev/null +++ b/nixide/src/logging.rs @@ -0,0 +1,76 @@ +use crate::errors::ErrorContext; +use crate::stdext::AsCPtr as _; +use crate::sys; +use crate::util::wrap; +use crate::util::wrappers::AsInnerPtr as _; + +pub use sys::NixVerbosity; + +/// Sets the verbosity level. +/// +/// **This function should never fail!** +/// A panic would indicate a bug in nixide itself. +/// +/// # Nix C++ API Internals +/// +/// ```cpp +/// nix_err nix_set_verbosity(nix_c_context * context, nix_verbosity level) +/// { +/// if (context) +/// context->last_err_code = NIX_OK; +/// if (level > NIX_LVL_VOMIT || level < NIX_LVL_ERROR) +/// return nix_set_err_msg(context, NIX_ERR_UNKNOWN, "Invalid verbosity level"); +/// try { +/// nix::verbosity = static_cast(level); +/// } catch (...) { +/// return nix_context_error(context); +/// } +/// return NIX_OK; +/// } +/// ``` +/// +pub fn set_verbosity(level: NixVerbosity) { + wrap::nix_fn!(|ctx: &ErrorContext| unsafe { + sys::nix_set_verbosity(ctx.as_ptr(), level); + }) + .unwrap() +} + +/// The log formats `libnix` can output. +/// +/// # Nix C++ API Internals +/// +/// Defined in `/libmain/include/nix/main/loggers.hh`. +/// +pub enum LogFormat { + Raw, + RawWithLogs, + InternalJSON, + Bar, + BarWithLogs, +} + +impl ToString for LogFormat { + fn to_string(&self) -> String { + match self { + LogFormat::Raw => "raw".to_owned(), + LogFormat::RawWithLogs => "raw-with-logs".to_owned(), + LogFormat::InternalJSON => "internal-json".to_owned(), + LogFormat::Bar => "bar".to_owned(), + LogFormat::BarWithLogs => "bar-with-logs".to_owned(), + } + } +} + +/// Configure the global (default) logger's output format. +/// +/// **This function should never fail!** +/// A panic would indicate a nix's `enum LogFormat` has been +/// modified without nixide updating to account for this. +/// +pub fn set_log_format(format: LogFormat) { + wrap::nix_fn!(|ctx: &ErrorContext| unsafe { + sys::nix_set_log_format(ctx.as_ptr(), format.to_string().as_c_ptr().unwrap()); + }) + .unwrap() +} diff --git a/nixide/src/verbosity.rs b/nixide/src/verbosity.rs deleted file mode 100644 index 8e1b2c0..0000000 --- a/nixide/src/verbosity.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::errors::ErrorContext; -use crate::sys; -use crate::util::wrap; -use crate::util::wrappers::AsInnerPtr as _; - -pub use sys::NixVerbosity; - -/// Sets the verbosity level. -/// -/// **This function should never fail!** -/// A panic would indicate a bug in nixide itself. -/// -/// # Nix C++ API Internals -/// -/// ```cpp -/// nix_err nix_set_verbosity(nix_c_context * context, nix_verbosity level) -/// { -/// if (context) -/// context->last_err_code = NIX_OK; -/// if (level > NIX_LVL_VOMIT || level < NIX_LVL_ERROR) -/// return nix_set_err_msg(context, NIX_ERR_UNKNOWN, "Invalid verbosity level"); -/// try { -/// nix::verbosity = static_cast(level); -/// } catch (...) { -/// return nix_context_error(context); -/// } -/// return NIX_OK; -/// } -/// ``` -/// -pub fn set_verbosity(level: NixVerbosity) { - wrap::nix_fn!(|ctx: &ErrorContext| unsafe { - sys::nix_set_verbosity(ctx.as_ptr(), level); - }) - .unwrap() -} From 8cb5d1bf40f9669166bb699dbc90ad610bc400ec Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 10 Apr 2026 10:11:36 +1000 Subject: [PATCH 02/12] start plugin support --- nixide/src/lib.rs | 1 + nixide/src/plugins.rs | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 nixide/src/plugins.rs diff --git a/nixide/src/lib.rs b/nixide/src/lib.rs index f0b056c..fdb79ac 100644 --- a/nixide/src/lib.rs +++ b/nixide/src/lib.rs @@ -10,6 +10,7 @@ pub(crate) mod errors; mod init; pub mod logging; mod nix_settings; +pub mod plugins; mod stdext; pub(crate) mod util; mod version; diff --git a/nixide/src/plugins.rs b/nixide/src/plugins.rs new file mode 100644 index 0000000..216235f --- /dev/null +++ b/nixide/src/plugins.rs @@ -0,0 +1,10 @@ +use crate::NixideResult; +use crate::errors::ErrorContext; +use crate::util::wrap; +use crate::util::wrappers::AsInnerPtr as _; + +pub fn load_plugins() -> NixideResult<()> { + wrap::nix_fn!(|ctx: &ErrorContext| unsafe { + sys::nix_init_plugins(ctx.as_ptr()); + }) +} From 6573bffa581c0b9d1aa758bc7b68dce7fab136b6 Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 10 Apr 2026 10:12:06 +1000 Subject: [PATCH 03/12] nix_api_store now exposes derivation.h + store_path.h --- nixide-sys/include/nix-store.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nixide-sys/include/nix-store.h b/nixide-sys/include/nix-store.h index 3252ece..1c2ad65 100644 --- a/nixide-sys/include/nix-store.h +++ b/nixide-sys/include/nix-store.h @@ -6,4 +6,7 @@ #include // #include +#include +#include + #endif From eb3f19f4d2bfcf6e77cb8d2828ca03b07de910f5 Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 10 Apr 2026 10:12:33 +1000 Subject: [PATCH 04/12] add /.clangd --- .clangd | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .clangd diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..6418b4e --- /dev/null +++ b/.clangd @@ -0,0 +1,2 @@ +CompileFlags: + Add: [-std=c++23] From 50aec26a39cd52226e3d613cb27f1291c46562bc Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 10 Apr 2026 10:12:53 +1000 Subject: [PATCH 05/12] clean sys/build.rs --- nixide-sys/build.rs | 80 ++++++++++++++++++------------------------- nixide-sys/src/lib.rs | 2 +- 2 files changed, 35 insertions(+), 47 deletions(-) diff --git a/nixide-sys/build.rs b/nixide-sys/build.rs index 19c9e23..7bcfa95 100644 --- a/nixide-sys/build.rs +++ b/nixide-sys/build.rs @@ -92,36 +92,39 @@ const LIBS: &[&'static str] = &[ ]; fn main() { - let include_paths: Vec = LIBS + let libs: Vec = LIBS .iter() .map(|&name| { - let lib = pkg_config::probe_library(name) - .expect(&format!("Unable to find .pc file for {}", name)); - - for p in lib.link_files { - println!("cargo::rustc-link-lib={}", p.display()); - } - - lib.include_paths + pkg_config::probe_library(name).expect(&format!("Unable to find .pc file for {}", name)) }) + .collect(); + + let include_paths: Vec = libs + .clone() + .into_iter() + .map(|lib| lib.include_paths) + .flatten() + .unique() + .collect(); + let link_paths: Vec = libs + .clone() + .into_iter() + .map(|lib| lib.link_files) .flatten() .unique() .collect(); - // let clang_target = format!( - // "--target={}", - // env::var("CARGO_BUILD_TARGET") - // .expect("Environment variable `CARGO_BUILD_TARGET` not set! nixide/build.rs won't be able to set pointer sizes correctly!")); - let clang_args: Vec = vec![ - "-x", - "c++", - "-std=c++23", - "--target=x86_64-unknown-linux-gnu", // DEBUG - ] - .into_iter() - .map(|s: &str| s.to_owned()) - .chain(include_paths.iter().map(|p| format!("-I{}", p.display()))) - .collect(); + // ::DEBUG:DEBUG:: + // for path in link_paths { + // println!("cargo::rustc-link-lib={}", path.display()); + // } + // ::DEBUG:DEBUG:: + + let clang_args: Vec = vec!["-x", "c++", "-std=c++23"] + .into_iter() + .map(|s: &str| s.to_owned()) + .chain(include_paths.iter().map(|p| format!("-I{}", p.display()))) + .collect(); dbg!(&clang_args); @@ -139,7 +142,7 @@ fn main() { // .files(LIBS.iter().map(|s| (*s).strip_prefix("nix-").unwrap().strip_suffix("-c").unwrap())) .opt_level((!cfg!(debug_assertions)) as u32 * 3) .includes(&include_paths) - .compile("libnixide"); + .compile("nixide"); let mut builder = bindgen::Builder::default() .rust_edition(RustEdition::Edition2024) @@ -152,26 +155,11 @@ fn main() { .formatter(bindgen::Formatter::Rustfmt) .rustfmt_configuration_file(std::fs::canonicalize("rustfmt.toml").ok()) // Control allow/block listing - .allowlist_recursively(true) // DEBUG(TEMP): should remain `false` + .allowlist_recursively(true) // .allowlist_file(r".*nix_api_[a-z]+(_internal)?\.h") - .allowlist_file(r".*nix_api_[a-z]+\.h") + .allowlist_file(r".*nix_api_[a-z]+(/[a-z_]+)?\.h") - // .allowlist_type("nix_.*") - // .allowlist_function("nix_.*") - // DEBUG - // .allowlist_type(r"nix_locked_flake") - // .allowlist_type(r"nix_flake_settings") - // .allowlist_type(r"nix_flake_reference") - // .allowlist_type(r"nix_flake_reference_parse_flags") - // .allowlist_type(r"nix_flake_lock_flags") - // DEBUG - - // .allowlist_file(r".+-gcc-14\.3\.0/include/c\+\+/14\.3\.0/optional") // allow optional type - // .blocklist_file(r".*-gcc-[^/]+/include/c++/[0-9\.]+/^(optional).*") // allow optional type - // .blocklist_file(r".*-(glibc|clang-wrapper|boost)-.*") // block stdlib (gcc|glibc|clang-wrapper|boost) - // .blocklist_type(r".*Optional.*") - - .layout_tests(false) // DEBUG + // .layout_tests(false) // DEBUG .use_core() // use ::core instead of ::std .ctypes_prefix("::core::ffi") // use ::core::ffi instead of ::std::os::raw .time_phases(true) @@ -182,13 +170,13 @@ fn main() { .default_enum_style(bindgen::EnumVariation::Rust { non_exhaustive: false }) // .translate_enum_integer_types(false) .size_t_is_usize(true) - .use_distinct_char16_t(false) // DEBUG (comment this) + // .use_distinct_char16_t(false) // DEBUG .generate_comments(false) .generate_cstr(true) // use &CStr instead of &[u8] - .fit_macro_constants(true) // DEBUG (comment this) + .fit_macro_constants(false) .explicit_padding(true) - .enable_cxx_namespaces() - .represent_cxx_operators(false) // DEBUG (comment this) + // .enable_cxx_namespaces() + // .represent_cxx_operators(false) // DEBUG .enable_function_attribute_detection() .raw_line("/** These bindings were auto-generated for the Nixide project (https://github.com/cry128/nixide) */"); diff --git a/nixide-sys/src/lib.rs b/nixide-sys/src/lib.rs index 57ea9e7..93aceeb 100644 --- a/nixide-sys/src/lib.rs +++ b/nixide-sys/src/lib.rs @@ -20,7 +20,7 @@ mod bindings { include!(concat!(env!("OUT_DIR"), "/bindings.rs")); } -pub use bindings::root::*; +pub use bindings::*; mod exts; #[allow(unused_imports)] From c96289e688527fb5b865531e2293c3247149f6f3 Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 10 Apr 2026 10:13:04 +1000 Subject: [PATCH 06/12] libnixide_sys.so is unnecessary --- nixide-sys/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/nixide-sys/Cargo.toml b/nixide-sys/Cargo.toml index 41a1b93..f1f98e6 100644 --- a/nixide-sys/Cargo.toml +++ b/nixide-sys/Cargo.toml @@ -15,6 +15,7 @@ targets = [ "x86_64-unknown-linux-gnu" ] [lib] path = "src/lib.rs" +# crate-type = ["dylib"] # build libnixide_sys.so # NOTE: `[features]` have a 1-1 correspondence to the # NOTE: shared libraries produced by the Nix C API. From b7e9a69dd82f8f5ee0dbe0ffc4656a88697e80a6 Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 10 Apr 2026 10:13:26 +1000 Subject: [PATCH 07/12] support a nixide C API extension --- nixide-sys/libnixide-c/nixide_api_expr.cc | 0 nixide-sys/libnixide-c/nixide_api_expr.h | 12 ++++++++ nixide-sys/libnixide-c/nixide_api_fetchers.cc | 6 ++-- nixide-sys/libnixide-c/nixide_api_fetchers.h | 3 +- nixide-sys/libnixide-c/nixide_api_flake.cc | 14 ++++----- nixide-sys/libnixide-c/nixide_api_flake.h | 2 +- nixide-sys/libnixide-c/nixide_api_main.cc | 30 +++++++++++++++++++ nixide-sys/libnixide-c/nixide_api_main.h | 17 +++++++++++ nixide-sys/libnixide-c/nixide_api_store.cc | 0 nixide-sys/libnixide-c/nixide_api_store.h | 12 ++++++++ nixide-sys/libnixide-c/nixide_api_util.cc | 0 nixide-sys/libnixide-c/nixide_api_util.h | 12 ++++++++ 12 files changed, 96 insertions(+), 12 deletions(-) create mode 100644 nixide-sys/libnixide-c/nixide_api_expr.cc create mode 100644 nixide-sys/libnixide-c/nixide_api_expr.h create mode 100644 nixide-sys/libnixide-c/nixide_api_main.cc create mode 100644 nixide-sys/libnixide-c/nixide_api_main.h create mode 100644 nixide-sys/libnixide-c/nixide_api_store.cc create mode 100644 nixide-sys/libnixide-c/nixide_api_store.h create mode 100644 nixide-sys/libnixide-c/nixide_api_util.cc create mode 100644 nixide-sys/libnixide-c/nixide_api_util.h diff --git a/nixide-sys/libnixide-c/nixide_api_expr.cc b/nixide-sys/libnixide-c/nixide_api_expr.cc new file mode 100644 index 0000000..e69de29 diff --git a/nixide-sys/libnixide-c/nixide_api_expr.h b/nixide-sys/libnixide-c/nixide_api_expr.h new file mode 100644 index 0000000..d082784 --- /dev/null +++ b/nixide-sys/libnixide-c/nixide_api_expr.h @@ -0,0 +1,12 @@ +#ifndef NIXIDE_API_EXPR_H +#define NIXIDE_API_EXPR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // NIXIDE_API_EXPR_H diff --git a/nixide-sys/libnixide-c/nixide_api_fetchers.cc b/nixide-sys/libnixide-c/nixide_api_fetchers.cc index a8cd4e0..6dbbd03 100644 --- a/nixide-sys/libnixide-c/nixide_api_fetchers.cc +++ b/nixide-sys/libnixide-c/nixide_api_fetchers.cc @@ -1,7 +1,7 @@ -#include "nix_api_util_internal.h" -#include "nix_api_fetchers_internal.hh" +#include +#include -#include "nix/fetchers/fetch-settings.hh" +#include extern "C" { diff --git a/nixide-sys/libnixide-c/nixide_api_fetchers.h b/nixide-sys/libnixide-c/nixide_api_fetchers.h index 572eaff..7e906e4 100644 --- a/nixide-sys/libnixide-c/nixide_api_fetchers.h +++ b/nixide-sys/libnixide-c/nixide_api_fetchers.h @@ -1,9 +1,10 @@ #ifndef NIXIDE_API_FETCHERS_H #define NIXIDE_API_FETCHERS_H -#include "nix_api_fetchers.h" #include +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/nixide-sys/libnixide-c/nixide_api_flake.cc b/nixide-sys/libnixide-c/nixide_api_flake.cc index 4b9ec00..45ad079 100644 --- a/nixide-sys/libnixide-c/nixide_api_flake.cc +++ b/nixide-sys/libnixide-c/nixide_api_flake.cc @@ -1,12 +1,12 @@ // #include -// #include "nix_api_flake.h" -#include "nix_api_flake_internal.hh" -// #include "nix_api_util.h" -#include "nix_api_util_internal.h" -// #include "nix_api_expr_internal.h" -// #include "nix_api_fetchers_internal.hh" -// #include "nix_api_fetchers.h" +// #include +#include +// #include +#include +// #include +// #include +// #include #include "nix/flake/flake.hh" diff --git a/nixide-sys/libnixide-c/nixide_api_flake.h b/nixide-sys/libnixide-c/nixide_api_flake.h index 1cd279e..b51518d 100644 --- a/nixide-sys/libnixide-c/nixide_api_flake.h +++ b/nixide-sys/libnixide-c/nixide_api_flake.h @@ -1,7 +1,7 @@ #ifndef NIXIDE_API_FLAKE_H #define NIXIDE_API_FLAKE_H -#include "nix_api_flake.h" +#include #ifdef __cplusplus extern "C" { diff --git a/nixide-sys/libnixide-c/nixide_api_main.cc b/nixide-sys/libnixide-c/nixide_api_main.cc new file mode 100644 index 0000000..5e6fd92 --- /dev/null +++ b/nixide-sys/libnixide-c/nixide_api_main.cc @@ -0,0 +1,30 @@ +#include + +#include +#include + +#include + +extern "C" { + +nix_err nixide_register_plugin(nix_c_context * context, char * plugin) +{ + if (context) + context->last_err_code = NIX_OK; + if (plugin == nullptr) { + // TODO: should this be `NIX_ERR_RECOVERABLE` or `NIX_ERR_UNKNOWN`? + return nix_set_err_msg(context, NIX_ERR_RECOVERABLE, "Plugin is null"); + } + + void * handle = dlopen("libnixmainc.so", RTLD_LAZY | RTLD_GLOBAL); + if (!handle) { + return nix_set_err_msg(context, NIX_ERR_UNKNOWN, dlerror()); + } + + void * sym_addr = dlsym(handle, "pluginSettings"); + + try { + } + NIXC_CATCH_ERRS +} +} diff --git a/nixide-sys/libnixide-c/nixide_api_main.h b/nixide-sys/libnixide-c/nixide_api_main.h new file mode 100644 index 0000000..0962cf5 --- /dev/null +++ b/nixide-sys/libnixide-c/nixide_api_main.h @@ -0,0 +1,17 @@ +#ifndef NIXIDE_API_MAIN_H +#define NIXIDE_API_MAIN_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// NOTE: all plugins should be registered BEFORE `nix_init_plugins` is run +nix_err nixide_register_plugin(nix_c_context * context, char * plugin); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // NIXIDE_API_MAIN_H diff --git a/nixide-sys/libnixide-c/nixide_api_store.cc b/nixide-sys/libnixide-c/nixide_api_store.cc new file mode 100644 index 0000000..e69de29 diff --git a/nixide-sys/libnixide-c/nixide_api_store.h b/nixide-sys/libnixide-c/nixide_api_store.h new file mode 100644 index 0000000..51baab0 --- /dev/null +++ b/nixide-sys/libnixide-c/nixide_api_store.h @@ -0,0 +1,12 @@ +#ifndef NIXIDE_API_STORE_H +#define NIXIDE_API_STORE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // NIXIDE_API_STORE_H diff --git a/nixide-sys/libnixide-c/nixide_api_util.cc b/nixide-sys/libnixide-c/nixide_api_util.cc new file mode 100644 index 0000000..e69de29 diff --git a/nixide-sys/libnixide-c/nixide_api_util.h b/nixide-sys/libnixide-c/nixide_api_util.h new file mode 100644 index 0000000..4d610c3 --- /dev/null +++ b/nixide-sys/libnixide-c/nixide_api_util.h @@ -0,0 +1,12 @@ +#ifndef NIXIDE_API_UTIL_H +#define NIXIDE_API_UTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // NIXIDE_API_UTIL_H From a81691c4beb0c8f983e8723b3d2a066759040a01 Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 10 Apr 2026 10:13:45 +1000 Subject: [PATCH 08/12] restructure nixide feature flags --- nixide/Cargo.toml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/nixide/Cargo.toml b/nixide/Cargo.toml index 345f42f..d72f945 100644 --- a/nixide/Cargo.toml +++ b/nixide/Cargo.toml @@ -13,8 +13,9 @@ build = "build.rs" path = "src/lib.rs" [features] -default = [] -store = ["nixide-sys/nix-store-c"] +default = ["nix"] +nix = ["nixide-sys/nix-util-c", "nixide-sys/nix-main-c"] +store = ["nix", "nixide-sys/nix-store-c"] exprs = ["store", "nixide-sys/nix-expr-c"] flakes = ["exprs", "nixide-sys/nix-flake-c", "nixide-sys/nix-fetchers-c"] @@ -22,7 +23,7 @@ flakes = ["exprs", "nixide-sys/nix-flake-c", "nixide-sys/nix-fetchers-c"] libc = "0.2.183" stdext = "0.3.3" ctor = "0.6.3" -nixide-sys = { path = "../nixide-sys", version = "0.1.0", features = ["nix-util-c", "nix-main-c"]} +nixide-sys = { path = "../nixide-sys", version = "0.1.0" } tempfile = "3.27.0" [dev-dependencies] From d32c760213c5d6c8be7ed89d4d1c8c467d79bbb8 Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 10 Apr 2026 10:14:05 +1000 Subject: [PATCH 09/12] support NixErr::Recoverable --- nixide/src/errors/context.rs | 2 ++ nixide/src/errors/nix_error.rs | 27 +++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/nixide/src/errors/context.rs b/nixide/src/errors/context.rs index f04a10e..060ddd9 100644 --- a/nixide/src/errors/context.rs +++ b/nixide/src/errors/context.rs @@ -118,6 +118,8 @@ impl Into> for &ErrorContext { .unwrap_or_else(|| panic_issue_call_failed!()), }, + // XXX: WARNING: Recoverable only exists in later version of Nix + sys::NixErr::Recoverable => NixError::Recoverable, sys::NixErr::Unknown => NixError::Unknown, }; diff --git a/nixide/src/errors/nix_error.rs b/nixide/src/errors/nix_error.rs index a2c7789..23dfcf3 100644 --- a/nixide/src/errors/nix_error.rs +++ b/nixide/src/errors/nix_error.rs @@ -6,6 +6,22 @@ use crate::sys; /// produced by the libnix C API. #[derive(Debug, Clone)] pub enum NixError { + /// A recoverable error occurred. + /// + /// # Reason + /// + /// This is used primarily by C API *consumers* to communicate that a failed + /// primop call should be retried on the next evaluation attempt. + /// + /// # Nix C++ API Internals + /// + /// ```cpp + /// // `NIX_ERR_NIX_ERROR` variant of the `nix_err` enum type + /// NIX_ERR_RECOVERABLE = -4 + /// ``` + /// + Recoverable, + /// A generic Nix error occurred. /// /// # Reason @@ -19,6 +35,7 @@ pub enum NixError { /// // `NIX_ERR_NIX_ERROR` variant of the `nix_err` enum type /// NIX_ERR_NIX_ERROR = -4 /// ``` + /// ExprEval { name: String, info_msg: String }, /// A key/index access error occurred in C API functions. @@ -47,6 +64,7 @@ pub enum NixError { /// // `NIX_ERR_KEY` variant of the `nix_err` enum type /// NIX_ERR_KEY = -3 /// ``` + /// KeyNotFound(Option), /// An overflow error occurred. @@ -62,6 +80,7 @@ pub enum NixError { /// // `NIX_ERR_OVERFLOW` variant of the `nix_err` enum type /// NIX_ERR_OVERFLOW = -2 /// ``` + /// Overflow, /// An unknown error occurred. @@ -77,6 +96,7 @@ pub enum NixError { /// // `NIX_ERR_OVERFLOW` variant of the `nix_err` enum type /// NIX_ERR_UNKNOWN = -1 /// ``` + /// Unknown, /// @@ -95,12 +115,14 @@ pub enum NixError { /// This is solely a language difference between C++ and Rust, since /// [sys::NixErr] is defined over the *"continuous" (not realy)* /// type [::core::ffi::c_int]. + /// Undocumented(sys::NixErr), } impl Display for NixError { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { match self { + NixError::Recoverable => write!(f, "[libnix] Recoverable error occurred"), NixError::ExprEval { name, info_msg } => write!( f, "[libnix] NixExpr evaluation failed [name=\"{name}\", info_msg=\"{info_msg}\"]" @@ -120,12 +142,13 @@ impl Display for NixError { impl NixError { pub fn err_code(&self) -> sys::NixErr { match self { - NixError::Overflow => sys::NixErr::Overflow, - NixError::KeyNotFound(_) => sys::NixErr::Key, + NixError::Recoverable => sys::NixErr::Recoverable, NixError::ExprEval { name: _, info_msg: _, } => sys::NixErr::NixError, + NixError::KeyNotFound(_) => sys::NixErr::Key, + NixError::Overflow => sys::NixErr::Overflow, NixError::Unknown => sys::NixErr::NixError, NixError::Undocumented(err) => err.clone(), } From 8aebcdda5a8d56aaa95d61736c0a8970b7b50d37 Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 10 Apr 2026 10:14:18 +1000 Subject: [PATCH 10/12] label WriteAsNeeded as default --- nixide/src/flake/flake_lock_flags.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nixide/src/flake/flake_lock_flags.rs b/nixide/src/flake/flake_lock_flags.rs index 06f3554..9f5427d 100644 --- a/nixide/src/flake/flake_lock_flags.rs +++ b/nixide/src/flake/flake_lock_flags.rs @@ -12,6 +12,8 @@ use crate::util::wrappers::AsInnerPtr; pub enum FlakeLockMode { /// Configures [LockedFlake::lock] to make incremental changes to the lock file as needed. Changes are written to file. /// + /// This is the default mode. + /// WriteAsNeeded, /// Like [FlakeLockMode::WriteAsNeeded], but does not write to the lock file. From ecd88cd4c1596baaa83217ed618f58b49b588908 Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 10 Apr 2026 10:14:36 +1000 Subject: [PATCH 11/12] fix Rc> issues --- nixide/src/expr/realised_string.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/nixide/src/expr/realised_string.rs b/nixide/src/expr/realised_string.rs index 8cf08a4..5e10470 100644 --- a/nixide/src/expr/realised_string.rs +++ b/nixide/src/expr/realised_string.rs @@ -1,6 +1,7 @@ use std::cell::RefCell; use std::ffi::c_char; use std::ptr::NonNull; +use std::rc::Rc; use crate::errors::ErrorContext; use crate::expr::values::NixString; @@ -74,15 +75,18 @@ impl<'a> RealisedString<'a> { Ok(Self { inner: RefCell::new(inner), - path: Self::parse_path(inner.as_ptr(), &state.store_ref().borrow()), + path: Self::parse_path(inner.as_ptr(), state.store_ref().clone()), children: LazyArray::new( size, - Box::new(|_| StorePath::fake_path(&state.store_ref().borrow()).unwrap()), + Box::new(|_| StorePath::fake_path(state.store_ref().clone()).unwrap()), ), }) } - fn parse_path(realised_string: *mut sys::NixRealisedString, store: &Store) -> StorePath { + fn parse_path( + realised_string: *mut sys::NixRealisedString, + store: Rc>, + ) -> StorePath { let buffer_ptr = unsafe { sys::nix_realised_string_get_buffer_start(realised_string) }; let buffer_size = unsafe { sys::nix_realised_string_get_buffer_size(realised_string) }; From bc56ecca6e77432e292d02148d86876e13ddf034 Mon Sep 17 00:00:00 2001 From: _cry64 Date: Fri, 10 Apr 2026 10:14:46 +1000 Subject: [PATCH 12/12] update flake tests --- nixide/src/flake/locked_flake.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/nixide/src/flake/locked_flake.rs b/nixide/src/flake/locked_flake.rs index 3a76880..7a71fa6 100644 --- a/nixide/src/flake/locked_flake.rs +++ b/nixide/src/flake/locked_flake.rs @@ -166,7 +166,10 @@ mod tests { assert_eq!(flakeref.fragment(), "subthing"); - let outputs = LockedFlake::lock(, flakeref, &eval_state).unwrap().outputs().unwrap(); + let outputs = LockedFlake::lock(FlakeLockMode::WriteAsNeeded, flakeref, &eval_state) + .unwrap() + .outputs() + .unwrap(); assert!(matches!(outputs, Value::Attrs(_))); if let Value::Attrs(outputs) = outputs { @@ -262,9 +265,9 @@ mod tests { assert_eq!(flakeref_a.fragment(), ""); // Step 1: Do not update (check), fails - flake_lock_flags.set_mode(&FlakeLockMode::Check).unwrap(); + flake_lock_flags.set_mode(FlakeLockMode::Check).unwrap(); - let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state); + let locked_flake = LockedFlake::lock(FlakeLockMode::Check, flakeref_a, &eval_state); // Has not been locked and would need to write a lock file. assert!(locked_flake.is_err()); let saved_err = match locked_flake { @@ -273,7 +276,7 @@ mod tests { }; // Step 2: Update but do not write, succeeds - flake_lock_flags.set_mode(&FlakeLockMode::Virtual).unwrap(); + flake_lock_flags.set_mode(FlakeLockMode::Virtual).unwrap(); let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state).unwrap(); @@ -290,7 +293,7 @@ mod tests { } // Step 3: The lock was not written, so Step 1 would fail again - flake_lock_flags.set_mode(&FlakeLockMode::Check).unwrap(); + flake_lock_flags.set_mode(FlakeLockMode::Check).unwrap(); let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state); // Has not been locked and would need to write a lock file. @@ -303,7 +306,7 @@ mod tests { // Step 4: Update and write, succeeds flake_lock_flags - .set_mode(&FlakeLockMode::WriteAsNeeded) + .set_mode(FlakeLockMode::WriteAsNeeded) .unwrap(); let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state).unwrap(); @@ -321,7 +324,7 @@ mod tests { } // Step 5: Lock was written, so Step 1 succeeds - flake_lock_flags.set_mode(&FlakeLockMode::Check).unwrap(); + flake_lock_flags.set_mode(FlakeLockMode::Check).unwrap(); let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state).unwrap(); @@ -341,7 +344,7 @@ mod tests { // This shouldn't matter; write_as_needed will be overridden flake_lock_flags - .set_mode(&FlakeLockMode::WriteAsNeeded) + .set_mode(FlakeLockMode::WriteAsNeeded) .unwrap(); let flakeref_c = FlakeRef::parse(&format!("path:{}", &flake_dir_c_str)).unwrap(); @@ -367,7 +370,7 @@ mod tests { let mut flake_lock_flags = FlakeLockFlags::new(&flake_settings).unwrap(); // Step 7: Override was not written; lock still points to b - flake_lock_flags.set_mode(&FlakeLockMode::Check).unwrap(); + flake_lock_flags.set_mode(FlakeLockMode::Check).unwrap(); let locked_flake = LockedFlake::lock(flake_lock_flags, flakeref_a, &eval_state).unwrap();