4 proto "github.com/hashicorp/terraform/internal/tfplugin5"
5 "github.com/hashicorp/terraform/tfdiags"
6 "github.com/zclconf/go-cty/cty"
9 // WarnsAndErrorsToProto converts the warnings and errors return by the legacy
10 // provider to protobuf diagnostics.
11 func WarnsAndErrsToProto(warns []string, errs []error) (diags []*proto.Diagnostic) {
12 for _, w := range warns {
13 diags = AppendProtoDiag(diags, w)
16 for _, e := range errs {
17 diags = AppendProtoDiag(diags, e)
23 // AppendProtoDiag appends a new diagnostic from a warning string or an error.
24 // This panics if d is not a string or error.
25 func AppendProtoDiag(diags []*proto.Diagnostic, d interface{}) []*proto.Diagnostic {
26 switch d := d.(type) {
28 ap := PathToAttributePath(d.Path)
29 diags = append(diags, &proto.Diagnostic{
30 Severity: proto.Diagnostic_ERROR,
35 diags = append(diags, &proto.Diagnostic{
36 Severity: proto.Diagnostic_ERROR,
40 diags = append(diags, &proto.Diagnostic{
41 Severity: proto.Diagnostic_WARNING,
44 case *proto.Diagnostic:
45 diags = append(diags, d)
46 case []*proto.Diagnostic:
47 diags = append(diags, d...)
52 // ProtoToDiagnostics converts a list of proto.Diagnostics to a tf.Diagnostics.
53 func ProtoToDiagnostics(ds []*proto.Diagnostic) tfdiags.Diagnostics {
54 var diags tfdiags.Diagnostics
55 for _, d := range ds {
56 var severity tfdiags.Severity
59 case proto.Diagnostic_ERROR:
60 severity = tfdiags.Error
61 case proto.Diagnostic_WARNING:
62 severity = tfdiags.Warning
65 var newDiag tfdiags.Diagnostic
67 // if there's an attribute path, we need to create a AttributeValue diagnostic
68 if d.Attribute != nil {
69 path := AttributePathToPath(d.Attribute)
70 newDiag = tfdiags.AttributeValue(severity, d.Summary, d.Detail, path)
72 newDiag = tfdiags.WholeContainingBody(severity, d.Summary, d.Detail)
75 diags = diags.Append(newDiag)
81 // AttributePathToPath takes the proto encoded path and converts it to a cty.Path
82 func AttributePathToPath(ap *proto.AttributePath) cty.Path {
84 for _, step := range ap.Steps {
85 switch selector := step.Selector.(type) {
86 case *proto.AttributePath_Step_AttributeName:
87 p = p.GetAttr(selector.AttributeName)
88 case *proto.AttributePath_Step_ElementKeyString:
89 p = p.Index(cty.StringVal(selector.ElementKeyString))
90 case *proto.AttributePath_Step_ElementKeyInt:
91 p = p.Index(cty.NumberIntVal(selector.ElementKeyInt))
97 // AttributePathToPath takes a cty.Path and converts it to a proto-encoded path.
98 func PathToAttributePath(p cty.Path) *proto.AttributePath {
99 ap := &proto.AttributePath{}
100 for _, step := range p {
101 switch selector := step.(type) {
102 case cty.GetAttrStep:
103 ap.Steps = append(ap.Steps, &proto.AttributePath_Step{
104 Selector: &proto.AttributePath_Step_AttributeName{
105 AttributeName: selector.Name,
112 ap.Steps = append(ap.Steps, &proto.AttributePath_Step{
113 Selector: &proto.AttributePath_Step_ElementKeyString{
114 ElementKeyString: key.AsString(),
118 v, _ := key.AsBigFloat().Int64()
119 ap.Steps = append(ap.Steps, &proto.AttributePath_Step{
120 Selector: &proto.AttributePath_Step_ElementKeyInt{
125 // We'll bail early if we encounter anything else, and just
126 // return the valid prefix.