feat: EvalState.realise_string
(cherry picked from commit f2b1142018fd64dd45ec97f1eccf0c48cc4a8c6d)
This commit is contained in:
parent
6736f05a3f
commit
87203ef394
3 changed files with 140 additions and 1 deletions
|
|
@ -3,6 +3,7 @@ use anyhow::Context as _;
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use nix_c_raw as raw;
|
use nix_c_raw as raw;
|
||||||
|
use nix_store::path::StorePath;
|
||||||
use nix_store::store::Store;
|
use nix_store::store::Store;
|
||||||
use nix_util::context::Context;
|
use nix_util::context::Context;
|
||||||
use nix_util::string_return::callback_get_vec_u8;
|
use nix_util::string_return::callback_get_vec_u8;
|
||||||
|
|
@ -34,6 +35,11 @@ pub fn init() -> Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RealisedString {
|
||||||
|
pub s: String,
|
||||||
|
pub paths: Vec<StorePath>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct EvalState {
|
pub struct EvalState {
|
||||||
eval_state: NonNull<raw::EvalState>,
|
eval_state: NonNull<raw::EvalState>,
|
||||||
store: Store,
|
store: Store,
|
||||||
|
|
@ -131,6 +137,46 @@ impl EvalState {
|
||||||
}
|
}
|
||||||
self.get_string(value)
|
self.get_string(value)
|
||||||
}
|
}
|
||||||
|
pub fn realise_string(
|
||||||
|
&self,
|
||||||
|
value: &Value,
|
||||||
|
is_import_from_derivation: bool,
|
||||||
|
) -> Result<RealisedString> {
|
||||||
|
let t = self.value_type(value)?;
|
||||||
|
if t != ValueType::String {
|
||||||
|
bail!("expected a string, but got a {:?}", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
let rs = unsafe {
|
||||||
|
raw::string_realise(
|
||||||
|
self.context.ptr(),
|
||||||
|
self.raw_ptr(),
|
||||||
|
value.raw_ptr(),
|
||||||
|
is_import_from_derivation,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
self.context.check_err()?;
|
||||||
|
|
||||||
|
let s = unsafe {
|
||||||
|
let start = raw::realised_string_get_buffer_start(rs) as *const u8;
|
||||||
|
let size = raw::realised_string_get_buffer_size(rs);
|
||||||
|
let slice = std::slice::from_raw_parts(start, size);
|
||||||
|
String::from_utf8(slice.to_vec())
|
||||||
|
.map_err(|e| anyhow::format_err!("Nix string is not valid UTF-8: {}", e))?
|
||||||
|
};
|
||||||
|
|
||||||
|
let paths = unsafe {
|
||||||
|
let n = raw::realised_string_get_store_path_count(rs);
|
||||||
|
let mut paths = Vec::with_capacity(n as usize);
|
||||||
|
for i in 0..n {
|
||||||
|
let path = raw::realised_string_get_store_path(rs, i);
|
||||||
|
paths.push(StorePath::new_raw_clone(path));
|
||||||
|
}
|
||||||
|
paths
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(RealisedString { s, paths })
|
||||||
|
}
|
||||||
|
|
||||||
fn new_value_uninitialized(&self) -> Value {
|
fn new_value_uninitialized(&self) -> Value {
|
||||||
let value = unsafe { raw::alloc_value(self.context.ptr(), self.raw_ptr()) };
|
let value = unsafe { raw::alloc_value(self.context.ptr(), self.raw_ptr()) };
|
||||||
|
|
@ -191,12 +237,24 @@ impl Drop for EvalState {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use ctor::ctor;
|
use ctor::ctor;
|
||||||
|
use nix_util::settings;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[ctor]
|
#[ctor]
|
||||||
fn setup() {
|
fn setup() {
|
||||||
init().unwrap();
|
(|| -> Result<()> {
|
||||||
|
init()?;
|
||||||
|
// If it reinvokes the test suite,
|
||||||
|
// settings::set("build-hook", "")?;
|
||||||
|
|
||||||
|
// When testing in the sandbox, the default build dir would be a parent of the storeDir,
|
||||||
|
// which causes an error. So we set a custom build dir here.
|
||||||
|
settings::set("sandbox-build-dir", "/custom-build-dir-for-test")?;
|
||||||
|
Ok(())
|
||||||
|
})()
|
||||||
|
.unwrap();
|
||||||
|
std::env::set_var("_NIX_TEST_NO_SANDBOX", "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -356,4 +414,51 @@ mod tests {
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn eval_state_realise_string() {
|
||||||
|
gc_registering_current_thread(|| {
|
||||||
|
let store = Store::open("auto").unwrap();
|
||||||
|
let es = EvalState::new(store).unwrap();
|
||||||
|
let expr = r#"
|
||||||
|
''
|
||||||
|
a derivation output: ${
|
||||||
|
derivation { name = "letsbuild";
|
||||||
|
system = builtins.currentSystem;
|
||||||
|
builder = "/bin/sh";
|
||||||
|
args = [ "-c" "echo foo > $out" ];
|
||||||
|
}}
|
||||||
|
a path: ${builtins.toFile "just-a-file" "ooh file good"}
|
||||||
|
a derivation path by itself: ${
|
||||||
|
builtins.unsafeDiscardOutputDependency
|
||||||
|
(derivation {
|
||||||
|
name = "not-actually-built-yet";
|
||||||
|
system = builtins.currentSystem;
|
||||||
|
builder = "/bin/sh";
|
||||||
|
args = [ "-c" "echo foo > $out" ];
|
||||||
|
}).drvPath}
|
||||||
|
''
|
||||||
|
"#;
|
||||||
|
let v = es.eval_from_string(expr, "<test>").unwrap();
|
||||||
|
es.force(&v).unwrap();
|
||||||
|
let rs = es.realise_string(&v, false).unwrap();
|
||||||
|
|
||||||
|
assert!(rs.s.starts_with("a derivation output:"));
|
||||||
|
assert!(rs.s.contains("-letsbuild\n"));
|
||||||
|
assert!(!rs.s.contains("-letsbuild.drv"));
|
||||||
|
assert!(rs.s.contains("a path:"));
|
||||||
|
assert!(rs.s.contains("-just-a-file"));
|
||||||
|
assert!(!rs.s.contains("-just-a-file.drv"));
|
||||||
|
assert!(!rs.s.contains("ooh file good"));
|
||||||
|
assert!(rs.s.ends_with("-not-actually-built-yet.drv\n"));
|
||||||
|
|
||||||
|
assert_eq!(rs.paths.len(), 3);
|
||||||
|
let mut names: Vec<String> = rs.paths.iter().map(|p| p.name().unwrap()).collect();
|
||||||
|
names.sort();
|
||||||
|
assert_eq!(names[0], "just-a-file");
|
||||||
|
assert_eq!(names[1], "letsbuild");
|
||||||
|
assert_eq!(names[2], "not-actually-built-yet.drv");
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
|
pub mod path;
|
||||||
pub mod store;
|
pub mod store;
|
||||||
|
|
|
||||||
33
rust/nix-store/src/path.rs
Normal file
33
rust/nix-store/src/path.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use nix_c_raw as raw;
|
||||||
|
use nix_util::string_return::{callback_get_vec_u8, callback_get_vec_u8_data};
|
||||||
|
|
||||||
|
pub struct StorePath {
|
||||||
|
raw: *mut raw::StorePath,
|
||||||
|
}
|
||||||
|
impl StorePath {
|
||||||
|
pub fn new_raw_clone(raw: *const raw::StorePath) -> Self {
|
||||||
|
Self::new_raw(unsafe { raw::store_path_clone(raw as *mut raw::StorePath) })
|
||||||
|
}
|
||||||
|
pub fn new_raw(raw: *mut raw::StorePath) -> Self {
|
||||||
|
StorePath { raw }
|
||||||
|
}
|
||||||
|
pub fn name(&self) -> Result<String> {
|
||||||
|
unsafe {
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
raw::store_path_name(
|
||||||
|
self.raw,
|
||||||
|
Some(callback_get_vec_u8),
|
||||||
|
callback_get_vec_u8_data(&mut vec),
|
||||||
|
);
|
||||||
|
String::from_utf8(vec).map_err(|e| e.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Drop for StorePath {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
raw::store_path_free(self.raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue