133 lines
3.6 KiB
Go
133 lines
3.6 KiB
Go
package convert
|
|
|
|
import (
|
|
proto "github.com/hashicorp/terraform/internal/tfplugin5"
|
|
"github.com/hashicorp/terraform/tfdiags"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
// WarnsAndErrorsToProto converts the warnings and errors return by the legacy
|
|
// provider to protobuf diagnostics.
|
|
func WarnsAndErrsToProto(warns []string, errs []error) (diags []*proto.Diagnostic) {
|
|
for _, w := range warns {
|
|
diags = AppendProtoDiag(diags, w)
|
|
}
|
|
|
|
for _, e := range errs {
|
|
diags = AppendProtoDiag(diags, e)
|
|
}
|
|
|
|
return diags
|
|
}
|
|
|
|
// AppendProtoDiag appends a new diagnostic from a warning string or an error.
|
|
// This panics if d is not a string or error.
|
|
func AppendProtoDiag(diags []*proto.Diagnostic, d interface{}) []*proto.Diagnostic {
|
|
switch d := d.(type) {
|
|
case cty.PathError:
|
|
ap := PathToAttributePath(d.Path)
|
|
diags = append(diags, &proto.Diagnostic{
|
|
Severity: proto.Diagnostic_ERROR,
|
|
Summary: d.Error(),
|
|
Attribute: ap,
|
|
})
|
|
case error:
|
|
diags = append(diags, &proto.Diagnostic{
|
|
Severity: proto.Diagnostic_ERROR,
|
|
Summary: d.Error(),
|
|
})
|
|
case string:
|
|
diags = append(diags, &proto.Diagnostic{
|
|
Severity: proto.Diagnostic_WARNING,
|
|
Summary: d,
|
|
})
|
|
case *proto.Diagnostic:
|
|
diags = append(diags, d)
|
|
case []*proto.Diagnostic:
|
|
diags = append(diags, d...)
|
|
}
|
|
return diags
|
|
}
|
|
|
|
// ProtoToDiagnostics converts a list of proto.Diagnostics to a tf.Diagnostics.
|
|
func ProtoToDiagnostics(ds []*proto.Diagnostic) tfdiags.Diagnostics {
|
|
var diags tfdiags.Diagnostics
|
|
for _, d := range ds {
|
|
var severity tfdiags.Severity
|
|
|
|
switch d.Severity {
|
|
case proto.Diagnostic_ERROR:
|
|
severity = tfdiags.Error
|
|
case proto.Diagnostic_WARNING:
|
|
severity = tfdiags.Warning
|
|
}
|
|
|
|
var newDiag tfdiags.Diagnostic
|
|
|
|
// if there's an attribute path, we need to create a AttributeValue diagnostic
|
|
if d.Attribute != nil {
|
|
path := AttributePathToPath(d.Attribute)
|
|
newDiag = tfdiags.AttributeValue(severity, d.Summary, d.Detail, path)
|
|
} else {
|
|
newDiag = tfdiags.WholeContainingBody(severity, d.Summary, d.Detail)
|
|
}
|
|
|
|
diags = diags.Append(newDiag)
|
|
}
|
|
|
|
return diags
|
|
}
|
|
|
|
// AttributePathToPath takes the proto encoded path and converts it to a cty.Path
|
|
func AttributePathToPath(ap *proto.AttributePath) cty.Path {
|
|
var p cty.Path
|
|
for _, step := range ap.Steps {
|
|
switch selector := step.Selector.(type) {
|
|
case *proto.AttributePath_Step_AttributeName:
|
|
p = p.GetAttr(selector.AttributeName)
|
|
case *proto.AttributePath_Step_ElementKeyString:
|
|
p = p.Index(cty.StringVal(selector.ElementKeyString))
|
|
case *proto.AttributePath_Step_ElementKeyInt:
|
|
p = p.Index(cty.NumberIntVal(selector.ElementKeyInt))
|
|
}
|
|
}
|
|
return p
|
|
}
|
|
|
|
// AttributePathToPath takes a cty.Path and converts it to a proto-encoded path.
|
|
func PathToAttributePath(p cty.Path) *proto.AttributePath {
|
|
ap := &proto.AttributePath{}
|
|
for _, step := range p {
|
|
switch selector := step.(type) {
|
|
case cty.GetAttrStep:
|
|
ap.Steps = append(ap.Steps, &proto.AttributePath_Step{
|
|
Selector: &proto.AttributePath_Step_AttributeName{
|
|
AttributeName: selector.Name,
|
|
},
|
|
})
|
|
case cty.IndexStep:
|
|
key := selector.Key
|
|
switch key.Type() {
|
|
case cty.String:
|
|
ap.Steps = append(ap.Steps, &proto.AttributePath_Step{
|
|
Selector: &proto.AttributePath_Step_ElementKeyString{
|
|
ElementKeyString: key.AsString(),
|
|
},
|
|
})
|
|
case cty.Number:
|
|
v, _ := key.AsBigFloat().Int64()
|
|
ap.Steps = append(ap.Steps, &proto.AttributePath_Step{
|
|
Selector: &proto.AttributePath_Step_ElementKeyInt{
|
|
ElementKeyInt: v,
|
|
},
|
|
})
|
|
default:
|
|
// We'll bail early if we encounter anything else, and just
|
|
// return the valid prefix.
|
|
return ap
|
|
}
|
|
}
|
|
}
|
|
return ap
|
|
}
|