Bubble errors instead of panicking (#194)

This commit is contained in:
Simon Frei
2021-08-19 10:00:53 +02:00
committed by GitHub
parent f547618963
commit 5a9c9c7864
7 changed files with 90 additions and 85 deletions
+10 -24
View File
@@ -13,22 +13,12 @@ var (
callbackReturnSignature = reflect.TypeOf((*error)(nil)).Elem()
)
// Error reported by Kong.
type Error struct{ msg string }
func (e Error) Error() string { return e.msg }
func fail(format string, args ...interface{}) {
panic(Error{msg: fmt.Sprintf(format, args...)})
}
func failField(parent reflect.Value, field reflect.StructField, format string, args ...interface{}) {
func failField(parent reflect.Value, field reflect.StructField, format string, args ...interface{}) error {
name := parent.Type().Name()
if name == "" {
name = "<anonymous struct>"
}
msg := fmt.Sprintf("%s.%s: %s", name, field.Name, fmt.Sprintf(format, args...))
panic(Error{msg: msg})
return fmt.Errorf("%s.%s: %s", name, field.Name, fmt.Sprintf(format, args...))
}
// Must creates a new Parser or panics if there is an error.
@@ -118,16 +108,22 @@ func New(grammar interface{}, options ...Option) (*Kong, error) {
// Synthesise command nodes.
for _, dcmd := range k.dynamicCommands {
tag := parseTagString(strings.Join(dcmd.tags, " "))
tag, terr := parseTagString(strings.Join(dcmd.tags, " "))
if terr != nil {
return nil, terr
}
tag.Name = dcmd.name
tag.Help = dcmd.help
tag.Group = dcmd.group
tag.Cmd = true
v := reflect.Indirect(reflect.ValueOf(dcmd.cmd))
buildChild(k, k.Model.Node, CommandNode, reflect.Value{}, reflect.StructField{
err = buildChild(k, k.Model.Node, CommandNode, reflect.Value{}, reflect.StructField{
Name: dcmd.name,
Type: v.Type(),
}, v, tag, dcmd.name, map[string]bool{})
if err != nil {
return nil, err
}
}
for _, option := range k.postBuildOptions {
@@ -231,7 +227,6 @@ func (k *Kong) extraFlags() []*Flag {
// Will return a ParseError if a *semantically* invalid command-line is encountered (as opposed to a syntactically
// invalid one, which will report a normal error).
func (k *Kong) Parse(args []string) (ctx *Context, err error) {
defer catch(&err)
ctx, err = Trace(k, args)
if err != nil {
return nil, err
@@ -398,12 +393,3 @@ func (k *Kong) LoadConfig(path string) (Resolver, error) {
return k.loader(r)
}
func catch(err *error) {
msg := recover()
if test, ok := msg.(Error); ok {
*err = test
} else if msg != nil {
panic(msg)
}
}