system/output: implement MessageError
All checks were successful
Test / Hakurei (push) Successful in 43s
Test / Create distribution (push) Successful in 26s
Test / Sandbox (push) Successful in 1m40s
Test / Hpkg (push) Successful in 3m35s
Test / Sandbox (race detector) (push) Successful in 4m24s
Test / Hakurei (race detector) (push) Successful in 5m20s
Test / Flake checks (push) Successful in 1m37s
All checks were successful
Test / Hakurei (push) Successful in 43s
Test / Create distribution (push) Successful in 26s
Test / Sandbox (push) Successful in 1m40s
Test / Hpkg (push) Successful in 3m35s
Test / Sandbox (race detector) (push) Successful in 4m24s
Test / Hakurei (race detector) (push) Successful in 5m20s
Test / Flake checks (push) Successful in 1m37s
This error is also formatted differently based on state. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
780e3e5465
commit
b489a3bba1
@ -22,14 +22,14 @@ func SetOutput(v container.Msg) {
|
|||||||
type OpError struct {
|
type OpError struct {
|
||||||
Op string
|
Op string
|
||||||
Err error
|
Err error
|
||||||
Message string
|
Msg string
|
||||||
Revert bool
|
Revert bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *OpError) Unwrap() error { return e.Err }
|
func (e *OpError) Unwrap() error { return e.Err }
|
||||||
func (e *OpError) Error() string {
|
func (e *OpError) Error() string {
|
||||||
if e.Message != "" {
|
if e.Msg != "" {
|
||||||
return e.Message
|
return e.Msg
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
@ -47,6 +47,16 @@ func (e *OpError) Error() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *OpError) Message() string {
|
||||||
|
switch {
|
||||||
|
case e.Msg != "":
|
||||||
|
return e.Error()
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "cannot " + e.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// newOpError returns an [OpError] without a message string.
|
// newOpError returns an [OpError] without a message string.
|
||||||
func newOpError(op string, err error, revert bool) error {
|
func newOpError(op string, err error, revert bool) error {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -69,10 +79,18 @@ func printJoinedError(println func(v ...any), fallback string, err error) {
|
|||||||
error
|
error
|
||||||
}
|
}
|
||||||
if !errors.As(err, &joinErr) {
|
if !errors.As(err, &joinErr) {
|
||||||
|
if m, ok := container.GetErrorMessage(err); ok {
|
||||||
|
println(m)
|
||||||
|
} else {
|
||||||
println(fallback, err)
|
println(fallback, err)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, err = range joinErr.Unwrap() {
|
for _, err = range joinErr.Unwrap() {
|
||||||
|
if m, ok := container.GetErrorMessage(err); ok {
|
||||||
|
println(m)
|
||||||
|
} else {
|
||||||
println(err.Error())
|
println(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -19,27 +19,33 @@ func TestOpError(t *testing.T) {
|
|||||||
s string
|
s string
|
||||||
is error
|
is error
|
||||||
isF error
|
isF error
|
||||||
|
msg string
|
||||||
}{
|
}{
|
||||||
{"message", newOpErrorMessage("dbus", ErrDBusConfig,
|
{"message", newOpErrorMessage("dbus", ErrDBusConfig,
|
||||||
"attempted to create message bus proxy args without session bus config", false),
|
"attempted to create message bus proxy args without session bus config", false),
|
||||||
"attempted to create message bus proxy args without session bus config",
|
"attempted to create message bus proxy args without session bus config",
|
||||||
ErrDBusConfig, syscall.ENOTRECOVERABLE},
|
ErrDBusConfig, syscall.ENOTRECOVERABLE,
|
||||||
|
"attempted to create message bus proxy args without session bus config"},
|
||||||
|
|
||||||
{"apply", newOpError("tmpfile", syscall.EBADE, false),
|
{"apply", newOpError("tmpfile", syscall.EBADE, false),
|
||||||
"apply tmpfile: invalid exchange",
|
"apply tmpfile: invalid exchange",
|
||||||
syscall.EBADE, syscall.EBADF},
|
syscall.EBADE, syscall.EBADF,
|
||||||
|
"cannot apply tmpfile: invalid exchange"},
|
||||||
|
|
||||||
{"revert", newOpError("wayland", syscall.EBADF, true),
|
{"revert", newOpError("wayland", syscall.EBADF, true),
|
||||||
"revert wayland: bad file descriptor",
|
"revert wayland: bad file descriptor",
|
||||||
syscall.EBADF, syscall.EBADE},
|
syscall.EBADF, syscall.EBADE,
|
||||||
|
"cannot revert wayland: bad file descriptor"},
|
||||||
|
|
||||||
{"path", newOpError("tmpfile", &os.PathError{Op: "stat", Path: "/run/dbus", Err: syscall.EISDIR}, false),
|
{"path", newOpError("tmpfile", &os.PathError{Op: "stat", Path: "/run/dbus", Err: syscall.EISDIR}, false),
|
||||||
"stat /run/dbus: is a directory",
|
"stat /run/dbus: is a directory",
|
||||||
syscall.EISDIR, syscall.ENOTDIR},
|
syscall.EISDIR, syscall.ENOTDIR,
|
||||||
|
"cannot stat /run/dbus: is a directory"},
|
||||||
|
|
||||||
{"net", newOpError("wayland", &net.OpError{Op: "dial", Net: "unix", Addr: &net.UnixAddr{Name: "/run/user/1000/wayland-1", Net: "unix"}, Err: syscall.ENOENT}, false),
|
{"net", newOpError("wayland", &net.OpError{Op: "dial", Net: "unix", Addr: &net.UnixAddr{Name: "/run/user/1000/wayland-1", Net: "unix"}, Err: syscall.ENOENT}, false),
|
||||||
"dial unix /run/user/1000/wayland-1: no such file or directory",
|
"dial unix /run/user/1000/wayland-1: no such file or directory",
|
||||||
syscall.ENOENT, syscall.EPERM},
|
syscall.ENOENT, syscall.EPERM,
|
||||||
|
"cannot dial unix /run/user/1000/wayland-1: no such file or directory"},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
@ -48,6 +54,7 @@ func TestOpError(t *testing.T) {
|
|||||||
t.Errorf("Error: %q, want %q", got, tc.s)
|
t.Errorf("Error: %q, want %q", got, tc.s)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("is", func(t *testing.T) {
|
t.Run("is", func(t *testing.T) {
|
||||||
if !errors.Is(tc.err, tc.is) {
|
if !errors.Is(tc.err, tc.is) {
|
||||||
t.Error("Is: unexpected false")
|
t.Error("Is: unexpected false")
|
||||||
@ -56,6 +63,17 @@ func TestOpError(t *testing.T) {
|
|||||||
t.Error("Is: unexpected true")
|
t.Error("Is: unexpected true")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("msg", func(t *testing.T) {
|
||||||
|
if got, ok := container.GetErrorMessage(tc.err); !ok {
|
||||||
|
if tc.msg != "" {
|
||||||
|
t.Errorf("GetErrorMessage: err does not implement MessageError")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else if got != tc.msg {
|
||||||
|
t.Errorf("GetErrorMessage: %q, want %q", got, tc.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,14 +121,40 @@ func TestPrintJoinedError(t *testing.T) {
|
|||||||
want [][]any
|
want [][]any
|
||||||
}{
|
}{
|
||||||
{"nil", nil, [][]any{{"not a joined error:", nil}}},
|
{"nil", nil, [][]any{{"not a joined error:", nil}}},
|
||||||
{"unwrapped", syscall.EINVAL, [][]any{{"not a joined error:", syscall.EINVAL}}},
|
|
||||||
{"single", errors.Join(syscall.EINVAL), [][]any{{"invalid argument"}}},
|
{"single", errors.Join(syscall.EINVAL), [][]any{{"invalid argument"}}},
|
||||||
|
|
||||||
|
{"unwrapped", syscall.EINVAL, [][]any{{"not a joined error:", syscall.EINVAL}}},
|
||||||
|
{"unwrapped message", &OpError{
|
||||||
|
Op: "meow",
|
||||||
|
Err: syscall.EBADFD,
|
||||||
|
}, [][]any{
|
||||||
|
{"cannot apply meow: file descriptor in bad state"},
|
||||||
|
}},
|
||||||
|
|
||||||
{"many", errors.Join(syscall.ENOTRECOVERABLE, syscall.ETIMEDOUT, syscall.EBADFD), [][]any{
|
{"many", errors.Join(syscall.ENOTRECOVERABLE, syscall.ETIMEDOUT, syscall.EBADFD), [][]any{
|
||||||
{"state not recoverable"},
|
{"state not recoverable"},
|
||||||
{"connection timed out"},
|
{"connection timed out"},
|
||||||
{"file descriptor in bad state"},
|
{"file descriptor in bad state"},
|
||||||
}},
|
}},
|
||||||
|
{"many message", errors.Join(
|
||||||
|
&container.StartError{
|
||||||
|
Step: "meow",
|
||||||
|
Err: syscall.ENOMEM,
|
||||||
|
},
|
||||||
|
&os.PathError{
|
||||||
|
Op: "meow",
|
||||||
|
Path: "/proc/nonexistent",
|
||||||
|
Err: syscall.ENOSYS,
|
||||||
|
},
|
||||||
|
&OpError{
|
||||||
|
Op: "meow",
|
||||||
|
Err: syscall.ENODEV,
|
||||||
|
Revert: true,
|
||||||
|
}), [][]any{
|
||||||
|
{"cannot meow: cannot allocate memory"},
|
||||||
|
{"meow /proc/nonexistent: function not implemented"},
|
||||||
|
{"cannot revert meow: no such device"},
|
||||||
|
}},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user