]>
Commit | Line | Data |
---|---|---|
107c1cdb ND |
1 | package convert |
2 | ||
3 | import ( | |
4 | proto "github.com/hashicorp/terraform/internal/tfplugin5" | |
5 | "github.com/hashicorp/terraform/tfdiags" | |
6 | "github.com/zclconf/go-cty/cty" | |
7 | ) | |
8 | ||
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) | |
14 | } | |
15 | ||
16 | for _, e := range errs { | |
17 | diags = AppendProtoDiag(diags, e) | |
18 | } | |
19 | ||
20 | return diags | |
21 | } | |
22 | ||
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) { | |
27 | case cty.PathError: | |
28 | ap := PathToAttributePath(d.Path) | |
29 | diags = append(diags, &proto.Diagnostic{ | |
30 | Severity: proto.Diagnostic_ERROR, | |
31 | Summary: d.Error(), | |
32 | Attribute: ap, | |
33 | }) | |
34 | case error: | |
35 | diags = append(diags, &proto.Diagnostic{ | |
36 | Severity: proto.Diagnostic_ERROR, | |
37 | Summary: d.Error(), | |
38 | }) | |
39 | case string: | |
40 | diags = append(diags, &proto.Diagnostic{ | |
41 | Severity: proto.Diagnostic_WARNING, | |
42 | Summary: d, | |
43 | }) | |
44 | case *proto.Diagnostic: | |
45 | diags = append(diags, d) | |
46 | case []*proto.Diagnostic: | |
47 | diags = append(diags, d...) | |
48 | } | |
49 | return diags | |
50 | } | |
51 | ||
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 | |
57 | ||
58 | switch d.Severity { | |
59 | case proto.Diagnostic_ERROR: | |
60 | severity = tfdiags.Error | |
61 | case proto.Diagnostic_WARNING: | |
62 | severity = tfdiags.Warning | |
63 | } | |
64 | ||
65 | var newDiag tfdiags.Diagnostic | |
66 | ||
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) | |
71 | } else { | |
72 | newDiag = tfdiags.WholeContainingBody(severity, d.Summary, d.Detail) | |
73 | } | |
74 | ||
75 | diags = diags.Append(newDiag) | |
76 | } | |
77 | ||
78 | return diags | |
79 | } | |
80 | ||
81 | // AttributePathToPath takes the proto encoded path and converts it to a cty.Path | |
82 | func AttributePathToPath(ap *proto.AttributePath) cty.Path { | |
83 | var p 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)) | |
92 | } | |
93 | } | |
94 | return p | |
95 | } | |
96 | ||
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, | |
106 | }, | |
107 | }) | |
108 | case cty.IndexStep: | |
109 | key := selector.Key | |
110 | switch key.Type() { | |
111 | case cty.String: | |
112 | ap.Steps = append(ap.Steps, &proto.AttributePath_Step{ | |
113 | Selector: &proto.AttributePath_Step_ElementKeyString{ | |
114 | ElementKeyString: key.AsString(), | |
115 | }, | |
116 | }) | |
117 | case cty.Number: | |
118 | v, _ := key.AsBigFloat().Int64() | |
119 | ap.Steps = append(ap.Steps, &proto.AttributePath_Step{ | |
120 | Selector: &proto.AttributePath_Step_ElementKeyInt{ | |
121 | ElementKeyInt: v, | |
122 | }, | |
123 | }) | |
124 | default: | |
125 | // We'll bail early if we encounter anything else, and just | |
126 | // return the valid prefix. | |
127 | return ap | |
128 | } | |
129 | } | |
130 | } | |
131 | return ap | |
132 | } |