feat(tvix/eval): teach builtins.toXML context
XmlEmitter gains a NixContext field, and `write_typed_value` extends it with all context elements present in the passed value. Once all serialization is done, a into_context() function returns the collected context, so we can construct a NixString with context. Tests for this live in tvix-glue, as we use builtins.derivation, which is not present in the tvix-eval crate. Fixes b/398. Change-Id: I85feaaa17b753885f8a017a54e419ec4e602af21 Reviewed-on: https://cl.tvl.fyi/c/depot/+/11704 Tested-by: BuildkiteCI Reviewed-by: flokli <flokli@flokli.de> Autosubmit: flokli <flokli@flokli.de> Reviewed-by: Alyssa Ross <hi@alyssa.is>
This commit is contained in:
parent
a4a313cdd2
commit
ec8d79f3db
4 changed files with 53 additions and 6 deletions
|
@ -1504,8 +1504,19 @@ mod pure_builtins {
|
|||
}
|
||||
|
||||
let mut buf: Vec<u8> = vec![];
|
||||
to_xml::value_to_xml(&mut buf, &value)?;
|
||||
Ok(buf.into())
|
||||
let context = to_xml::value_to_xml(&mut buf, &value)?;
|
||||
|
||||
Ok((
|
||||
buf,
|
||||
// FUTUREWORK: We have a distinction between an empty context, and
|
||||
// no context at all. Fix this.
|
||||
if !context.is_empty() {
|
||||
Some(Box::new(context))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)
|
||||
.into())
|
||||
}
|
||||
|
||||
#[builtin("placeholder")]
|
||||
|
|
|
@ -6,11 +6,12 @@ use bstr::ByteSlice;
|
|||
use std::borrow::Cow;
|
||||
use std::{io::Write, rc::Rc};
|
||||
|
||||
use crate::{ErrorKind, Value};
|
||||
use crate::{ErrorKind, NixContext, NixContextElement, Value};
|
||||
|
||||
/// Recursively serialise a value to XML. The value *must* have been
|
||||
/// deep-forced before being passed to this function.
|
||||
pub fn value_to_xml<W: Write>(mut writer: W, value: &Value) -> Result<(), ErrorKind> {
|
||||
/// On success, returns the NixContext.
|
||||
pub fn value_to_xml<W: Write>(mut writer: W, value: &Value) -> Result<NixContext, ErrorKind> {
|
||||
// Write a literal document declaration, using C++-Nix-style
|
||||
// single quotes.
|
||||
writeln!(writer, "<?xml version='1.0' encoding='utf-8'?>")?;
|
||||
|
@ -21,7 +22,7 @@ pub fn value_to_xml<W: Write>(mut writer: W, value: &Value) -> Result<(), ErrorK
|
|||
value_variant_to_xml(&mut emitter, value)?;
|
||||
emitter.write_closing_tag("expr")?;
|
||||
|
||||
Ok(())
|
||||
Ok(emitter.into_context())
|
||||
}
|
||||
|
||||
fn write_typed_value<W: Write, V: ToString>(
|
||||
|
@ -45,7 +46,12 @@ fn value_variant_to_xml<W: Write>(w: &mut XmlEmitter<W>, value: &Value) -> Resul
|
|||
Value::Bool(b) => return write_typed_value(w, "bool", b),
|
||||
Value::Integer(i) => return write_typed_value(w, "int", i),
|
||||
Value::Float(f) => return write_typed_value(w, "float", f),
|
||||
Value::String(s) => return write_typed_value(w, "string", s.to_str()?),
|
||||
Value::String(s) => {
|
||||
if let Some(context) = s.context() {
|
||||
w.extend_context(context.iter().cloned());
|
||||
}
|
||||
return write_typed_value(w, "string", s.to_str()?);
|
||||
}
|
||||
Value::Path(p) => return write_typed_value(w, "path", p.to_string_lossy()),
|
||||
|
||||
Value::List(list) => {
|
||||
|
@ -137,6 +143,7 @@ struct XmlEmitter<W> {
|
|||
/// The current indentation
|
||||
cur_indent: usize,
|
||||
writer: W,
|
||||
context: NixContext,
|
||||
}
|
||||
|
||||
impl<W: Write> XmlEmitter<W> {
|
||||
|
@ -144,6 +151,7 @@ impl<W: Write> XmlEmitter<W> {
|
|||
XmlEmitter {
|
||||
cur_indent: 0,
|
||||
writer,
|
||||
context: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,6 +253,19 @@ impl<W: Write> XmlEmitter<W> {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Extends the existing context with more context elements.
|
||||
fn extend_context<T>(&mut self, iter: T)
|
||||
where
|
||||
T: IntoIterator<Item = NixContextElement>,
|
||||
{
|
||||
self.context.extend(iter)
|
||||
}
|
||||
|
||||
/// Consumes [Self] and returns the [NixContext] collected.
|
||||
fn into_context(self) -> NixContext {
|
||||
self.context
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
[ { "/nix/store/y1s2fiq89v2h9vkb38w508ir20dwv6v2-test.drv" = { allOutputs = true; }; } false ]
|
14
tvix/glue/src/tests/tvix_tests/eval-okay-toxml-context.nix
Normal file
14
tvix/glue/src/tests/tvix_tests/eval-okay-toxml-context.nix
Normal file
|
@ -0,0 +1,14 @@
|
|||
[
|
||||
# builtins.toXML retains context where there is.
|
||||
(builtins.getContext (builtins.toXML {
|
||||
inherit (derivation {
|
||||
name = "test";
|
||||
builder = "/bin/sh";
|
||||
system = builtins.currentSystem;
|
||||
}) drvPath;
|
||||
}))
|
||||
|
||||
# this should have no context.
|
||||
(builtins.hasContext
|
||||
(builtins.toXML { }))
|
||||
]
|
Loading…
Reference in a new issue