-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
exit.go
60 lines (52 loc) · 1.36 KB
/
exit.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
package clino
import (
"errors"
"fmt"
"os/exec"
"syscall"
)
// ExitError wraps the error, adding an exit code.
//
// You can use it to exit the process gracefully with a specific exit code when something goes wrong.
// You should only wrap error when err != nil. You don't need to wrap it if the exit code is *exec.ExitError.
type ExitError struct {
Code int
Err error
}
// Error returns the original (wrapped) error message.
func (ee ExitError) Error() string {
return fmt.Sprintf("%v", ee.Err)
}
// Unwrap error.
func (ee ExitError) Unwrap() error { return ee.Err }
// ExitCode from the command for the process to use when exiting.
// It returns 0 if the error is nil.
// If the error comes from *exec.Cmd Run, the same child process exit code
// is used. If the error is ExitError, it returns the Code field.
// Otherwise, return exit code 1.
// func main() {
// p := clino.Program{
// Root: &RootCommand{},
// }
// if err := p.Run(context.Background(), os.Args[1:]...); err != nil {
// fmt.Fprintf(os.Stderr, "%+v\n", err)
// os.Exit(clino.ExitCode(err))
// }
// }
//
func ExitCode(err error) int {
if err == nil {
return 0
}
var ee ExitError
if errors.As(err, &ee) {
return ee.Code
}
var xe *exec.ExitError
if errors.As(err, &xe) {
if ws, ok := xe.Sys().(syscall.WaitStatus); ok && ws.Exited() {
return ws.ExitStatus()
}
}
return 1
}