-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cli: Don't print help and don't skip defer
ed funcs on failures
#2942
base: master
Are you sure you want to change the base?
Conversation
85bf87d
to
24ab511
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Conflicts, rebase pls. But looks nice in general. Probably we can add some tests for it as well.
// | ||
// 0 if nil | ||
// 1 if [sdkstatus.ErrServerInternal] or untyped | ||
// 2 if [sdkstatus.ErrObjectAccessDenied] | ||
// 3 if [ErrAwaitTimeout] | ||
func ExitOnErr(cmd *cobra.Command, errFmt string, err error) { | ||
func WrapError(errFmt string, err error) *custom_errors.ExitErr { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd probably do it as WrapError(err error)
and leave fmt.Errorf()
to the caller if and when needed. You still can unwrap internally to get the code, but formatting would be easier, I think. You can have cases like "smth (additional data: %d): %w"
and this won't fit the current interface.
@@ -9,9 +9,11 @@ Changelog for NeoFS Node | |||
- Expose health status of inner ring via Prometheus (#2934) | |||
|
|||
### Fixed | |||
- `defer` func is not skipped in cobra-based programs (#2942) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure it makes sense for outside reader, but don't have immediate suggestions either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cmd/internal/custom_errors/errors.go
Outdated
@@ -0,0 +1,27 @@ | |||
package custom_errors |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not a good choice of pkg name https://go.dev/blog/package-names. I can suggest cmderr
if getConfirmation(false, "Continue configuration? yes/[no]: ") { | ||
return | ||
if flag, err := getConfirmation(false, "Continue configuration? yes/[no]: "); flag { | ||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this never happens for flag==true
, i think the condition should be
if flag, err := getConfirmation(false, "Continue configuration? yes/[no]: "); flag || err != nil {
return err
}
// | ||
// 0 if nil | ||
// 1 if [sdkstatus.ErrServerInternal] or untyped | ||
// 2 if [sdkstatus.ErrObjectAccessDenied] | ||
// 3 if [ErrAwaitTimeout] | ||
func ExitOnErr(cmd *cobra.Command, errFmt string, err error) { | ||
func WrapError(errFmt string, err error) *custom_errors.ExitErr { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should not return pointers to be compliant with ExitOnErr
making
var e ExitErr
if !errors.As(err, &e) {
e.Code = 1
}
easy to check
func TestExit(t *testing.T) {
custom_errors.ExitOnErr(common.WrapError("context; %w", common.ErrAwaitTimeout))
}
expected 3
, got 1
cmd/neofs-cli/internal/client/sdk.go
Outdated
cli, err := getSDKClientByFlag(ctx, endpointFlag) | ||
if err != nil { | ||
common.ExitOnErr(cmd, "can't create API client: %w", err) | ||
return nil, common.WrapError("can't create API client: %w", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i dont think this is a good place to throw ExitErr
, this is the responsibility of RunE
s. So, just return nil, fmt.Errorf(...)
} | ||
|
||
var exitErr *custom_errors.ExitErr | ||
if errors.As(err, &exitErr) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
having this means that code does not care who makes ExitErr
while it should. Imo normally this should never be true. The most stable approach is to wrap by RunE
functions only
_, err := os.Stat(eaclPath) // check if `eaclPath` is an existing file | ||
if err != nil { | ||
ExitOnErr(cmd, "", errors.New("incorrect path to file with EACL")) | ||
return eacl.Table{}, WrapError("", errors.New("incorrect path to file with EACL")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here too enough to return eacl.Table{}, errors.New("incorrect path to file with EACL")
and let caller how to wrap it. With this, u wont need to wrap all function returns
cmd/neofs-lens/internal/meta/get.go
Outdated
var addr oid.Address | ||
|
||
err := addr.DecodeString(vAddress) | ||
common.ExitOnErr(cmd, common.Errf("invalid address argument: %w", err)) | ||
if err != nil { | ||
return common.Errf("invalid address argument: %w", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
common.Errf
made sense with ExitOnErr
func since it allowed to avoid if
statement. Now we should use fmt.Errorf
(and purge Errf
)
24ab511
to
b99e708
Compare
For all cobra-based programs add custom error with code and cause of error and exit func from programs. Signed-off-by: Andrey Butusov <andrey@nspcc.io>
Use `RunE` instead of `Run` and throw an error to main function. Then handle error with custom error handler. Signed-off-by: Andrey Butusov <andrey@nspcc.io>
Use `RunE` instead of `Run` and throw an error to main function. Wrap error with `common.WrapError` to specify the status code. Then handle error with custom error handler. Signed-off-by: Andrey Butusov <andrey@nspcc.io>
Use `RunE` instead of `Run` and throw an error to main function. Then handle error with custom error handler. Update CHANGELOG.md. Closes #2890. Signed-off-by: Andrey Butusov <andrey@nspcc.io>
b99e708
to
23c2dce
Compare
Now, in the |
"os" | ||
) | ||
|
||
type ExitErr struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
an exported type, should be documented according to ancient chronicles
Closes #623, #2890.
In
neofs-cli
I add funccommon.WrapError
that wrap error tocustom_errors.ExitErr
and return it on every error, But I doubt it. Maybe it is necessary to wrap only the first appearance of this error, or vice versa, only the last one.