Skip to content

Commit 142116e

Browse files
authored
feat: Add the ability to wrap and unwrap errors with exit codes (#21)
1 parent a7718c8 commit 142116e

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

exit.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ of some sort. Exit Codes 100-119 indicate software or system error of some sort.
77
*/
88
package exit
99

10+
import (
11+
"errors"
12+
"fmt"
13+
)
14+
1015
// Code is the exit code that is passed to the system call `exit`
1116
// when the program terminates. Conventionally, the value zero indicates
1217
// success and all other values (1-255) indicate failure.
@@ -95,3 +100,46 @@ func IsSignal(code Code) bool {
95100
// https://pkg.go.dev/os#ProcessState.ExitCode
96101
return code == -1 || code > 128 && code < 255
97102
}
103+
104+
var (
105+
ErrNotOK = Error{Code: NotOK}
106+
ErrUsageError = Error{Code: UsageError}
107+
ErrUnknownSubcommand = Error{Code: UnknownSubcommand}
108+
ErrRequirementNotMet = Error{Code: RequirementNotMet}
109+
ErrForbidden = Error{Code: Forbidden}
110+
ErrMovedPermanently = Error{Code: MovedPermanently}
111+
ErrInternalError = Error{Code: InternalError}
112+
ErrUnavailable = Error{Code: Unavailable}
113+
)
114+
115+
func FromError(err error) Code {
116+
var e Error
117+
if errors.As(err, &e) {
118+
return e.Code
119+
} else if err == nil {
120+
return OK
121+
} else {
122+
return NotOK
123+
}
124+
}
125+
126+
func Wrap(err error, code Code) error {
127+
return Error{Code: code, Cause: err}
128+
}
129+
130+
type Error struct {
131+
Code Code
132+
Cause error
133+
}
134+
135+
func (e Error) Error() string {
136+
if e.Cause != nil {
137+
return fmt.Sprintf("exit %d: %s", e.Code, e.Cause)
138+
} else {
139+
return fmt.Sprintf("exit %d", e.Code)
140+
}
141+
}
142+
143+
func (e Error) Unwrap() error {
144+
return e.Cause
145+
}

readme_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package exit
33
import (
44
_ "embed"
55
"go/ast"
6+
"go/importer"
67
"go/parser"
78
"go/token"
89
"go/types"
@@ -17,11 +18,8 @@ var readme string
1718
var src string
1819

1920
func TestExitCodesMatchReadme(t *testing.T) {
20-
var (
21-
f *ast.File
22-
conf types.Config
23-
err error
24-
)
21+
var f *ast.File
22+
var err error
2523

2624
re := regexp.MustCompile("\\| (\\d+) \\| `(\\w+)` \\| .* \\|\n")
2725
expectedConstants := make(map[string]string)
@@ -38,6 +36,7 @@ func TestExitCodesMatchReadme(t *testing.T) {
3836
// We create an empty map for each kind of input
3937
// we're interested in, and Check populates them.
4038
info := types.Info{Defs: make(map[*ast.Ident]types.Object)}
39+
conf := types.Config{Importer: importer.Default()}
4140
if _, err = conf.Check("", fset, []*ast.File{f}, &info); err != nil {
4241
t.Error(err)
4342
}

0 commit comments

Comments
 (0)