Skip to content

Commit 04757df

Browse files
committed
Eliminate errs.Matches().
Use the more-explicit and less-error-prone `errors.As()` instead.
1 parent 7ece78b commit 04757df

File tree

31 files changed

+117
-162
lines changed

31 files changed

+117
-162
lines changed

Diff for: cmd/state-svc/internal/rtwatcher/watcher.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package rtwatcher
22

33
import (
44
"encoding/json"
5+
"errors"
56
"os"
67
"runtime/debug"
78
"strconv"
@@ -81,7 +82,8 @@ func (w *Watcher) check() {
8182
for i := range w.watching {
8283
e := w.watching[i] // Must use index, because we are deleting indexes further down
8384
running, err := e.IsRunning()
84-
if err != nil && !errs.Matches(err, &processError{}) {
85+
var errProcess *processError
86+
if err != nil && !errors.As(err, &errProcess) {
8587
multilog.Error("Could not check if runtime process is running: %s", errs.JoinMessage(err))
8688
// Don't return yet, the conditional below still needs to clear this entry
8789
}
@@ -110,7 +112,8 @@ func (w *Watcher) GetProcessesInUse(execDir string) []entry {
110112
continue
111113
}
112114
isRunning, err := proc.IsRunning()
113-
if err != nil && !errs.Matches(err, &processError{}) {
115+
var errProcess *processError
116+
if err != nil && !errors.As(err, &errProcess) {
114117
multilog.Error("Could not check if runtime process is running: %s", errs.JoinMessage(err))
115118
// Any errors should not affect fetching which processes are currently in use. We just won't
116119
// include this one in the list.

Diff for: cmd/state/autoupdate.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"os"
78
"strings"
@@ -73,7 +74,8 @@ func autoUpdate(svc *model.SvcModel, args []string, childCmd *captain.Command, c
7374

7475
err = up.InstallBlocking("")
7576
if err != nil {
76-
if errs.Matches(err, &updater.ErrorInProgress{}) {
77+
var errInProgress *updater.ErrorInProgress
78+
if errors.As(err, &errInProgress) {
7779
return false, nil // ignore
7880
}
7981
if os.IsPermission(err) {
@@ -87,10 +89,14 @@ func autoUpdate(svc *model.SvcModel, args []string, childCmd *captain.Command, c
8789

8890
code, err := relaunch(args)
8991
if err != nil {
92+
var errStateExe *ErrStateExe
93+
var errExecuteRelaunch *ErrExecuteRelaunch
94+
9095
var msg string
91-
if errs.Matches(err, &ErrStateExe{}) {
96+
switch {
97+
case errors.As(err, &errStateExe):
9298
msg = anaConst.UpdateErrorExecutable
93-
} else if errs.Matches(err, &ErrExecuteRelaunch{}) {
99+
case errors.As(err, &errExecuteRelaunch):
94100
msg = anaConst.UpdateErrorRelaunch
95101
}
96102
an.EventWithLabel(anaConst.CatUpdates, anaConst.ActUpdateRelaunch, anaConst.UpdateLabelFailed, &dimensions.Values{

Diff for: cmd/state/main.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"os"
78
"runtime/debug"
@@ -32,7 +33,7 @@ import (
3233
_ "github.com/ActiveState/cli/internal/prompt" // Sets up survey defaults
3334
"github.com/ActiveState/cli/internal/rollbar"
3435
"github.com/ActiveState/cli/internal/rtutils"
35-
"github.com/ActiveState/cli/internal/runbits/errors"
36+
runbits_errors "github.com/ActiveState/cli/internal/runbits/errors"
3637
"github.com/ActiveState/cli/internal/runbits/panics"
3738
"github.com/ActiveState/cli/internal/subshell"
3839
"github.com/ActiveState/cli/internal/svcctl"
@@ -107,7 +108,7 @@ func main() {
107108
// Run our main command logic, which is logic that defers to the error handling logic below
108109
err = run(os.Args, isInteractive, cfg, out)
109110
if err != nil {
110-
exitCode, err = errors.ParseUserFacing(err)
111+
exitCode, err = runbits_errors.ParseUserFacing(err)
111112
if err != nil {
112113
out.Error(err)
113114
}
@@ -185,7 +186,8 @@ func run(args []string, isInteractive bool, cfg *config.Instance, out output.Out
185186
out.Notice(locale.T("warning_activestate_project_env_var"))
186187
}
187188
pjPath, err := projectfile.GetProjectFilePath()
188-
if err != nil && errs.Matches(err, &projectfile.ErrorNoProjectFromEnv{}) {
189+
var errNoProjectFromEnv *projectfile.ErrorNoProjectFromEnv
190+
if err != nil && errors.As(err, &errNoProjectFromEnv) {
189191
// Fail if we are meant to inherit the projectfile from the environment, but the file doesn't exist
190192
return err
191193
}
@@ -271,7 +273,7 @@ func run(args []string, isInteractive bool, cfg *config.Instance, out output.Out
271273
if !out.Type().IsStructured() {
272274
err = errs.AddTips(err, locale.Tl("err_tip_run_help", "Run → '[ACTIONABLE]state {{.V0}}--help[/RESET]' for general help", cmdName))
273275
}
274-
errors.ReportError(err, cmds.Command(), an)
276+
runbits_errors.ReportError(err, cmds.Command(), an)
275277
}
276278

277279
return err

Diff for: internal/errs/errs.go

-34
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"reflect"
77
"strings"
88

9-
"github.com/ActiveState/cli/internal/condition"
109
"github.com/ActiveState/cli/internal/osutils/stacktrace"
1110
"github.com/ActiveState/cli/internal/rtutils"
1211
"gopkg.in/yaml.v3"
@@ -194,39 +193,6 @@ func AddTips(err error, tips ...string) error {
194193

195194
var errorType = reflect.TypeOf((*error)(nil)).Elem()
196195

197-
// Matches is an analog for errors.As that just checks whether err matches the given type, so you can do:
198-
// errs.Matches(err, &ErrStruct{})
199-
// Without having to first assign it to a variable
200-
// This is useful if you ONLY care about the bool return value and not about setting the variable
201-
func Matches(err error, target interface{}) bool {
202-
if target == nil {
203-
panic("errors: target cannot be nil")
204-
}
205-
206-
// Guard against miss-use of this function
207-
if _, ok := target.(*WrapperError); ok {
208-
if condition.BuiltOnDevMachine() || condition.InActiveStateCI() {
209-
panic("target cannot be a WrapperError, you probably want errors.Is")
210-
}
211-
}
212-
213-
val := reflect.ValueOf(target)
214-
targetType := val.Type()
215-
if targetType.Kind() != reflect.Interface && !targetType.Implements(errorType) {
216-
panic("errors: *target must be interface or implement error")
217-
}
218-
errs := Unpack(err)
219-
for _, err := range errs {
220-
if reflect.TypeOf(err).AssignableTo(targetType) {
221-
return true
222-
}
223-
if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(&target) {
224-
return true
225-
}
226-
}
227-
return false
228-
}
229-
230196
func IsAny(err error, errs ...error) bool {
231197
for _, e := range errs {
232198
if errors.Is(err, e) {

Diff for: internal/errs/errs_test.go

-78
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package errs_test
22

33
import (
44
"errors"
5-
"os"
6-
"os/exec"
75
"path/filepath"
86
"reflect"
97
"strings"
@@ -63,82 +61,6 @@ func TestErrs(t *testing.T) {
6361

6462
type standardError struct{ error }
6563

66-
func TestMatches(t *testing.T) {
67-
type args struct {
68-
err error
69-
target interface{}
70-
}
71-
tests := []struct {
72-
name string
73-
args args
74-
want bool
75-
}{
76-
{
77-
"Simple match",
78-
args{
79-
&standardError{errors.New("error")},
80-
&standardError{},
81-
},
82-
true,
83-
},
84-
{
85-
"Simple miss-match",
86-
args{
87-
errors.New("error"),
88-
&standardError{},
89-
},
90-
false,
91-
},
92-
{
93-
"Wrapped match",
94-
args{
95-
errs.Wrap(&standardError{errors.New("error")}, "Wrapped"),
96-
&standardError{},
97-
},
98-
true,
99-
},
100-
{
101-
"exec.ExitError", // this one has proved troublesome
102-
args{
103-
&exec.ExitError{&os.ProcessState{}, []byte("")},
104-
&exec.ExitError{},
105-
},
106-
true,
107-
},
108-
{
109-
"wrapped exec.ExitError",
110-
args{
111-
errs.Wrap(&exec.ExitError{&os.ProcessState{}, []byte("")}, "wrapped"),
112-
&exec.ExitError{},
113-
},
114-
true,
115-
},
116-
{
117-
"combined errors 1",
118-
args{
119-
errs.Pack(&exec.ExitError{&os.ProcessState{}, []byte("")}, errs.New("Random")),
120-
&exec.ExitError{},
121-
},
122-
true,
123-
},
124-
{
125-
"combined errors 2 - inverted",
126-
args{
127-
errs.Pack(errs.New("Random"), &exec.ExitError{&os.ProcessState{}, []byte("")}),
128-
&exec.ExitError{},
129-
},
130-
true,
131-
},
132-
}
133-
for _, tt := range tests {
134-
t.Run(tt.name, func(t *testing.T) {
135-
if got := errs.Matches(tt.args.err, tt.args.target); got != tt.want {
136-
t.Errorf("Matches() = %v, want %v", got, tt.want)
137-
}
138-
})
139-
}
140-
}
141-
14264
func TestAddTips(t *testing.T) {
14365
type args struct {
14466
err error

Diff for: internal/errs/example_test.go

-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ func TestExample(t *testing.T) {
1919
errt := &MyError{}
2020
var errx error = &MyError{errs.New("test1")}
2121
errors.As(errx, &errt)
22-
errs.Matches(errx, &MyError{})
2322

2423
// Regular error
2524
var err error = errs.New("Regular error message on %s", runtime.GOOS)
@@ -38,8 +37,6 @@ func TestExample(t *testing.T) {
3837
err = errs.Wrap(myError, "My WrappedErr!")
3938
assert.Error(t, err)
4039
assert.True(t, errors.As(err, &myErrorCopy), "Error can be accessed as myErrorCopy")
41-
assert.True(t, errs.Matches(err, &MyError{}), "Error Matches")
42-
assert.False(t, errs.Matches(errs.New("foo"), &MyError{}), "Error doesn't match")
4340
assert.True(t, errors.Is(err, myError), "err is equivalent to myError") // ptrs same addr, non-ptrs struct equality
4441

4542
// Create user input error

Diff for: internal/installation/paths.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package installation
22

33
import (
4+
"errors"
45
"os"
56
"path/filepath"
67
"strings"
@@ -22,14 +23,15 @@ const (
2223
)
2324

2425
type InstallMarkerMeta struct {
25-
Channel string `json:"channel"`
26+
Channel string `json:"channel"`
2627
Version string `json:"version"`
2728
}
2829

2930
type StateExeDoesNotExistError struct{ *errs.WrapperError }
3031

3132
func IsStateExeDoesNotExistError(err error) bool {
32-
return errs.Matches(err, &StateExeDoesNotExistError{})
33+
var errStateExeDoesNotExist *StateExeDoesNotExistError
34+
return errors.As(err, &errStateExeDoesNotExist)
3335
}
3436

3537
func DefaultInstallPath() (string, error) {

Diff for: internal/osutils/lockfile/pidlock.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package lockfile
22

33
import (
4+
"errors"
45
"fmt"
56
"io"
67
"os"
@@ -105,7 +106,8 @@ func (pl *PidLock) WaitForLock(timeout time.Duration) error {
105106
for {
106107
err := pl.TryLock()
107108
if err != nil {
108-
if !errs.Matches(err, &AlreadyLockedError{}) {
109+
var errAlreadyLocked *AlreadyLockedError
110+
if !errors.As(err, &errAlreadyLocked) {
109111
return errs.Wrap(err, "Could not acquire lock")
110112
}
111113

Diff for: internal/runbits/auth/keypair.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package auth
22

33
import (
4+
"errors"
5+
46
"github.com/ActiveState/cli/internal/constants"
57
"github.com/ActiveState/cli/internal/errs"
68
"github.com/ActiveState/cli/internal/keypairs"
@@ -16,9 +18,10 @@ import (
1618
// and saved.
1719
func ensureUserKeypair(passphrase string, cfg keypairs.Configurable, out output.Outputer, prompt prompt.Prompter, auth *authentication.Auth) error {
1820
keypairRes, err := keypairs.FetchRaw(secretsapi.Get(auth), cfg, auth)
21+
var errKeypairNotFound *keypairs.ErrKeypairNotFound
1922
if err == nil {
2023
err = processExistingKeypairForUser(keypairRes, passphrase, cfg, out, prompt, auth)
21-
} else if errs.Matches(err, &keypairs.ErrKeypairNotFound{}) {
24+
} else if errors.As(err, &errKeypairNotFound) {
2225
err = generateKeypairForUser(cfg, passphrase, auth)
2326
}
2427

@@ -52,10 +55,11 @@ func generateKeypairForUser(cfg keypairs.Configurable, passphrase string, auth *
5255
// provided passphrase and then uploaded; unless the user declines, which results in err.
5356
func processExistingKeypairForUser(keypairRes *secretsModels.Keypair, passphrase string, cfg keypairs.Configurable, out output.Outputer, prompt prompt.Prompter, auth *authentication.Auth) error {
5457
keypair, err := keypairs.ParseEncryptedRSA(*keypairRes.EncryptedPrivateKey, passphrase)
58+
var errKeypairPassphrase *keypairs.ErrKeypairPassphrase
5559
if err == nil {
5660
// yay, store keypair locally just in case it isn't
5761
return keypairs.SaveWithDefaults(cfg, keypair)
58-
} else if !errs.Matches(err, &keypairs.ErrKeypairPassphrase{}) {
62+
} else if !errors.As(err, &errKeypairPassphrase) {
5963
// err did not involve an unmatched passphrase
6064
return err
6165
}
@@ -74,7 +78,7 @@ func processExistingKeypairForUser(keypairRes *secretsModels.Keypair, passphrase
7478

7579
// failed to validate with local private-key, try using previous passphrase
7680
err = recoverKeypairFromPreviousPassphrase(keypairRes, passphrase, cfg, out, prompt, auth)
77-
if err != nil && errs.Matches(err, &keypairs.ErrKeypairPassphrase{}) {
81+
if err != nil && errors.As(err, &errKeypairPassphrase) {
7882
// that failed, see if they want to regenerate their passphrase
7983
err = promptUserToRegenerateKeypair(passphrase, cfg, out, prompt, auth)
8084
}

Diff for: internal/runbits/auth/login.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package auth
22

33
import (
4+
"errors"
45
"net/url"
56
"time"
67

@@ -49,12 +50,15 @@ func AuthenticateWithInput(
4950

5051
err := AuthenticateWithCredentials(credentials, auth)
5152
if err != nil {
53+
var errTokenRequired *authentication.ErrTokenRequired
54+
var errUnauthorized *authentication.ErrUnauthorized
55+
5256
switch {
53-
case errs.Matches(err, &authentication.ErrTokenRequired{}):
57+
case errors.As(err, &errTokenRequired):
5458
if err := promptToken(credentials, out, prompt, auth); err != nil {
5559
return errs.Wrap(err, "promptToken failed")
5660
}
57-
case errs.Matches(err, &authentication.ErrUnauthorized{}):
61+
case errors.As(err, &errUnauthorized):
5862
return locale.WrapError(err, "err_auth_failed")
5963
default:
6064
return locale.WrapError(err, "err_auth_failed_unknown_cause", "", err.Error())

Diff for: internal/runbits/findproject/project.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package findproject
22

33
import (
4+
"errors"
45
"sort"
56
"strings"
67

@@ -18,7 +19,8 @@ type LocalProjectDoesNotExist struct{ *locale.LocalizedError }
1819

1920
// IsLocalProjectDoesNotExistError checks if the error is a LocalProjectDoesNotExist.
2021
func IsLocalProjectDoesNotExistError(err error) bool {
21-
return errs.Matches(err, &LocalProjectDoesNotExist{})
22+
var errLocalProjectDoesNotExist *LocalProjectDoesNotExist
23+
return errors.As(err, &errLocalProjectDoesNotExist)
2224
}
2325

2426
func FromInputByPriority(path string, ns *project.Namespaced, cfg projectfile.ConfigGetter, prompt prompt.Prompter) (*project.Project, error) {

0 commit comments

Comments
 (0)