refact: Make require_attrs_select* error handling regular
(cherry picked from commit de6c6cbd462202405bc787fed02dee249cf16973)
This commit is contained in:
parent
61efb9b79f
commit
c16a9b0595
2 changed files with 56 additions and 32 deletions
|
|
@ -184,20 +184,27 @@ impl EvalState {
|
||||||
Ok(attrs)
|
Ok(attrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make this the main implementation and move the error handling to require_attrs_select_opt
|
/// Evaluate, require that the value is an attrset, and select an attribute by name.
|
||||||
// that gets rid of the odd self.context.check_err() usage that relies on the context not being reset
|
|
||||||
pub fn require_attrs_select(&self, v: &Value, attr_name: &str) -> Result<Value> {
|
pub fn require_attrs_select(&self, v: &Value, attr_name: &str) -> Result<Value> {
|
||||||
let r = self.require_attrs_select_opt(v, attr_name)?;
|
let t = self.value_type(v)?;
|
||||||
match r {
|
if t != ValueType::AttrSet {
|
||||||
Some(v) => Ok(v),
|
bail!("expected an attrset, but got a {:?}", t);
|
||||||
None => self.context.check_err().and_then(|_| {
|
|
||||||
// should be unreachable
|
|
||||||
bail!("attribute not found: {}", attr_name)
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
|
let attr_name = CString::new(attr_name)
|
||||||
|
.with_context(|| "require_attrs_select: attrName contains null byte")?;
|
||||||
|
let v2 = self.context.check_one_call(|ctx_ptr| unsafe {
|
||||||
|
raw::get_attr_byname(ctx_ptr, v.raw_ptr(), self.raw_ptr(), attr_name.as_ptr())
|
||||||
|
})?;
|
||||||
|
Ok(Value::new(v2))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate, require that the value is an attrset, and select an attribute by name.
|
/// Evaluate, require that the value is an attrset, and select an attribute by name.
|
||||||
|
///
|
||||||
|
/// Return `Err(...)` if `v` is not an attrset, or if some other error occurred.
|
||||||
|
///
|
||||||
|
/// Return `Ok(None)` if the attribute is not present.
|
||||||
|
///
|
||||||
|
/// Return `Ok(Some(value))` if the attribute is present.
|
||||||
pub fn require_attrs_select_opt(&self, v: &Value, attr_name: &str) -> Result<Option<Value>> {
|
pub fn require_attrs_select_opt(&self, v: &Value, attr_name: &str) -> Result<Option<Value>> {
|
||||||
let t = self.value_type(v)?;
|
let t = self.value_type(v)?;
|
||||||
if t != ValueType::AttrSet {
|
if t != ValueType::AttrSet {
|
||||||
|
|
@ -205,21 +212,10 @@ impl EvalState {
|
||||||
}
|
}
|
||||||
let attr_name = CString::new(attr_name)
|
let attr_name = CString::new(attr_name)
|
||||||
.with_context(|| "require_attrs_select_opt: attrName contains null byte")?;
|
.with_context(|| "require_attrs_select_opt: attrName contains null byte")?;
|
||||||
// c_void should be Value; why was void generated?
|
let v2 = self.context.check_one_call_or_key_none(|ctx_ptr| unsafe {
|
||||||
let v = unsafe {
|
raw::get_attr_byname(ctx_ptr, v.raw_ptr(), self.raw_ptr(), attr_name.as_ptr())
|
||||||
raw::get_attr_byname(
|
})?;
|
||||||
self.context.ptr(),
|
Ok(v2.map(Value::new))
|
||||||
v.raw_ptr(),
|
|
||||||
self.raw_ptr(),
|
|
||||||
attr_name.as_ptr(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
if self.context.is_key_error() {
|
|
||||||
Ok(None)
|
|
||||||
} else {
|
|
||||||
self.context.check_err()?;
|
|
||||||
Ok(Some(Value::new(v)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new value containing the passed string.
|
/// Create a new value containing the passed string.
|
||||||
|
|
@ -575,6 +571,18 @@ mod tests {
|
||||||
let b = es.require_attrs_select(&v, "b").unwrap();
|
let b = es.require_attrs_select(&v, "b").unwrap();
|
||||||
assert_eq!(es.require_string(&a).unwrap(), "aye");
|
assert_eq!(es.require_string(&a).unwrap(), "aye");
|
||||||
assert_eq!(es.require_string(&b).unwrap(), "bee");
|
assert_eq!(es.require_string(&b).unwrap(), "bee");
|
||||||
|
let missing = es.require_attrs_select(&v, "c");
|
||||||
|
match missing {
|
||||||
|
Ok(_) => panic!("expected an error"),
|
||||||
|
Err(e) => {
|
||||||
|
let s = format!("{e:#}");
|
||||||
|
// TODO: bad error message from Nix
|
||||||
|
if !s.contains("missing attribute") {
|
||||||
|
eprintln!("unexpected error message: {}", s);
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,17 +35,20 @@ impl Context {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear(&self) {
|
||||||
|
unsafe {
|
||||||
|
raw::set_err_msg(
|
||||||
|
self.inner.as_ptr(),
|
||||||
|
raw::NIX_OK.try_into().unwrap(),
|
||||||
|
b"\0".as_ptr() as *const i8,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn check_err_and_clear(&self) -> Result<()> {
|
pub fn check_err_and_clear(&self) -> Result<()> {
|
||||||
let r = self.check_err();
|
let r = self.check_err();
|
||||||
if r.is_err() {
|
if r.is_err() {
|
||||||
unsafe {
|
self.clear();
|
||||||
// TODO (https://github.com/NixOS/nix/pull/10910): raw::err_clear
|
|
||||||
raw::set_err_msg(
|
|
||||||
self.inner.as_ptr(),
|
|
||||||
raw::NIX_OK.try_into().unwrap(),
|
|
||||||
b"\0".as_ptr() as *const i8,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
@ -59,6 +62,19 @@ impl Context {
|
||||||
Ok(t)
|
Ok(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn check_one_call_or_key_none<T, F: FnOnce(*mut raw::c_context) -> T>(
|
||||||
|
&self,
|
||||||
|
f: F,
|
||||||
|
) -> Result<Option<T>> {
|
||||||
|
let t = f(self.ptr());
|
||||||
|
if self.is_key_error() {
|
||||||
|
self.clear();
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
self.check_err_and_clear()?;
|
||||||
|
Ok(Some(t))
|
||||||
|
}
|
||||||
|
|
||||||
/// NIX_ERR_KEY is returned when e.g. an attribute is missing. Return true if the error is of this type.
|
/// NIX_ERR_KEY is returned when e.g. an attribute is missing. Return true if the error is of this type.
|
||||||
pub fn is_key_error(&self) -> bool {
|
pub fn is_key_error(&self) -> bool {
|
||||||
unsafe { raw::err_code(self.inner.as_ptr()) == raw::NIX_ERR_KEY }
|
unsafe { raw::err_code(self.inner.as_ptr()) == raw::NIX_ERR_KEY }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue