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 lazy_static::lazy_static;
|
||||
use nix_c_raw as raw;
|
||||
use nix_store::path::StorePath;
|
||||
use nix_store::store::Store;
|
||||
use nix_util::context::Context;
|
||||
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 {
|
||||
eval_state: NonNull<raw::EvalState>,
|
||||
store: Store,
|
||||
|
|
@ -131,6 +137,46 @@ impl EvalState {
|
|||
}
|
||||
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 {
|
||||
let value = unsafe { raw::alloc_value(self.context.ptr(), self.raw_ptr()) };
|
||||
|
|
@ -191,12 +237,24 @@ impl Drop for EvalState {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ctor::ctor;
|
||||
use nix_util::settings;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[ctor]
|
||||
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]
|
||||
|
|
@ -356,4 +414,51 @@ mod tests {
|
|||
})
|
||||
.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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue