feat: nix-flake: Basic locking
(cherry picked from commit cfd374f9deda7d40229198911516b22bc3d82626)
This commit is contained in:
parent
e6b993a42b
commit
b77a3a2085
1 changed files with 216 additions and 2 deletions
|
|
@ -1,6 +1,14 @@
|
|||
use anyhow::Result;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
use anyhow::{Context as _, Result};
|
||||
use nix_c_raw as raw;
|
||||
use nix_util::context::{self, Context};
|
||||
use nix_expr::eval_state::EvalState;
|
||||
use nix_fetchers::FetchersSettings;
|
||||
use nix_util::{
|
||||
context::{self, Context},
|
||||
result_string_init,
|
||||
string_return::{callback_get_result_string, callback_get_result_string_data},
|
||||
};
|
||||
|
||||
pub struct FlakeSettings {
|
||||
pub(crate) ptr: *mut raw::flake_settings,
|
||||
|
|
@ -47,6 +55,149 @@ impl EvalStateBuilderExt for nix_expr::eval_state::EvalStateBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct FlakeReferenceParseFlags {
|
||||
pub(crate) ptr: NonNull<raw::flake_reference_parse_flags>,
|
||||
}
|
||||
impl Drop for FlakeReferenceParseFlags {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
raw::flake_reference_parse_flags_free(self.ptr.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
impl FlakeReferenceParseFlags {
|
||||
pub fn new(settings: &FlakeSettings) -> Result<Self> {
|
||||
let mut ctx = Context::new();
|
||||
let ptr = unsafe {
|
||||
context::check_call!(raw::flake_reference_parse_flags_new(&mut ctx, settings.ptr))
|
||||
}?;
|
||||
let ptr = NonNull::new(ptr)
|
||||
.context("flake_reference_parse_flags_new unexpectedly returned null")?;
|
||||
Ok(FlakeReferenceParseFlags { ptr })
|
||||
}
|
||||
pub fn set_base_directory(&mut self, base_directory: &str) -> Result<()> {
|
||||
let mut ctx = Context::new();
|
||||
unsafe {
|
||||
context::check_call!(raw::flake_reference_parse_flags_set_base_directory(
|
||||
&mut ctx,
|
||||
self.ptr.as_ptr(),
|
||||
base_directory.as_ptr() as *const i8,
|
||||
base_directory.len()
|
||||
))
|
||||
}?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FlakeReference {
|
||||
pub(crate) ptr: NonNull<raw::flake_reference>,
|
||||
}
|
||||
impl Drop for FlakeReference {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
raw::flake_reference_free(self.ptr.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
impl FlakeReference {
|
||||
pub fn parse_with_fragment(
|
||||
fetch_settings: &FetchersSettings,
|
||||
flake_settings: &FlakeSettings,
|
||||
flags: &FlakeReferenceParseFlags,
|
||||
reference: &str,
|
||||
) -> Result<(FlakeReference, String)> {
|
||||
let mut ctx = Context::new();
|
||||
let mut r = result_string_init!();
|
||||
let mut ptr: *mut raw::flake_reference = std::ptr::null_mut();
|
||||
unsafe {
|
||||
context::check_call!(raw::flake_reference_and_fragment_from_string(
|
||||
&mut ctx,
|
||||
fetch_settings.raw_ptr(),
|
||||
flake_settings.ptr,
|
||||
flags.ptr.as_ptr(),
|
||||
reference.as_ptr() as *const i8,
|
||||
reference.len(),
|
||||
// pointer to ptr
|
||||
&mut ptr,
|
||||
Some(callback_get_result_string),
|
||||
callback_get_result_string_data(&mut r)
|
||||
))
|
||||
}?;
|
||||
let ptr = NonNull::new(ptr)
|
||||
.context("flake_reference_and_fragment_from_string unexpectedly returned null")?;
|
||||
Ok((FlakeReference { ptr: ptr }, r?))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FlakeLockFlags {
|
||||
pub(crate) ptr: *mut raw::flake_lock_flags,
|
||||
}
|
||||
impl Drop for FlakeLockFlags {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
raw::flake_lock_flags_free(self.ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
impl FlakeLockFlags {
|
||||
pub fn new(settings: &FlakeSettings) -> Result<Self> {
|
||||
let mut ctx = Context::new();
|
||||
let s = unsafe { context::check_call!(raw::flake_lock_flags_new(&mut ctx, settings.ptr)) }?;
|
||||
Ok(FlakeLockFlags { ptr: s })
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LockedFlake {
|
||||
pub(crate) ptr: NonNull<raw::locked_flake>,
|
||||
}
|
||||
impl Drop for LockedFlake {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
raw::locked_flake_free(self.ptr.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
impl LockedFlake {
|
||||
pub fn lock(
|
||||
fetch_settings: &FetchersSettings,
|
||||
flake_settings: &FlakeSettings,
|
||||
eval_state: &EvalState,
|
||||
flags: &FlakeLockFlags,
|
||||
flake_ref: &FlakeReference,
|
||||
) -> Result<LockedFlake> {
|
||||
let mut ctx = Context::new();
|
||||
let ptr = unsafe {
|
||||
context::check_call!(raw::flake_lock(
|
||||
&mut ctx,
|
||||
fetch_settings.raw_ptr(),
|
||||
flake_settings.ptr,
|
||||
eval_state.raw_ptr(),
|
||||
flags.ptr,
|
||||
flake_ref.ptr.as_ptr()
|
||||
))
|
||||
}?;
|
||||
let ptr = NonNull::new(ptr).context("flake_lock unexpectedly returned null")?;
|
||||
Ok(LockedFlake { ptr })
|
||||
}
|
||||
|
||||
pub fn outputs(
|
||||
&self,
|
||||
flake_settings: &FlakeSettings,
|
||||
eval_state: &mut EvalState,
|
||||
) -> Result<nix_expr::value::Value> {
|
||||
let mut ctx = Context::new();
|
||||
unsafe {
|
||||
let r = context::check_call!(raw::locked_flake_get_output_attrs(
|
||||
&mut ctx,
|
||||
flake_settings.ptr,
|
||||
eval_state.raw_ptr(),
|
||||
self.ptr.as_ptr()
|
||||
))?;
|
||||
Ok(nix_expr::value::__private::raw_value_new(r))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use nix_expr::eval_state::{gc_register_my_thread, EvalStateBuilder};
|
||||
|
|
@ -80,4 +231,67 @@ mod tests {
|
|||
|
||||
drop(gc_registration);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flake_lock_load_flake() {
|
||||
init();
|
||||
let gc_registration = gc_register_my_thread();
|
||||
let store = Store::open(None, []).unwrap();
|
||||
let flake_settings = FlakeSettings::new().unwrap();
|
||||
let mut eval_state = EvalStateBuilder::new(store)
|
||||
.unwrap()
|
||||
.flakes(&flake_settings)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let tmp_dir = tempfile::tempdir().unwrap();
|
||||
|
||||
// Create flake.nix
|
||||
let flake_nix = tmp_dir.path().join("flake.nix");
|
||||
std::fs::write(
|
||||
&flake_nix,
|
||||
r#"
|
||||
{
|
||||
outputs = { ... }: {
|
||||
hello = "potato";
|
||||
};
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let flake_lock_flags = FlakeLockFlags::new(&flake_settings).unwrap();
|
||||
|
||||
let (flake_ref, fragment) = FlakeReference::parse_with_fragment(
|
||||
&FetchersSettings::new().unwrap(),
|
||||
&flake_settings,
|
||||
&FlakeReferenceParseFlags::new(&flake_settings).unwrap(),
|
||||
&format!("path:{}#subthing", tmp_dir.path().display()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(fragment, "subthing");
|
||||
|
||||
let locked_flake = LockedFlake::lock(
|
||||
&FetchersSettings::new().unwrap(),
|
||||
&flake_settings,
|
||||
&eval_state,
|
||||
&flake_lock_flags,
|
||||
&flake_ref,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let outputs = locked_flake
|
||||
.outputs(&flake_settings, &mut eval_state)
|
||||
.unwrap();
|
||||
|
||||
let hello = eval_state.require_attrs_select(&outputs, &"hello").unwrap();
|
||||
let hello = eval_state.require_string(&hello).unwrap();
|
||||
|
||||
assert_eq!(hello, "potato");
|
||||
|
||||
drop(tmp_dir);
|
||||
drop(gc_registration);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue