aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/tfdiags
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/tfdiags')
-rw-r--r--vendor/github.com/hashicorp/terraform/tfdiags/diagnostic.go26
-rw-r--r--vendor/github.com/hashicorp/terraform/tfdiags/diagnostics.go181
-rw-r--r--vendor/github.com/hashicorp/terraform/tfdiags/doc.go16
-rw-r--r--vendor/github.com/hashicorp/terraform/tfdiags/error.go23
-rw-r--r--vendor/github.com/hashicorp/terraform/tfdiags/hcl.go77
-rw-r--r--vendor/github.com/hashicorp/terraform/tfdiags/rpc_friendly.go53
-rw-r--r--vendor/github.com/hashicorp/terraform/tfdiags/severity_string.go21
-rw-r--r--vendor/github.com/hashicorp/terraform/tfdiags/simple_warning.go25
-rw-r--r--vendor/github.com/hashicorp/terraform/tfdiags/source_range.go35
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 @@
1package tfdiags
2
3type Diagnostic interface {
4 Severity() Severity
5 Description() Description
6 Source() Source
7}
8
9type Severity rune
10
11//go:generate stringer -type=Severity
12
13const (
14 Error Severity = 'E'
15 Warning Severity = 'W'
16)
17
18type Description struct {
19 Summary string
20 Detail string
21}
22
23type 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 @@
1package tfdiags
2
3import (
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.
19type 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.
44func (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.
96func (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.
115func (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()
132func (diags Diagnostics) Err() error {
133 if !diags.HasErrors() {
134 return nil
135 }
136 return diagnosticsAsError{diags}
137}
138
139type diagnosticsAsError struct {
140 Diagnostics
141}
142
143func (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.
173func (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.
16package 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 @@
1package tfdiags
2
3// nativeError is a Diagnostic implementation that wraps a normal Go error
4type nativeError struct {
5 err error
6}
7
8var _ Diagnostic = nativeError{}
9
10func (e nativeError) Severity() Severity {
11 return Error
12}
13
14func (e nativeError) Description() Description {
15 return Description{
16 Summary: e.err.Error(),
17 }
18}
19
20func (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 @@
1package tfdiags
2
3import (
4 "github.com/hashicorp/hcl2/hcl"
5)
6
7// hclDiagnostic is a Diagnostic implementation that wraps a HCL Diagnostic
8type hclDiagnostic struct {
9 diag *hcl.Diagnostic
10}
11
12var _ Diagnostic = hclDiagnostic{}
13
14func (d hclDiagnostic) Severity() Severity {
15 switch d.diag.Severity {
16 case hcl.DiagWarning:
17 return Warning
18 default:
19 return Error
20 }
21}
22
23func (d hclDiagnostic) Description() Description {
24 return Description{
25 Summary: d.diag.Summary,
26 Detail: d.diag.Detail,
27 }
28}
29
30func (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.
45func 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.
63func (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 @@
1package tfdiags
2
3import (
4 "encoding/gob"
5)
6
7type 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.
21func 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
33func (d *rpcFriendlyDiag) Severity() Severity {
34 return d.Severity_
35}
36
37func (d *rpcFriendlyDiag) Description() Description {
38 return Description{
39 Summary: d.Summary_,
40 Detail: d.Detail_,
41 }
42}
43
44func (d *rpcFriendlyDiag) Source() Source {
45 return Source{
46 Subject: d.Subject_,
47 Context: d.Context_,
48 }
49}
50
51func 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
3package tfdiags
4
5import "strconv"
6
7const (
8 _Severity_name_0 = "Error"
9 _Severity_name_1 = "Warning"
10)
11
12func (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 @@
1package tfdiags
2
3type simpleWarning string
4
5var _ Diagnostic = simpleWarning("")
6
7// SimpleWarning constructs a simple (summary-only) warning diagnostic.
8func SimpleWarning(msg string) Diagnostic {
9 return simpleWarning(msg)
10}
11
12func (e simpleWarning) Severity() Severity {
13 return Warning
14}
15
16func (e simpleWarning) Description() Description {
17 return Description{
18 Summary: string(e),
19 }
20}
21
22func (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 @@
1package tfdiags
2
3import (
4 "fmt"
5 "os"
6 "path/filepath"
7)
8
9type SourceRange struct {
10 Filename string
11 Start, End SourcePos
12}
13
14type 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.
20func (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}