-
Notifications
You must be signed in to change notification settings - Fork 2
/
execute.go
114 lines (100 loc) · 3.17 KB
/
execute.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package cmdutil
import (
"context"
"crypto/x509"
"errors"
"fmt"
"net/http"
"strings"
"github.com/appgate/sdpctl/pkg/api"
"github.com/hashicorp/go-multierror"
"github.com/spf13/cobra"
)
type ExitCode int
var ErrExitAuth = errors.New("no authentication")
const (
ExitOK ExitCode = 0
ExitError ExitCode = 1
ExitCancel ExitCode = 2
ExitAuth ExitCode = 4
)
func privligeError(err *api.Error) error {
if err.StatusCode == http.StatusForbidden {
var result *multierror.Error
result = multierror.Append(result, fmt.Errorf("Run '%s privileges' to see your current user privileges", GetCaller()))
if err.RequestURL != nil {
result = multierror.Append(result, errors.New(*err.RequestURL))
}
return result
}
return nil
}
func ExecuteCommand(cmd *cobra.Command) ExitCode {
cmd, err := cmd.ExecuteC()
if err != nil {
var result *multierror.Error
if we := errors.Unwrap(err); we != nil {
// if the command return a api error, (api.HTTPErrorResponse) for example HTTP 400-599, we will
// resolve each nested error and convert them to multierror to prettify it for the user in a list view.
if ae, ok := we.(*api.Error); ok {
result = multierror.Append(result, privligeError(ae))
for _, e := range ae.Errors {
result = multierror.Append(result, e)
}
}
// Unwrap error and check if we have a nested multierr
// if we do, we will make the errors flat for 1 level
// otherwise, append error to new multierr list
if merr, ok := we.(*multierror.Error); ok {
for _, e := range merr.Errors {
result = multierror.Append(result, e)
}
} else {
result = multierror.Append(result, err)
}
} else {
if ae, ok := err.(*api.Error); ok {
result = multierror.Append(result, privligeError(ae))
for _, e := range ae.Errors {
result = multierror.Append(result, e)
}
} else {
result = multierror.Append(result, err)
}
}
// if error is DeadlineExceeded, add custom ErrCommandTimeout
if errors.Is(err, context.DeadlineExceeded) {
result = multierror.Append(result, ErrCommandTimeout)
}
// if error is ErrNothingToUpgrade, exit with zero code
if errors.Is(err, ErrNothingToPrepare) {
fmt.Fprintln(cmd.ErrOrStderr(), err.Error())
return ExitOK
}
// if we during any request get a SSL error, (un-trusted certificate) error, prompt the user to import the pem file.
var sslErr x509.UnknownAuthorityError
if errors.As(err, &sslErr) {
result = multierror.Append(result, ErrSSL)
}
// print all multierrors to stderr, then return correct exitcode based on error type
if result.ErrorOrNil() == nil {
result = multierror.Append(result, err)
}
fmt.Fprintln(cmd.ErrOrStderr(), result.ErrorOrNil())
if errors.Is(err, ErrExitAuth) {
return ExitAuth
}
if errors.Is(err, ErrExecutionCanceledByUser) {
return ExitCancel
}
// only show usage prompt if we get invalid args / flags
errorString := err.Error()
if strings.Contains(errorString, "arg(s)") || strings.Contains(errorString, "flag") || strings.Contains(errorString, "command") {
fmt.Fprintln(cmd.ErrOrStderr())
fmt.Fprintln(cmd.ErrOrStderr(), cmd.UsageString())
return ExitError
}
return ExitError
}
return ExitOK
}