oh we're pushing

This commit is contained in:
do butterflies cry? 2026-03-25 11:12:45 +10:00
parent ff28c6f13f
commit ab9886281a
Signed by: cry
GPG key ID: F68745A836CA0412
4 changed files with 79 additions and 55 deletions

View file

@ -197,10 +197,9 @@ impl Store {
/// ///
/// ```no_run /// ```no_run
/// # use std::sync::Arc; /// # use std::sync::Arc;
/// # use nixide::{Context, Store}; /// # use nixide::Store;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> { /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let ctx = Arc::new(Context::new()?); /// let store = Store::open(None)?;
/// let store = Store::open(&ctx, None)?;
/// let path = store.store_path("/nix/store/...")?; /// let path = store.store_path("/nix/store/...")?;
/// # Ok(()) /// # Ok(())
/// # } /// # }

View file

@ -7,9 +7,9 @@ use crate::errors::{new_nixide_error, ErrorContext};
use crate::util::panic_issue_call_failed; use crate::util::panic_issue_call_failed;
use crate::util::wrap; use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr; use crate::util::wrappers::AsInnerPtr;
use crate::NixideError; use crate::NixideResult;
use nixide_sys::{self as sys, nix_err_NIX_OK}; use nixide_sys as sys;
/// A path in the Nix store. /// A path in the Nix store.
/// ///
@ -36,7 +36,7 @@ impl StorePath {
/// # Errors /// # Errors
/// ///
/// Returns an error if the path cannot be parsed. /// Returns an error if the path cannot be parsed.
pub fn parse(store: &Store, path: &str) -> Result<Self, NixideError> { pub fn parse(store: &Store, path: &str) -> NixideResult<Self> {
let c_path = CString::new(path).or(Err(new_nixide_error!(StringNulByte)))?; let c_path = CString::new(path).or(Err(new_nixide_error!(StringNulByte)))?;
let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe { let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe {
@ -46,6 +46,10 @@ impl StorePath {
Ok(Self { inner }) Ok(Self { inner })
} }
pub fn fake_path(store: &Store) -> NixideResult<Self> {
Self::parse(store, "/nix/store/00000000000000000000000000000000-fake")
}
/// Get the name component of the store path. /// Get the name component of the store path.
/// ///
/// This returns the name part of the store path (everything after the hash). /// This returns the name part of the store path (everything after the hash).
@ -55,11 +59,12 @@ impl StorePath {
/// ///
/// Returns an error if the name cannot be retrieved. /// Returns an error if the name cannot be retrieved.
/// ///
pub fn name(&self) -> Result<String, NixideError> { pub fn name(&self) -> NixideResult<String> {
wrap::nix_string_callback!(|callback, userdata: *mut __UserData, _| unsafe { wrap::nix_string_callback!(|callback, userdata: *mut __UserData, _| unsafe {
sys::nix_store_path_name(self.inner.as_ptr(), Some(callback), userdata as *mut c_void); sys::nix_store_path_name(self.inner.as_ptr(), Some(callback), userdata as *mut c_void);
// NOTE: nix_store_path_name doesn't return nix_err, so we force it to return successfully // NOTE: nix_store_path_name doesn't return nix_err, so we force it to return successfully
nix_err_NIX_OK // XXX: NOTE: now `nix_string_callback` is a macro this isn't necessary
// sys::nix_err_NIX_OK
}) })
} }
@ -84,7 +89,7 @@ impl StorePath {
/// ///
/// * `store` - The store containing the path /// * `store` - The store containing the path
/// ///
pub fn real_path(&self, store: &Store) -> Result<PathBuf, NixideError> { pub fn real_path(&self, store: &Store) -> NixideResult<PathBuf> {
wrap::nix_pathbuf_callback!( wrap::nix_pathbuf_callback!(
|callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe { |callback, userdata: *mut __UserData, ctx: &ErrorContext| unsafe {
sys::nix_store_real_path( sys::nix_store_real_path(

View file

@ -1,53 +1,82 @@
use serial_test::serial; use serial_test::serial;
use super::*; use super::{Store, StorePath};
use crate::errors::ErrorContext;
use crate::sys;
use crate::util::wrappers::AsInnerPtr as _;
#[test] #[test]
#[serial] #[serial]
fn test_store_opening() { fn test_store_opening() {
let mut ctx = ErrorContext::new();
unsafe {
sys::nix_libutil_init(ctx.as_ptr());
ctx.pop()
.expect("nix_libutil_init failed with bad ErrorContext");
sys::nix_libstore_init(ctx.as_ptr());
ctx.pop()
.expect("nix_libstore_init failed with bad ErrorContext");
sys::nix_libexpr_init(ctx.as_ptr());
ctx.pop()
.expect("nix_libexpr_init failed with bad ErrorContext");
};
let _store = Store::open(None).expect("Failed to open store"); let _store = Store::open(None).expect("Failed to open store");
} }
#[test] #[test]
#[serial] #[serial]
fn test_store_path_parse() { fn test_store_path_parse() {
let mut ctx = ErrorContext::new();
unsafe {
sys::nix_libutil_init(ctx.as_ptr());
ctx.pop()
.expect("nix_libutil_init failed with bad ErrorContext");
sys::nix_libstore_init(ctx.as_ptr());
ctx.pop()
.expect("nix_libstore_init failed with bad ErrorContext");
sys::nix_libexpr_init(ctx.as_ptr());
ctx.pop()
.expect("nix_libexpr_init failed with bad ErrorContext");
};
let store = Store::open(None).expect("Failed to open store"); let store = Store::open(None).expect("Failed to open store");
// Try parsing a well-formed store path // Try parsing a well-formed store path
// Note: This may fail if the path doesn't exist in the store let result = StorePath::fake_path(&store);
let result = StorePath::parse(&store, "/nix/store/00000000000000000000000000000000-test"); result.expect("idk hopefully this fails");
// We don't assert success here because the path might not exist
// This test mainly checks that the API works correctly
match result {
Ok(_path) => {
// Successfully parsed the path
}
Err(_) => {
// Path doesn't exist or is invalid, which is expected
}
}
} }
#[test] #[test]
#[serial] #[serial]
fn test_store_path_clone() { fn test_store_path_clone() {
let mut ctx = ErrorContext::new();
unsafe {
sys::nix_libutil_init(ctx.as_ptr());
ctx.pop()
.expect("nix_libutil_init failed with bad ErrorContext");
sys::nix_libstore_init(ctx.as_ptr());
ctx.pop()
.expect("nix_libstore_init failed with bad ErrorContext");
sys::nix_libexpr_init(ctx.as_ptr());
ctx.pop()
.expect("nix_libexpr_init failed with bad ErrorContext");
};
let store = Store::open(None).expect("Failed to open store"); let store = Store::open(None).expect("Failed to open store");
// Try to get a valid store path by parsing // Try to get a valid store path by parsing
// Note: This test is somewhat limited without a guaranteed valid path let path = StorePath::fake_path(&store).expect("Failed to create `StorePath::fake_path`");
if let Ok(path) = StorePath::parse(&store, "/nix/store/00000000000000000000000000000000-test") { let cloned = path.clone();
let cloned = path.clone();
// Assert that the cloned path has the same name as the original // Assert that the cloned path has the same name as the original
let original_name = path.name().expect("Failed to get original path name"); let original_name = path.name().expect("Failed to get original path name");
let cloned_name = cloned.name().expect("Failed to get cloned path name"); let cloned_name = cloned.name().expect("Failed to get cloned path name");
assert_eq!( assert_eq!(
original_name, cloned_name, original_name, cloned_name,
"Cloned path should have the same name as original" "Cloned path should have the same name as original"
); );
}
} }
// Note: test_realize is not included because it requires a valid store path // Note: test_realize is not included because it requires a valid store path

View file

@ -3,6 +3,12 @@
pub(crate) struct UserData<S, T> { pub(crate) struct UserData<S, T> {
pub inner: S, pub inner: S,
pub retval: T, pub retval: T,
#[cfg(debug_assertions)]
pub init_inner: bool,
#[cfg(debug_assertions)]
pub init_retval: bool,
} }
impl<S, T> AsMut<UserData<S, T>> for UserData<S, T> { impl<S, T> AsMut<UserData<S, T>> for UserData<S, T> {
@ -11,30 +17,14 @@ impl<S, T> AsMut<UserData<S, T>> for UserData<S, T> {
} }
} }
// pub(crate) trait VoidPtrIsomorphism {
// fn as_void_ptr(self) -> *mut c_void;
// fn from_void_ptr(ptr: *mut c_void) -> Self;
// }
// impl<S, T> VoidPtrIsomorphism for *mut UserData<S, T> {
// fn as_void_ptr(self) -> *mut c_void {
// self as *mut c_void
// }
// fn from_void_ptr(ptr: *mut c_void) -> Self {
// ptr as Self
// }
// }
impl<S, T> UserData<S, T> { impl<S, T> UserData<S, T> {
/// # Warning /// # Warning
/// ///
/// Ensure `self.retval` has been initialised before unwrapping! /// Ensure `self.retval` has been initialised before unwrapping!
/// ///
pub unsafe fn unwrap(self) -> (S, T) { // pub unsafe fn unwrap(self) -> (S, T) {
(self.inner, self.retval) // (self.inner, self.retval)
} // }
pub unsafe fn as_mut_ptr(&mut self) -> *mut Self { pub unsafe fn as_mut_ptr(&mut self) -> *mut Self {
self as *mut Self self as *mut Self
@ -62,7 +52,6 @@ macro_rules! nonnull {
} }
}}; }};
} }
use std::ffi::c_void;
pub(crate) use nonnull; pub(crate) use nonnull;
@ -146,7 +135,9 @@ macro_rules! nix_callback {
$function(__wrapper_callback, __state.as_mut_ptr(), &__ctx); $function(__wrapper_callback, __state.as_mut_ptr(), &__ctx);
__ctx.pop().and_then(|_| unsafe { __state.assume_init().retval }) // type annotations for compiler
let __result: $ret = __ctx.pop().and_then(|_| unsafe { __state.assume_init().retval });
__result
}}; }};
} }
pub(crate) use nix_callback; pub(crate) use nix_callback;