Skip to content

Commit 464bd75

Browse files
committed
Split errors and exit error wrappers to separate files
1 parent afe3776 commit 464bd75

File tree

2 files changed

+171
-164
lines changed

2 files changed

+171
-164
lines changed

tfexec/errors.go

Lines changed: 2 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,8 @@
11
package tfexec
22

3-
import (
4-
"errors"
5-
"fmt"
6-
"os/exec"
7-
"regexp"
8-
"strings"
9-
)
3+
import "fmt"
104

11-
var (
12-
// The "Required variable not set:" case is for 0.11
13-
missingVarErrRegexp = regexp.MustCompile(`Error: No value for required variable|Error: Required variable not set:`)
14-
missingVarNameRegexp = regexp.MustCompile(`The root module input variable "(.+)" is not set, and has no default|Error: Required variable not set: (.+)`)
15-
16-
usageRegexp = regexp.MustCompile(`Too many command line arguments|^Usage: .*Options:.*|Error: Invalid -\d+ option`)
17-
18-
// "Could not load plugin" is present in 0.13
19-
noInitErrRegexp = regexp.MustCompile(`Error: Could not satisfy plugin requirements|Error: Could not load plugin`)
20-
21-
noConfigErrRegexp = regexp.MustCompile(`Error: No configuration files`)
22-
23-
workspaceDoesNotExistRegexp = regexp.MustCompile(`Workspace "(.+)" doesn't exist.`)
24-
25-
workspaceAlreadyExistsRegexp = regexp.MustCompile(`Workspace "(.+)" already exists`)
26-
27-
tfVersionMismatchErrRegexp = regexp.MustCompile(`Error: The currently running version of Terraform doesn't meet the|Error: Unsupported Terraform Core version`)
28-
tfVersionMismatchConstraintRegexp = regexp.MustCompile(`required_version = "(.+)"|Required version: (.+)\b`)
29-
)
30-
31-
func (tf *Terraform) parseError(err error, stderr string) error {
32-
ee, ok := err.(*exec.ExitError)
33-
if !ok {
34-
return err
35-
}
36-
37-
switch {
38-
case tfVersionMismatchErrRegexp.MatchString(stderr):
39-
constraint := ""
40-
constraints := tfVersionMismatchConstraintRegexp.FindStringSubmatch(stderr)
41-
for i := 1; i < len(constraints); i++ {
42-
constraint = strings.TrimSpace(constraints[i])
43-
if constraint != "" {
44-
break
45-
}
46-
}
47-
48-
if constraint == "" {
49-
// hardcode a value here for weird cases (incl. 0.12)
50-
constraint = "unknown"
51-
}
52-
53-
// only set this if it happened to be cached already
54-
ver := ""
55-
if tf != nil && tf.execVersion != nil {
56-
ver = tf.execVersion.String()
57-
}
58-
59-
return &ErrTFVersionMismatch{
60-
Constraint: constraint,
61-
TFVersion: ver,
62-
}
63-
case missingVarErrRegexp.MatchString(stderr):
64-
name := ""
65-
names := missingVarNameRegexp.FindStringSubmatch(stderr)
66-
for i := 1; i < len(names); i++ {
67-
name = strings.TrimSpace(names[i])
68-
if name != "" {
69-
break
70-
}
71-
}
72-
73-
return &ErrMissingVar{name}
74-
case usageRegexp.MatchString(stderr):
75-
return &ErrCLIUsage{stderr: stderr}
76-
case noInitErrRegexp.MatchString(stderr):
77-
return &ErrNoInit{stderr: stderr}
78-
case noConfigErrRegexp.MatchString(stderr):
79-
return &ErrNoConfig{stderr: stderr}
80-
case workspaceDoesNotExistRegexp.MatchString(stderr):
81-
submatches := workspaceDoesNotExistRegexp.FindStringSubmatch(stderr)
82-
if len(submatches) == 2 {
83-
return &ErrNoWorkspace{submatches[1]}
84-
}
85-
case workspaceAlreadyExistsRegexp.MatchString(stderr):
86-
submatches := workspaceAlreadyExistsRegexp.FindStringSubmatch(stderr)
87-
if len(submatches) == 2 {
88-
return &ErrWorkspaceExists{submatches[1]}
89-
}
90-
}
91-
errString := strings.TrimSpace(stderr)
92-
if errString == "" {
93-
// if stderr is empty, return the ExitError directly, as it will have a better message
94-
return ee
95-
}
96-
return errors.New(stderr)
97-
}
5+
// this file contains non-parsed exported errors
986

997
type ErrNoSuitableBinary struct {
1008
err error
@@ -104,19 +12,6 @@ func (e *ErrNoSuitableBinary) Error() string {
10412
return fmt.Sprintf("no suitable terraform binary could be found: %s", e.err.Error())
10513
}
10614

107-
// ErrTFVersionMismatch is returned when the running Terraform version is not compatible with the
108-
// value specified for required_version in the terraform block.
109-
type ErrTFVersionMismatch struct {
110-
TFVersion string
111-
112-
// Constraint is not returned in the error messaging on 0.12
113-
Constraint string
114-
}
115-
116-
func (e *ErrTFVersionMismatch) Error() string {
117-
return "terraform core version not supported by configuration"
118-
}
119-
12015
// ErrVersionMismatch is returned when the detected Terraform version is not compatible with the
12116
// command or flags being used in this invocation.
12217
type ErrVersionMismatch struct {
@@ -129,38 +24,6 @@ func (e *ErrVersionMismatch) Error() string {
12924
return fmt.Sprintf("unexpected version %s (min: %s, max: %s)", e.Actual, e.MinInclusive, e.MaxExclusive)
13025
}
13126

132-
type ErrNoInit struct {
133-
stderr string
134-
}
135-
136-
func (e *ErrNoInit) Error() string {
137-
return e.stderr
138-
}
139-
140-
type ErrNoConfig struct {
141-
stderr string
142-
}
143-
144-
func (e *ErrNoConfig) Error() string {
145-
return e.stderr
146-
}
147-
148-
// ErrCLIUsage is returned when the combination of flags or arguments is incorrect.
149-
//
150-
// CLI indicates usage errors in three different ways: either
151-
// 1. Exit 1, with a custom error message on stderr.
152-
// 2. Exit 1, with command usage logged to stderr.
153-
// 3. Exit 127, with command usage logged to stdout.
154-
// Currently cases 1 and 2 are handled.
155-
// TODO KEM: Handle exit 127 case. How does this work on non-Unix platforms?
156-
type ErrCLIUsage struct {
157-
stderr string
158-
}
159-
160-
func (e *ErrCLIUsage) Error() string {
161-
return e.stderr
162-
}
163-
16427
// ErrManualEnvVar is returned when an env var that should be set programatically via an option or method
16528
// is set via the manual environment passing functions.
16629
type ErrManualEnvVar struct {
@@ -170,28 +33,3 @@ type ErrManualEnvVar struct {
17033
func (err *ErrManualEnvVar) Error() string {
17134
return fmt.Sprintf("manual setting of env var %q detected", err.name)
17235
}
173-
174-
type ErrMissingVar struct {
175-
VariableName string
176-
}
177-
178-
func (err *ErrMissingVar) Error() string {
179-
return fmt.Sprintf("variable %q was required but not supplied", err.VariableName)
180-
}
181-
182-
type ErrNoWorkspace struct {
183-
Name string
184-
}
185-
186-
func (err *ErrNoWorkspace) Error() string {
187-
return fmt.Sprintf("workspace %q does not exist", err.Name)
188-
}
189-
190-
// ErrWorkspaceExists is returned when creating a workspace that already exists
191-
type ErrWorkspaceExists struct {
192-
Name string
193-
}
194-
195-
func (err *ErrWorkspaceExists) Error() string {
196-
return fmt.Sprintf("workspace %q already exists", err.Name)
197-
}

tfexec/exit_errors.go

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package tfexec
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os/exec"
7+
"regexp"
8+
"strings"
9+
)
10+
11+
// this file contains errors parsed from stderr
12+
13+
var (
14+
// The "Required variable not set:" case is for 0.11
15+
missingVarErrRegexp = regexp.MustCompile(`Error: No value for required variable|Error: Required variable not set:`)
16+
missingVarNameRegexp = regexp.MustCompile(`The root module input variable "(.+)" is not set, and has no default|Error: Required variable not set: (.+)`)
17+
18+
usageRegexp = regexp.MustCompile(`Too many command line arguments|^Usage: .*Options:.*|Error: Invalid -\d+ option`)
19+
20+
// "Could not load plugin" is present in 0.13
21+
noInitErrRegexp = regexp.MustCompile(`Error: Could not satisfy plugin requirements|Error: Could not load plugin`)
22+
23+
noConfigErrRegexp = regexp.MustCompile(`Error: No configuration files`)
24+
25+
workspaceDoesNotExistRegexp = regexp.MustCompile(`Workspace "(.+)" doesn't exist.`)
26+
27+
workspaceAlreadyExistsRegexp = regexp.MustCompile(`Workspace "(.+)" already exists`)
28+
29+
tfVersionMismatchErrRegexp = regexp.MustCompile(`Error: The currently running version of Terraform doesn't meet the|Error: Unsupported Terraform Core version`)
30+
tfVersionMismatchConstraintRegexp = regexp.MustCompile(`required_version = "(.+)"|Required version: (.+)\b`)
31+
)
32+
33+
func (tf *Terraform) parseError(err error, stderr string) error {
34+
ee, ok := err.(*exec.ExitError)
35+
if !ok {
36+
return err
37+
}
38+
39+
switch {
40+
case tfVersionMismatchErrRegexp.MatchString(stderr):
41+
constraint := ""
42+
constraints := tfVersionMismatchConstraintRegexp.FindStringSubmatch(stderr)
43+
for i := 1; i < len(constraints); i++ {
44+
constraint = strings.TrimSpace(constraints[i])
45+
if constraint != "" {
46+
break
47+
}
48+
}
49+
50+
if constraint == "" {
51+
// hardcode a value here for weird cases (incl. 0.12)
52+
constraint = "unknown"
53+
}
54+
55+
// only set this if it happened to be cached already
56+
ver := ""
57+
if tf != nil && tf.execVersion != nil {
58+
ver = tf.execVersion.String()
59+
}
60+
61+
return &ErrTFVersionMismatch{
62+
Constraint: constraint,
63+
TFVersion: ver,
64+
}
65+
case missingVarErrRegexp.MatchString(stderr):
66+
name := ""
67+
names := missingVarNameRegexp.FindStringSubmatch(stderr)
68+
for i := 1; i < len(names); i++ {
69+
name = strings.TrimSpace(names[i])
70+
if name != "" {
71+
break
72+
}
73+
}
74+
75+
return &ErrMissingVar{name}
76+
case usageRegexp.MatchString(stderr):
77+
return &ErrCLIUsage{stderr: stderr}
78+
case noInitErrRegexp.MatchString(stderr):
79+
return &ErrNoInit{stderr: stderr}
80+
case noConfigErrRegexp.MatchString(stderr):
81+
return &ErrNoConfig{stderr: stderr}
82+
case workspaceDoesNotExistRegexp.MatchString(stderr):
83+
submatches := workspaceDoesNotExistRegexp.FindStringSubmatch(stderr)
84+
if len(submatches) == 2 {
85+
return &ErrNoWorkspace{submatches[1]}
86+
}
87+
case workspaceAlreadyExistsRegexp.MatchString(stderr):
88+
submatches := workspaceAlreadyExistsRegexp.FindStringSubmatch(stderr)
89+
if len(submatches) == 2 {
90+
return &ErrWorkspaceExists{submatches[1]}
91+
}
92+
}
93+
errString := strings.TrimSpace(stderr)
94+
if errString == "" {
95+
// if stderr is empty, return the ExitError directly, as it will have a better message
96+
return ee
97+
}
98+
return errors.New(stderr)
99+
}
100+
101+
type ErrMissingVar struct {
102+
VariableName string
103+
}
104+
105+
func (err *ErrMissingVar) Error() string {
106+
return fmt.Sprintf("variable %q was required but not supplied", err.VariableName)
107+
}
108+
109+
type ErrNoWorkspace struct {
110+
Name string
111+
}
112+
113+
func (err *ErrNoWorkspace) Error() string {
114+
return fmt.Sprintf("workspace %q does not exist", err.Name)
115+
}
116+
117+
// ErrWorkspaceExists is returned when creating a workspace that already exists
118+
type ErrWorkspaceExists struct {
119+
Name string
120+
}
121+
122+
func (err *ErrWorkspaceExists) Error() string {
123+
return fmt.Sprintf("workspace %q already exists", err.Name)
124+
}
125+
126+
type ErrNoInit struct {
127+
stderr string
128+
}
129+
130+
func (e *ErrNoInit) Error() string {
131+
return e.stderr
132+
}
133+
134+
type ErrNoConfig struct {
135+
stderr string
136+
}
137+
138+
func (e *ErrNoConfig) Error() string {
139+
return e.stderr
140+
}
141+
142+
// ErrCLIUsage is returned when the combination of flags or arguments is incorrect.
143+
//
144+
// CLI indicates usage errors in three different ways: either
145+
// 1. Exit 1, with a custom error message on stderr.
146+
// 2. Exit 1, with command usage logged to stderr.
147+
// 3. Exit 127, with command usage logged to stdout.
148+
// Currently cases 1 and 2 are handled.
149+
// TODO KEM: Handle exit 127 case. How does this work on non-Unix platforms?
150+
type ErrCLIUsage struct {
151+
stderr string
152+
}
153+
154+
func (e *ErrCLIUsage) Error() string {
155+
return e.stderr
156+
}
157+
158+
// ErrTFVersionMismatch is returned when the running Terraform version is not compatible with the
159+
// value specified for required_version in the terraform block.
160+
type ErrTFVersionMismatch struct {
161+
TFVersion string
162+
163+
// Constraint is not returned in the error messaging on 0.12
164+
Constraint string
165+
}
166+
167+
func (e *ErrTFVersionMismatch) Error() string {
168+
return "terraform core version not supported by configuration"
169+
}

0 commit comments

Comments
 (0)