#![cfg(feature = "store")]
use std::{
ffi::{CStr, CString},
ptr::NonNull,
};
use crate::{
Error,
Result,
error::{check_err, string_from_callback},
sys,
};
#[must_use]
pub fn nix_version() -> &'static str {
unsafe {
let ptr = sys::nix_version_get();
if ptr.is_null() {
"<unknown>"
} else {
CStr::from_ptr(ptr).to_str().unwrap_or("<unknown>")
}
}
}
pub fn is_pure_eval() -> bool {
unsafe {
let val = string_from_callback(|cb, ud| {
sys::nix_setting_get(std::ptr::null_mut(), c"pure-eval".as_ptr(), cb, ud);
});
val.as_deref() == Some("true")
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Verbosity {
Error,
Warn,
Notice,
Info,
Talkative,
Chatty,
Debug,
Vomit,
}
impl Verbosity {
fn to_c(self) -> sys::nix_verbosity {
match self {
Verbosity::Error => sys::nix_verbosity_NIX_LVL_ERROR,
Verbosity::Warn => sys::nix_verbosity_NIX_LVL_WARN,
Verbosity::Notice => sys::nix_verbosity_NIX_LVL_NOTICE,
Verbosity::Info => sys::nix_verbosity_NIX_LVL_INFO,
Verbosity::Talkative => sys::nix_verbosity_NIX_LVL_TALKATIVE,
Verbosity::Chatty => sys::nix_verbosity_NIX_LVL_CHATTY,
Verbosity::Debug => sys::nix_verbosity_NIX_LVL_DEBUG,
Verbosity::Vomit => sys::nix_verbosity_NIX_LVL_VOMIT,
}
}
}
pub struct Context {
inner: NonNull<sys::nix_c_context>,
}
impl Context {
pub fn new() -> Result<Self> {
Self::new_inner(false)
}
pub fn new_no_load_config() -> Result<Self> {
Self::new_inner(true)
}
fn new_inner(no_load_config: bool) -> Result<Self> {
let ctx_ptr = unsafe { sys::nix_c_context_create() };
let inner = NonNull::new(ctx_ptr).ok_or(Error::NullPointer)?;
let ctx = Context { inner };
static INIT: std::sync::Once = std::sync::Once::new();
let mut init_err: Result<()> = Ok(());
INIT.call_once(|| {
let r = (|| unsafe {
check_err(
ctx.inner.as_ptr(),
sys::nix_libutil_init(ctx.inner.as_ptr()),
)?;
let store_err = if no_load_config {
sys::nix_libstore_init_no_load_config(ctx.inner.as_ptr())
} else {
sys::nix_libstore_init(ctx.inner.as_ptr())
};
check_err(ctx.inner.as_ptr(), store_err)?;
check_err(
ctx.inner.as_ptr(),
sys::nix_libexpr_init(ctx.inner.as_ptr()),
)
})();
init_err = r;
});
init_err?;
Ok(ctx)
}
pub fn set_setting(&self, key: &str, value: &str) -> Result<()> {
let key_c = CString::new(key)?;
let value_c = CString::new(value)?;
unsafe {
check_err(
self.inner.as_ptr(),
sys::nix_setting_set(
self.inner.as_ptr(),
key_c.as_ptr(),
value_c.as_ptr(),
),
)
}
}
pub fn get_setting(&self, key: &str) -> Result<String> {
let key_c = CString::new(key)?;
let mut err_code = sys::nix_err_NIX_OK;
let result = unsafe {
string_from_callback(|cb, ud| {
err_code =
sys::nix_setting_get(self.inner.as_ptr(), key_c.as_ptr(), cb, ud);
})
};
check_err(self.inner.as_ptr(), err_code)?;
result.ok_or_else(|| Error::KeyNotFound(key.to_string()))
}
pub fn set_verbosity(&self, level: Verbosity) -> Result<()> {
unsafe {
check_err(
self.inner.as_ptr(),
sys::nix_set_verbosity(self.inner.as_ptr(), level.to_c()),
)
}
}
pub fn clear_error(&self) {
unsafe { sys::nix_clear_err(self.inner.as_ptr()) };
}
#[cfg(feature = "main")]
pub fn init_plugins(&self) -> Result<()> {
unsafe {
check_err(
self.inner.as_ptr(),
sys::nix_init_plugins(self.inner.as_ptr()),
)
}
}
#[cfg(feature = "main")]
pub fn set_log_format(&self, format: &str) -> Result<()> {
let format_c = CString::new(format)?;
unsafe {
check_err(
self.inner.as_ptr(),
sys::nix_set_log_format(self.inner.as_ptr(), format_c.as_ptr()),
)
}
}
#[cfg(feature = "expr")]
pub fn gc_now() {
unsafe { sys::nix_gc_now() };
}
pub(crate) unsafe fn as_ptr(&self) -> *mut sys::nix_c_context {
self.inner.as_ptr()
}
}
impl Drop for Context {
fn drop(&mut self) {
unsafe {
sys::nix_c_context_free(self.inner.as_ptr());
}
}
}
unsafe impl Send for Context {}