diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/tfdiags')
9 files changed, 457 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/tfdiags/diagnostic.go b/vendor/github.com/hashicorp/terraform/tfdiags/diagnostic.go new file mode 100644 index 0000000..2c23f76 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/tfdiags/diagnostic.go | |||
@@ -0,0 +1,26 @@ | |||
1 | package tfdiags | ||
2 | |||
3 | type Diagnostic interface { | ||
4 | Severity() Severity | ||
5 | Description() Description | ||
6 | Source() Source | ||
7 | } | ||
8 | |||
9 | type Severity rune | ||
10 | |||
11 | //go:generate stringer -type=Severity | ||
12 | |||
13 | const ( | ||
14 | Error Severity = 'E' | ||
15 | Warning Severity = 'W' | ||
16 | ) | ||
17 | |||
18 | type Description struct { | ||
19 | Summary string | ||
20 | Detail string | ||
21 | } | ||
22 | |||
23 | type Source struct { | ||
24 | Subject *SourceRange | ||
25 | Context *SourceRange | ||
26 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/tfdiags/diagnostics.go b/vendor/github.com/hashicorp/terraform/tfdiags/diagnostics.go new file mode 100644 index 0000000..667ba80 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/tfdiags/diagnostics.go | |||
@@ -0,0 +1,181 @@ | |||
1 | package tfdiags | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "fmt" | ||
6 | |||
7 | "github.com/hashicorp/errwrap" | ||
8 | multierror "github.com/hashicorp/go-multierror" | ||
9 | "github.com/hashicorp/hcl2/hcl" | ||
10 | ) | ||
11 | |||
12 | // Diagnostics is a list of diagnostics. Diagnostics is intended to be used | ||
13 | // where a Go "error" might normally be used, allowing richer information | ||
14 | // to be conveyed (more context, support for warnings). | ||
15 | // | ||
16 | // A nil Diagnostics is a valid, empty diagnostics list, thus allowing | ||
17 | // heap allocation to be avoided in the common case where there are no | ||
18 | // diagnostics to report at all. | ||
19 | type Diagnostics []Diagnostic | ||
20 | |||
21 | // Append is the main interface for constructing Diagnostics lists, taking | ||
22 | // an existing list (which may be nil) and appending the new objects to it | ||
23 | // after normalizing them to be implementations of Diagnostic. | ||
24 | // | ||
25 | // The usual pattern for a function that natively "speaks" diagnostics is: | ||
26 | // | ||
27 | // // Create a nil Diagnostics at the start of the function | ||
28 | // var diags diag.Diagnostics | ||
29 | // | ||
30 | // // At later points, build on it if errors / warnings occur: | ||
31 | // foo, err := DoSomethingRisky() | ||
32 | // if err != nil { | ||
33 | // diags = diags.Append(err) | ||
34 | // } | ||
35 | // | ||
36 | // // Eventually return the result and diagnostics in place of error | ||
37 | // return result, diags | ||
38 | // | ||
39 | // Append accepts a variety of different diagnostic-like types, including | ||
40 | // native Go errors and HCL diagnostics. It also knows how to unwrap | ||
41 | // a multierror.Error into separate error diagnostics. It can be passed | ||
42 | // another Diagnostics to concatenate the two lists. If given something | ||
43 | // it cannot handle, this function will panic. | ||
44 | func (diags Diagnostics) Append(new ...interface{}) Diagnostics { | ||
45 | for _, item := range new { | ||
46 | if item == nil { | ||
47 | continue | ||
48 | } | ||
49 | |||
50 | switch ti := item.(type) { | ||
51 | case Diagnostic: | ||
52 | diags = append(diags, ti) | ||
53 | case Diagnostics: | ||
54 | diags = append(diags, ti...) // flatten | ||
55 | case diagnosticsAsError: | ||
56 | diags = diags.Append(ti.Diagnostics) // unwrap | ||
57 | case hcl.Diagnostics: | ||
58 | for _, hclDiag := range ti { | ||
59 | diags = append(diags, hclDiagnostic{hclDiag}) | ||
60 | } | ||
61 | case *hcl.Diagnostic: | ||
62 | diags = append(diags, hclDiagnostic{ti}) | ||
63 | case *multierror.Error: | ||
64 | for _, err := range ti.Errors { | ||
65 | diags = append(diags, nativeError{err}) | ||
66 | } | ||
67 | case error: | ||
68 | switch { | ||
69 | case errwrap.ContainsType(ti, Diagnostics(nil)): | ||
70 | // If we have an errwrap wrapper with a Diagnostics hiding | ||
71 | // inside then we'll unpick it here to get access to the | ||
72 | // individual diagnostics. | ||
73 | diags = diags.Append(errwrap.GetType(ti, Diagnostics(nil))) | ||
74 | case errwrap.ContainsType(ti, hcl.Diagnostics(nil)): | ||
75 | // Likewise, if we have HCL diagnostics we'll unpick that too. | ||
76 | diags = diags.Append(errwrap.GetType(ti, hcl.Diagnostics(nil))) | ||
77 | default: | ||
78 | diags = append(diags, nativeError{ti}) | ||
79 | } | ||
80 | default: | ||
81 | panic(fmt.Errorf("can't construct diagnostic(s) from %T", item)) | ||
82 | } | ||
83 | } | ||
84 | |||
85 | // Given the above, we should never end up with a non-nil empty slice | ||
86 | // here, but we'll make sure of that so callers can rely on empty == nil | ||
87 | if len(diags) == 0 { | ||
88 | return nil | ||
89 | } | ||
90 | |||
91 | return diags | ||
92 | } | ||
93 | |||
94 | // HasErrors returns true if any of the diagnostics in the list have | ||
95 | // a severity of Error. | ||
96 | func (diags Diagnostics) HasErrors() bool { | ||
97 | for _, diag := range diags { | ||
98 | if diag.Severity() == Error { | ||
99 | return true | ||
100 | } | ||
101 | } | ||
102 | return false | ||
103 | } | ||
104 | |||
105 | // ForRPC returns a version of the receiver that has been simplified so that | ||
106 | // it is friendly to RPC protocols. | ||
107 | // | ||
108 | // Currently this means that it can be serialized with encoding/gob and | ||
109 | // subsequently re-inflated. It may later grow to include other serialization | ||
110 | // formats. | ||
111 | // | ||
112 | // Note that this loses information about the original objects used to | ||
113 | // construct the diagnostics, so e.g. the errwrap API will not work as | ||
114 | // expected on an error-wrapped Diagnostics that came from ForRPC. | ||
115 | func (diags Diagnostics) ForRPC() Diagnostics { | ||
116 | ret := make(Diagnostics, len(diags)) | ||
117 | for i := range diags { | ||
118 | ret[i] = makeRPCFriendlyDiag(diags[i]) | ||
119 | } | ||
120 | return ret | ||
121 | } | ||
122 | |||
123 | // Err flattens a diagnostics list into a single Go error, or to nil | ||
124 | // if the diagnostics list does not include any error-level diagnostics. | ||
125 | // | ||
126 | // This can be used to smuggle diagnostics through an API that deals in | ||
127 | // native errors, but unfortunately it will lose naked warnings (warnings | ||
128 | // that aren't accompanied by at least one error) since such APIs have no | ||
129 | // mechanism through which to report these. | ||
130 | // | ||
131 | // return result, diags.Error() | ||
132 | func (diags Diagnostics) Err() error { | ||
133 | if !diags.HasErrors() { | ||
134 | return nil | ||
135 | } | ||
136 | return diagnosticsAsError{diags} | ||
137 | } | ||
138 | |||
139 | type diagnosticsAsError struct { | ||
140 | Diagnostics | ||
141 | } | ||
142 | |||
143 | func (dae diagnosticsAsError) Error() string { | ||
144 | diags := dae.Diagnostics | ||
145 | switch { | ||
146 | case len(diags) == 0: | ||
147 | // should never happen, since we don't create this wrapper if | ||
148 | // there are no diagnostics in the list. | ||
149 | return "no errors" | ||
150 | case len(diags) == 1: | ||
151 | desc := diags[0].Description() | ||
152 | if desc.Detail == "" { | ||
153 | return desc.Summary | ||
154 | } | ||
155 | return fmt.Sprintf("%s: %s", desc.Summary, desc.Detail) | ||
156 | default: | ||
157 | var ret bytes.Buffer | ||
158 | fmt.Fprintf(&ret, "%d problems:\n", len(diags)) | ||
159 | for _, diag := range dae.Diagnostics { | ||
160 | desc := diag.Description() | ||
161 | if desc.Detail == "" { | ||
162 | fmt.Fprintf(&ret, "\n- %s", desc.Summary) | ||
163 | } else { | ||
164 | fmt.Fprintf(&ret, "\n- %s: %s", desc.Summary, desc.Detail) | ||
165 | } | ||
166 | } | ||
167 | return ret.String() | ||
168 | } | ||
169 | } | ||
170 | |||
171 | // WrappedErrors is an implementation of errwrap.Wrapper so that an error-wrapped | ||
172 | // diagnostics object can be picked apart by errwrap-aware code. | ||
173 | func (dae diagnosticsAsError) WrappedErrors() []error { | ||
174 | var errs []error | ||
175 | for _, diag := range dae.Diagnostics { | ||
176 | if wrapper, isErr := diag.(nativeError); isErr { | ||
177 | errs = append(errs, wrapper.err) | ||
178 | } | ||
179 | } | ||
180 | return errs | ||
181 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/tfdiags/doc.go b/vendor/github.com/hashicorp/terraform/tfdiags/doc.go new file mode 100644 index 0000000..c427879 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/tfdiags/doc.go | |||
@@ -0,0 +1,16 @@ | |||
1 | // Package tfdiags is a utility package for representing errors and | ||
2 | // warnings in a manner that allows us to produce good messages for the | ||
3 | // user. | ||
4 | // | ||
5 | // "diag" is short for "diagnostics", and is meant as a general word for | ||
6 | // feedback to a user about potential or actual problems. | ||
7 | // | ||
8 | // A design goal for this package is for it to be able to provide rich | ||
9 | // messaging where possible but to also be pragmatic about dealing with | ||
10 | // generic errors produced by system components that _can't_ provide | ||
11 | // such rich messaging. As a consequence, the main types in this package -- | ||
12 | // Diagnostics and Diagnostic -- are designed so that they can be "smuggled" | ||
13 | // over an error channel and then be unpacked at the other end, so that | ||
14 | // error diagnostics (at least) can transit through APIs that are not | ||
15 | // aware of this package. | ||
16 | package tfdiags | ||
diff --git a/vendor/github.com/hashicorp/terraform/tfdiags/error.go b/vendor/github.com/hashicorp/terraform/tfdiags/error.go new file mode 100644 index 0000000..35edc30 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/tfdiags/error.go | |||
@@ -0,0 +1,23 @@ | |||
1 | package tfdiags | ||
2 | |||
3 | // nativeError is a Diagnostic implementation that wraps a normal Go error | ||
4 | type nativeError struct { | ||
5 | err error | ||
6 | } | ||
7 | |||
8 | var _ Diagnostic = nativeError{} | ||
9 | |||
10 | func (e nativeError) Severity() Severity { | ||
11 | return Error | ||
12 | } | ||
13 | |||
14 | func (e nativeError) Description() Description { | ||
15 | return Description{ | ||
16 | Summary: e.err.Error(), | ||
17 | } | ||
18 | } | ||
19 | |||
20 | func (e nativeError) Source() Source { | ||
21 | // No source information available for a native error | ||
22 | return Source{} | ||
23 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/tfdiags/hcl.go b/vendor/github.com/hashicorp/terraform/tfdiags/hcl.go new file mode 100644 index 0000000..24851f4 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/tfdiags/hcl.go | |||
@@ -0,0 +1,77 @@ | |||
1 | package tfdiags | ||
2 | |||
3 | import ( | ||
4 | "github.com/hashicorp/hcl2/hcl" | ||
5 | ) | ||
6 | |||
7 | // hclDiagnostic is a Diagnostic implementation that wraps a HCL Diagnostic | ||
8 | type hclDiagnostic struct { | ||
9 | diag *hcl.Diagnostic | ||
10 | } | ||
11 | |||
12 | var _ Diagnostic = hclDiagnostic{} | ||
13 | |||
14 | func (d hclDiagnostic) Severity() Severity { | ||
15 | switch d.diag.Severity { | ||
16 | case hcl.DiagWarning: | ||
17 | return Warning | ||
18 | default: | ||
19 | return Error | ||
20 | } | ||
21 | } | ||
22 | |||
23 | func (d hclDiagnostic) Description() Description { | ||
24 | return Description{ | ||
25 | Summary: d.diag.Summary, | ||
26 | Detail: d.diag.Detail, | ||
27 | } | ||
28 | } | ||
29 | |||
30 | func (d hclDiagnostic) Source() Source { | ||
31 | var ret Source | ||
32 | if d.diag.Subject != nil { | ||
33 | rng := SourceRangeFromHCL(*d.diag.Subject) | ||
34 | ret.Subject = &rng | ||
35 | } | ||
36 | if d.diag.Context != nil { | ||
37 | rng := SourceRangeFromHCL(*d.diag.Context) | ||
38 | ret.Context = &rng | ||
39 | } | ||
40 | return ret | ||
41 | } | ||
42 | |||
43 | // SourceRangeFromHCL constructs a SourceRange from the corresponding range | ||
44 | // type within the HCL package. | ||
45 | func SourceRangeFromHCL(hclRange hcl.Range) SourceRange { | ||
46 | return SourceRange{ | ||
47 | Filename: hclRange.Filename, | ||
48 | Start: SourcePos{ | ||
49 | Line: hclRange.Start.Line, | ||
50 | Column: hclRange.Start.Column, | ||
51 | Byte: hclRange.Start.Byte, | ||
52 | }, | ||
53 | End: SourcePos{ | ||
54 | Line: hclRange.End.Line, | ||
55 | Column: hclRange.End.Column, | ||
56 | Byte: hclRange.End.Byte, | ||
57 | }, | ||
58 | } | ||
59 | } | ||
60 | |||
61 | // ToHCL constructs a HCL Range from the receiving SourceRange. This is the | ||
62 | // opposite of SourceRangeFromHCL. | ||
63 | func (r SourceRange) ToHCL() hcl.Range { | ||
64 | return hcl.Range{ | ||
65 | Filename: r.Filename, | ||
66 | Start: hcl.Pos{ | ||
67 | Line: r.Start.Line, | ||
68 | Column: r.Start.Column, | ||
69 | Byte: r.Start.Byte, | ||
70 | }, | ||
71 | End: hcl.Pos{ | ||
72 | Line: r.End.Line, | ||
73 | Column: r.End.Column, | ||
74 | Byte: r.End.Byte, | ||
75 | }, | ||
76 | } | ||
77 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/tfdiags/rpc_friendly.go b/vendor/github.com/hashicorp/terraform/tfdiags/rpc_friendly.go new file mode 100644 index 0000000..6cc95cc --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/tfdiags/rpc_friendly.go | |||
@@ -0,0 +1,53 @@ | |||
1 | package tfdiags | ||
2 | |||
3 | import ( | ||
4 | "encoding/gob" | ||
5 | ) | ||
6 | |||
7 | type rpcFriendlyDiag struct { | ||
8 | Severity_ Severity | ||
9 | Summary_ string | ||
10 | Detail_ string | ||
11 | Subject_ *SourceRange | ||
12 | Context_ *SourceRange | ||
13 | } | ||
14 | |||
15 | // rpcFriendlyDiag transforms a given diagnostic so that is more friendly to | ||
16 | // RPC. | ||
17 | // | ||
18 | // In particular, it currently returns an object that can be serialized and | ||
19 | // later re-inflated using gob. This definition may grow to include other | ||
20 | // serializations later. | ||
21 | func makeRPCFriendlyDiag(diag Diagnostic) Diagnostic { | ||
22 | desc := diag.Description() | ||
23 | source := diag.Source() | ||
24 | return &rpcFriendlyDiag{ | ||
25 | Severity_: diag.Severity(), | ||
26 | Summary_: desc.Summary, | ||
27 | Detail_: desc.Detail, | ||
28 | Subject_: source.Subject, | ||
29 | Context_: source.Context, | ||
30 | } | ||
31 | } | ||
32 | |||
33 | func (d *rpcFriendlyDiag) Severity() Severity { | ||
34 | return d.Severity_ | ||
35 | } | ||
36 | |||
37 | func (d *rpcFriendlyDiag) Description() Description { | ||
38 | return Description{ | ||
39 | Summary: d.Summary_, | ||
40 | Detail: d.Detail_, | ||
41 | } | ||
42 | } | ||
43 | |||
44 | func (d *rpcFriendlyDiag) Source() Source { | ||
45 | return Source{ | ||
46 | Subject: d.Subject_, | ||
47 | Context: d.Context_, | ||
48 | } | ||
49 | } | ||
50 | |||
51 | func init() { | ||
52 | gob.Register((*rpcFriendlyDiag)(nil)) | ||
53 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/tfdiags/severity_string.go b/vendor/github.com/hashicorp/terraform/tfdiags/severity_string.go new file mode 100644 index 0000000..0b1249b --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/tfdiags/severity_string.go | |||
@@ -0,0 +1,21 @@ | |||
1 | // Code generated by "stringer -type=Severity"; DO NOT EDIT. | ||
2 | |||
3 | package tfdiags | ||
4 | |||
5 | import "strconv" | ||
6 | |||
7 | const ( | ||
8 | _Severity_name_0 = "Error" | ||
9 | _Severity_name_1 = "Warning" | ||
10 | ) | ||
11 | |||
12 | func (i Severity) String() string { | ||
13 | switch { | ||
14 | case i == 69: | ||
15 | return _Severity_name_0 | ||
16 | case i == 87: | ||
17 | return _Severity_name_1 | ||
18 | default: | ||
19 | return "Severity(" + strconv.FormatInt(int64(i), 10) + ")" | ||
20 | } | ||
21 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/tfdiags/simple_warning.go b/vendor/github.com/hashicorp/terraform/tfdiags/simple_warning.go new file mode 100644 index 0000000..fb3ac98 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/tfdiags/simple_warning.go | |||
@@ -0,0 +1,25 @@ | |||
1 | package tfdiags | ||
2 | |||
3 | type simpleWarning string | ||
4 | |||
5 | var _ Diagnostic = simpleWarning("") | ||
6 | |||
7 | // SimpleWarning constructs a simple (summary-only) warning diagnostic. | ||
8 | func SimpleWarning(msg string) Diagnostic { | ||
9 | return simpleWarning(msg) | ||
10 | } | ||
11 | |||
12 | func (e simpleWarning) Severity() Severity { | ||
13 | return Warning | ||
14 | } | ||
15 | |||
16 | func (e simpleWarning) Description() Description { | ||
17 | return Description{ | ||
18 | Summary: string(e), | ||
19 | } | ||
20 | } | ||
21 | |||
22 | func (e simpleWarning) Source() Source { | ||
23 | // No source information available for a native error | ||
24 | return Source{} | ||
25 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/tfdiags/source_range.go b/vendor/github.com/hashicorp/terraform/tfdiags/source_range.go new file mode 100644 index 0000000..3031168 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/tfdiags/source_range.go | |||
@@ -0,0 +1,35 @@ | |||
1 | package tfdiags | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "os" | ||
6 | "path/filepath" | ||
7 | ) | ||
8 | |||
9 | type SourceRange struct { | ||
10 | Filename string | ||
11 | Start, End SourcePos | ||
12 | } | ||
13 | |||
14 | type SourcePos struct { | ||
15 | Line, Column, Byte int | ||
16 | } | ||
17 | |||
18 | // StartString returns a string representation of the start of the range, | ||
19 | // including the filename and the line and column numbers. | ||
20 | func (r SourceRange) StartString() string { | ||
21 | filename := r.Filename | ||
22 | |||
23 | // We'll try to relative-ize our filename here so it's less verbose | ||
24 | // in the common case of being in the current working directory. If not, | ||
25 | // we'll just show the full path. | ||
26 | wd, err := os.Getwd() | ||
27 | if err == nil { | ||
28 | relFn, err := filepath.Rel(wd, filename) | ||
29 | if err == nil { | ||
30 | filename = relFn | ||
31 | } | ||
32 | } | ||
33 | |||
34 | return fmt.Sprintf("%s:%d,%d", filename, r.Start.Line, r.Start.Column) | ||
35 | } | ||