mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-14 18:24:14 +01:00
78 lines
2.5 KiB
Text
78 lines
2.5 KiB
Text
|
Package warnings implements error handling with non-fatal errors (warnings).
|
||
|
|
||
|
import path: "gopkg.in/warnings.v0"
|
||
|
package docs: https://godoc.org/gopkg.in/warnings.v0
|
||
|
issues: https://github.com/go-warnings/warnings/issues
|
||
|
pull requests: https://github.com/go-warnings/warnings/pulls
|
||
|
|
||
|
A recurring pattern in Go programming is the following:
|
||
|
|
||
|
func myfunc(params) error {
|
||
|
if err := doSomething(...); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if err := doSomethingElse(...); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if ok := doAnotherThing(...); !ok {
|
||
|
return errors.New("my error")
|
||
|
}
|
||
|
...
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
This pattern allows interrupting the flow on any received error. But what if
|
||
|
there are errors that should be noted but still not fatal, for which the flow
|
||
|
should not be interrupted? Implementing such logic at each if statement would
|
||
|
make the code complex and the flow much harder to follow.
|
||
|
|
||
|
Package warnings provides the Collector type and a clean and simple pattern
|
||
|
for achieving such logic. The Collector takes care of deciding when to break
|
||
|
the flow and when to continue, collecting any non-fatal errors (warnings)
|
||
|
along the way. The only requirement is that fatal and non-fatal errors can be
|
||
|
distinguished programmatically; that is a function such as
|
||
|
|
||
|
IsFatal(error) bool
|
||
|
|
||
|
must be implemented. The following is an example of what the above snippet
|
||
|
could look like using the warnings package:
|
||
|
|
||
|
import "gopkg.in/warnings.v0"
|
||
|
|
||
|
func isFatal(err error) bool {
|
||
|
_, ok := err.(WarningType)
|
||
|
return !ok
|
||
|
}
|
||
|
|
||
|
func myfunc(params) error {
|
||
|
c := warnings.NewCollector(isFatal)
|
||
|
c.FatalWithWarnings = true
|
||
|
if err := c.Collect(doSomething()); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if err := c.Collect(doSomethingElse(...)); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if ok := doAnotherThing(...); !ok {
|
||
|
if err := c.Collect(errors.New("my error")); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
...
|
||
|
return c.Done()
|
||
|
}
|
||
|
|
||
|
For an example of a non-trivial code base using this library, see
|
||
|
gopkg.in/gcfg.v1
|
||
|
|
||
|
Rules for using warnings
|
||
|
|
||
|
- ensure that warnings are programmatically distinguishable from fatal
|
||
|
errors (i.e. implement an isFatal function and any necessary error types)
|
||
|
- ensure that there is a single Collector instance for a call of each
|
||
|
exported function
|
||
|
- ensure that all errors (fatal or warning) are fed through Collect
|
||
|
- ensure that every time an error is returned, it is one returned by a
|
||
|
Collector (from Collect or Done)
|
||
|
- ensure that Collect is never called after Done
|