use std::rc::Rc;
use super::*;
use super::bridge_helpers::{as_string, load_format};
use sui_spec::lock_file::{self, LockFileFormat};
const NAME: &str = "builtins.sui.lockFile";
const FORMAT: &str = "cppnix-flake-lock-v7";
pub(crate) fn register(sui_ext: &mut NixAttrs) {
let mut set = NixAttrs::new();
register_builtin(&mut set, "parse", |args| {
let bridge = format!("{NAME}.parse");
let text = as_string(&args[0], &bridge)?;
let fmt: LockFileFormat = load_format(FORMAT, &bridge)?;
let parsed = lock_file::parse(&text, &fmt)
.map_err(|e| EvalError::type_error(format!("{bridge}: {e:?}")))?;
let mut out = NixAttrs::new();
out.insert("version".to_string(), Value::Int(parsed.version as i64));
out.insert("root".to_string(), Value::string(parsed.root));
let mut nodes = NixAttrs::new();
for (k, v) in parsed.nodes {
nodes.insert(k, json_to_value(&v));
}
out.insert("nodes".to_string(), Value::Attrs(Rc::new(nodes)));
Ok(Value::Attrs(Rc::new(out)))
});
register_builtin(&mut set, "rootInputs", |args| {
let bridge = format!("{NAME}.rootInputs");
let text = as_string(&args[0], &bridge)?;
let fmt: LockFileFormat = load_format(FORMAT, &bridge)?;
let parsed = lock_file::parse(&text, &fmt)
.map_err(|e| EvalError::type_error(format!("{bridge}: {e:?}")))?;
let inputs = lock_file::root_inputs(&parsed)
.map_err(|e| EvalError::type_error(format!("{bridge}: {e:?}")))?;
Ok(Value::list(inputs.into_iter().map(Value::string).collect()))
});
sui_ext.insert("lockFile".to_string(), Value::Attrs(Rc::new(set)));
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &str = r#"{
"version": 7,
"root": "root",
"nodes": {
"root": { "inputs": { "nixpkgs": "nixpkgs" } },
"nixpkgs": { "locked": { "narHash": "sha256:abc" } }
}
}"#;
fn call_parse(text: &str) -> Result<Value, EvalError> {
let bridge = format!("{NAME}.parse");
let text = as_string(&Value::string(text), &bridge)?;
let fmt = lock_file::load_canonical().unwrap().into_iter()
.find(|f| f.name == "cppnix-flake-lock-v7").unwrap();
let parsed = lock_file::parse(&text, &fmt)
.map_err(|e| EvalError::type_error(format!("{bridge}: {e:?}")))?;
let mut out = NixAttrs::new();
out.insert("version".to_string(), Value::Int(parsed.version as i64));
out.insert("root".to_string(), Value::string(parsed.root));
let mut nodes = NixAttrs::new();
for (k, v) in parsed.nodes {
nodes.insert(k, json_to_value(&v));
}
out.insert("nodes".to_string(), Value::Attrs(Rc::new(nodes)));
Ok(Value::Attrs(Rc::new(out)))
}
#[test]
fn parse_returns_typed_record() {
let result = call_parse(SAMPLE).unwrap();
let attrs = match result {
Value::Attrs(a) => a,
_ => panic!("expected attrs"),
};
match attrs.get("version") {
Some(Value::Int(7)) => {}
other => panic!("expected version=7, got {other:?}"),
}
match attrs.get("root") {
Some(Value::String(s)) => assert_eq!(s.chars.as_str(), "root"),
_ => panic!("expected root string"),
}
}
#[test]
fn parse_garbage_errors() {
let err = call_parse("not json").unwrap_err();
let msg = format!("{err:?}");
assert!(msg.contains("lockFile.parse"));
}
}