mirror of
https://github.com/Noratrieb/terustform.git
synced 2026-01-14 16:35:11 +01:00
fix diagnostic
This commit is contained in:
parent
e0f753c0c2
commit
b86292fadb
5 changed files with 90 additions and 43 deletions
|
|
@ -49,9 +49,9 @@ fn data_source_model_inner(
|
||||||
quote! {
|
quote! {
|
||||||
let #tf::Some(#name) = obj.remove(#name_str) else {
|
let #tf::Some(#name) = obj.remove(#name_str) else {
|
||||||
return #tf::Err(
|
return #tf::Err(
|
||||||
#tf::Diagnostics::error_string(
|
#tf::Diagnostics::from(#tf::Diagnostic::error_string(
|
||||||
format!("Expected property '{}', which was not present", #name_str),
|
format!("Expected property '{}', which was not present", #name_str),
|
||||||
).with_path(path.clone())
|
).with_path(path.clone()))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
let #name = <#ty as #tf::ValueModel>::from_value(
|
let #name = <#ty as #tf::ValueModel>::from_value(
|
||||||
|
|
@ -78,16 +78,16 @@ fn data_source_model_inner(
|
||||||
fn from_value(v: #tf::Value, path: &#tf::AttrPath) -> #tf::DResult<Self> {
|
fn from_value(v: #tf::Value, path: &#tf::AttrPath) -> #tf::DResult<Self> {
|
||||||
match v {
|
match v {
|
||||||
#tf::BaseValue::Unknown => {
|
#tf::BaseValue::Unknown => {
|
||||||
return #tf::Err(#tf::Diagnostics::with_path(
|
return #tf::Err(#tf::Diagnostics::from(#tf::Diagnostic::with_path(
|
||||||
#tf::Diagnostics::error_string(#tf::ToOwned::to_owned("Expected object, found unknown value")),
|
#tf::Diagnostic::error_string(#tf::ToOwned::to_owned("Expected object, found unknown value")),
|
||||||
#tf::Clone::clone(&path),
|
#tf::Clone::clone(&path),
|
||||||
));
|
)));
|
||||||
},
|
},
|
||||||
#tf::BaseValue::Null => {
|
#tf::BaseValue::Null => {
|
||||||
return #tf::Err(#tf::Diagnostics::with_path(
|
return #tf::Err(#tf::Diagnostics::from(#tf::Diagnostic::with_path(
|
||||||
#tf::Diagnostics::error_string(#tf::ToOwned::to_owned("Expected object, found null value")),
|
#tf::Diagnostic::error_string(#tf::ToOwned::to_owned("Expected object, found null value")),
|
||||||
#tf::Clone::clone(&path),
|
#tf::Clone::clone(&path),
|
||||||
));
|
)));
|
||||||
},
|
},
|
||||||
#tf::BaseValue::Known(#tf::ValueKind::Object(mut obj)) => {
|
#tf::BaseValue::Known(#tf::ValueKind::Object(mut obj)) => {
|
||||||
#(#field_extractions)*
|
#(#field_extractions)*
|
||||||
|
|
@ -97,10 +97,10 @@ fn data_source_model_inner(
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
#tf::BaseValue::Known(v) => {
|
#tf::BaseValue::Known(v) => {
|
||||||
return #tf::Err(#tf::Diagnostics::with_path(
|
return #tf::Err(#tf::Diagnostics::from(#tf::Diagnostic::with_path(
|
||||||
#tf::Diagnostics::error_string(format!("Expected object, found {} value", v.diagnostic_type_str())),
|
#tf::Diagnostic::error_string(format!("Expected object, found {} value", v.diagnostic_type_str())),
|
||||||
#tf::Clone::clone(&path),
|
#tf::Clone::clone(&path),
|
||||||
));
|
)));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,41 +9,58 @@ use self::datasource::DataSource;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Diagnostics {
|
pub struct Diagnostics {
|
||||||
pub(crate) errors: Vec<String>,
|
pub(crate) diags: Vec<Diagnostic>,
|
||||||
pub(crate) attr: Option<AttrPath>,
|
|
||||||
// note: lol this cannot contain warnings that would be fucked oops
|
// note: lol this cannot contain warnings that would be fucked oops
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Diagnostic {
|
||||||
|
pub(crate) msg: String,
|
||||||
|
pub(crate) attr: Option<AttrPath>,
|
||||||
|
}
|
||||||
|
|
||||||
pub type DResult<T> = Result<T, Diagnostics>;
|
pub type DResult<T> = Result<T, Diagnostics>;
|
||||||
|
|
||||||
impl Diagnostics {
|
impl Diagnostic {
|
||||||
pub fn error_string(msg: impl Into<String>) -> Self {
|
pub fn error_string(msg: impl Into<String>) -> Self {
|
||||||
Self {
|
Diagnostic {
|
||||||
errors: vec![msg.into()],
|
msg: msg.into(),
|
||||||
attr: None,
|
attr: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_path(mut self, path: AttrPath) -> Self {
|
pub fn with_path(mut self, path: AttrPath) -> Self {
|
||||||
self.attr = Some(path);
|
self.attr = Some(path);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Diagnostics {
|
||||||
pub fn has_errors(&self) -> bool {
|
pub fn has_errors(&self) -> bool {
|
||||||
!self.errors.is_empty()
|
!self.diags.is_empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: std::error::Error + std::fmt::Debug> From<E> for Diagnostics {
|
impl<E: std::error::Error + std::fmt::Debug> From<E> for Diagnostic {
|
||||||
fn from(value: E) -> Self {
|
fn from(value: E) -> Self {
|
||||||
Self::error_string(format!("{:?}", value))
|
Self::error_string(format!("{:?}", value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<E: std::error::Error + std::fmt::Debug> From<E> for Diagnostics {
|
||||||
|
fn from(value: E) -> Self {
|
||||||
|
Diagnostic::from(value).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Diagnostic> for Diagnostics {
|
||||||
|
fn from(value: Diagnostic) -> Self {
|
||||||
|
Self { diags: vec![value] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: this could probably be a clever 0-alloc &-based linked list!
|
// TODO: this could probably be a clever 0-alloc &-based linked list!
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct AttrPath(Vec<AttrPathSegment>);
|
pub struct AttrPath(pub(crate) Vec<AttrPathSegment>);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum AttrPathSegment {
|
pub enum AttrPathSegment {
|
||||||
|
|
@ -91,13 +108,14 @@ impl<T> BaseValue<T> {
|
||||||
|
|
||||||
pub fn expect_known(&self, path: AttrPath) -> DResult<&T> {
|
pub fn expect_known(&self, path: AttrPath) -> DResult<&T> {
|
||||||
match self {
|
match self {
|
||||||
BaseValue::Null => {
|
BaseValue::Null => Err(Diagnostic::error_string("expected value, found null value")
|
||||||
Err(Diagnostics::error_string("expected value, found null value").with_path(path))
|
.with_path(path)
|
||||||
}
|
.into()),
|
||||||
BaseValue::Unknown => Err(Diagnostics::error_string(
|
BaseValue::Unknown => Err(Diagnostic::error_string(
|
||||||
"expected known value, found unknown value",
|
"expected known value, found unknown value",
|
||||||
)
|
)
|
||||||
.with_path(path)),
|
.with_path(path)
|
||||||
|
.into()),
|
||||||
BaseValue::Known(v) => Ok(v),
|
BaseValue::Known(v) => Ok(v),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -111,13 +129,16 @@ pub trait ValueModel: Sized {
|
||||||
|
|
||||||
impl ValueModel for StringValue {
|
impl ValueModel for StringValue {
|
||||||
fn from_value(v: Value, path: &AttrPath) -> DResult<Self> {
|
fn from_value(v: Value, path: &AttrPath) -> DResult<Self> {
|
||||||
v.try_map(|v| match v {
|
v.try_map(|v| -> DResult<String> {
|
||||||
ValueKind::String(s) => Ok(s),
|
match v {
|
||||||
_ => Err(Diagnostics::error_string(format!(
|
ValueKind::String(s) => Ok(s),
|
||||||
"expected string, found {}",
|
_ => Err(Diagnostic::error_string(format!(
|
||||||
v.diagnostic_type_str()
|
"expected string, found {}",
|
||||||
))
|
v.diagnostic_type_str()
|
||||||
.with_path(path.clone())),
|
))
|
||||||
|
.with_path(path.clone())
|
||||||
|
.into()),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ async fn init_handshake(server_cert: &rcgen::Certificate) -> Result<(tempfile::T
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod __derive_private {
|
pub mod __derive_private {
|
||||||
pub use crate::framework::{
|
pub use crate::framework::{
|
||||||
AttrPath, AttrPathSegment, BaseValue, DResult, Diagnostics, ValueModel,
|
AttrPath, AttrPathSegment, BaseValue, DResult, Diagnostic, Diagnostics, ValueModel,
|
||||||
};
|
};
|
||||||
pub use crate::values::{Value, ValueKind};
|
pub use crate::values::{Value, ValueKind};
|
||||||
pub use {Clone, Option::Some, Result::Err, ToOwned};
|
pub use {Clone, Option::Some, Result::Err, ToOwned};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
framework::{
|
framework::{
|
||||||
datasource::{self, Mode},
|
datasource::{self, Mode},
|
||||||
Diagnostics,
|
AttrPathSegment, Diagnostics,
|
||||||
},
|
},
|
||||||
values::Type,
|
values::Type,
|
||||||
};
|
};
|
||||||
|
|
@ -78,13 +78,37 @@ impl datasource::Attribute {
|
||||||
|
|
||||||
impl Diagnostics {
|
impl Diagnostics {
|
||||||
pub(crate) fn to_tfplugin_diags(self) -> Vec<tfplugin6::Diagnostic> {
|
pub(crate) fn to_tfplugin_diags(self) -> Vec<tfplugin6::Diagnostic> {
|
||||||
self.errors
|
self.diags
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|err| tfplugin6::Diagnostic {
|
.map(|err| tfplugin6::Diagnostic {
|
||||||
severity: tfplugin6::diagnostic::Severity::Error as _,
|
severity: tfplugin6::diagnostic::Severity::Error as _,
|
||||||
summary: err,
|
summary: err.msg,
|
||||||
detail: "".to_owned(),
|
detail: "".to_owned(),
|
||||||
attribute: None,
|
attribute: err.attr.map(|attr| -> tfplugin6::AttributePath {
|
||||||
|
tfplugin6::AttributePath {
|
||||||
|
steps: attr
|
||||||
|
.0
|
||||||
|
.into_iter()
|
||||||
|
.map(|segment| {
|
||||||
|
use tfplugin6::attribute_path::step::Selector;
|
||||||
|
|
||||||
|
tfplugin6::attribute_path::Step {
|
||||||
|
selector: Some(match segment {
|
||||||
|
AttrPathSegment::AttributeName(name) => {
|
||||||
|
Selector::AttributeName(name)
|
||||||
|
}
|
||||||
|
AttrPathSegment::ElementKeyString(key) => {
|
||||||
|
Selector::ElementKeyString(key)
|
||||||
|
}
|
||||||
|
AttrPathSegment::ElementKeyInt(key) => {
|
||||||
|
Selector::ElementKeyInt(key)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use std::{
|
||||||
io::{self, Read},
|
io::{self, Read},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::framework::{BaseValue, DResult, Diagnostics};
|
use crate::framework::{BaseValue, DResult, Diagnostic};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
|
|
@ -250,16 +250,17 @@ impl Value {
|
||||||
let len = mp::read_map_len(rd)?;
|
let len = mp::read_map_len(rd)?;
|
||||||
|
|
||||||
if attrs.len() != (len as usize) {
|
if attrs.len() != (len as usize) {
|
||||||
return Err(Diagnostics::error_string(format!(
|
return Err(Diagnostic::error_string(format!(
|
||||||
"expected {} attrs, found {len} attrs in object",
|
"expected {} attrs, found {len} attrs in object",
|
||||||
attrs.len()
|
attrs.len()
|
||||||
)));
|
))
|
||||||
|
.into());
|
||||||
}
|
}
|
||||||
let elems = (0..len)
|
let elems = (0..len)
|
||||||
.map(|_| -> DResult<_> {
|
.map(|_| -> DResult<_> {
|
||||||
let key = read_string(rd)?;
|
let key = read_string(rd)?;
|
||||||
let typ = attrs.get(&key).ok_or_else(|| {
|
let typ = attrs.get(&key).ok_or_else(|| {
|
||||||
Diagnostics::error_string(format!("unexpected attribute: '{key}'"))
|
Diagnostic::error_string(format!("unexpected attribute: '{key}'"))
|
||||||
})?;
|
})?;
|
||||||
let value = Value::msg_unpack_inner(rd, &typ)?;
|
let value = Value::msg_unpack_inner(rd, &typ)?;
|
||||||
Ok((key, value))
|
Ok((key, value))
|
||||||
|
|
@ -270,10 +271,11 @@ impl Value {
|
||||||
Type::Tuple { elems } => {
|
Type::Tuple { elems } => {
|
||||||
let len = mp::read_array_len(rd)?;
|
let len = mp::read_array_len(rd)?;
|
||||||
if elems.len() != (len as usize) {
|
if elems.len() != (len as usize) {
|
||||||
return Err(Diagnostics::error_string(format!(
|
return Err(Diagnostic::error_string(format!(
|
||||||
"expected {} elems, found {len} elems in tuple",
|
"expected {} elems, found {len} elems in tuple",
|
||||||
elems.len()
|
elems.len()
|
||||||
)));
|
))
|
||||||
|
.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let elems = elems
|
let elems = elems
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue