Switch to the standard errors API, that was introduced in 1.13 (#273)

* Switch to the standard errors API, that was introduced in 1.13

* Fix linter errors 🤦‍

* Remove withStackError

* fix: freeze go version to 1.17, since 1.18 introduced generics, which are not supported by linters yet

* fix: freeze go version to 1.17, since 1.18 introduced generics, which are not supported by linters yet
This commit is contained in:
Denis Titusov
2022-03-18 10:54:29 +03:00
committed by GitHub
parent 7a63525420
commit 89b2806f6a
13 changed files with 61 additions and 65 deletions
+1 -1
View File
@@ -1 +1 @@
.go@latest.pkg
.go-1.17.pkg
+1 -1
View File
@@ -1 +1 @@
.go@latest.pkg
.go-1.17.pkg
+1 -3
View File
@@ -4,8 +4,6 @@ import (
"fmt"
"reflect"
"strings"
"github.com/pkg/errors"
)
type bindings map[reflect.Type]func() (reflect.Value, error)
@@ -35,7 +33,7 @@ func (b bindings) addProvider(provider interface{}) error {
pv := reflect.ValueOf(provider)
t := pv.Type()
if t.Kind() != reflect.Func || t.NumIn() != 0 || t.NumOut() != 2 || t.Out(1) != reflect.TypeOf((*error)(nil)).Elem() {
return errors.Errorf("%T must be a function with the signature func()(T, error)", provider)
return fmt.Errorf("%T must be a function with the signature func()(T, error)", provider)
}
rt := pv.Type().Out(0)
b[rt] = func() (reflect.Value, error) {
+8 -9
View File
@@ -1,14 +1,13 @@
package kong
import (
"errors"
"fmt"
"os"
"reflect"
"sort"
"strconv"
"strings"
"github.com/pkg/errors"
)
// Path records the nodes and parsed values from the current command-line.
@@ -209,9 +208,8 @@ func (c *Context) Validate() error { // nolint: gocyclo
desc = node.Path()
}
if validate := isValidatable(value); validate != nil {
err := validate.Validate()
if err != nil {
return errors.Wrap(err, desc)
if err := validate.Validate(); err != nil {
return fmt.Errorf("%s: %w", desc, err)
}
}
}
@@ -558,7 +556,7 @@ func (c *Context) Resolve() error {
for _, resolver := range resolvers {
s, err := resolver.Resolve(c, path, flag)
if err != nil {
return errors.Wrap(err, flag.ShortSummary())
return fmt.Errorf("%s: %w", flag.ShortSummary(), err)
}
if s == nil {
continue
@@ -683,8 +681,9 @@ func (c *Context) parseFlag(flags []*Flag, match string) (err error) {
}
err := flag.Parse(c.scan, c.getValue(flag.Value))
if err != nil {
if e, ok := errors.Cause(err).(*expectedError); ok && e.token.InferredType().IsAny(FlagToken, ShortFlagToken) {
return errors.Errorf("%s; perhaps try %s=%q?", err, flag.ShortSummary(), e.token)
var expected *expectedError
if errors.As(err, &expected) && expected.token.InferredType().IsAny(FlagToken, ShortFlagToken) {
return fmt.Errorf("%s; perhaps try %s=%q?", err.Error(), flag.ShortSummary(), expected.token)
}
return err
}
@@ -888,7 +887,7 @@ func checkEnum(value *Value, target reflect.Value) error {
return nil
case reflect.Map, reflect.Struct:
return errors.Errorf("enum can only be applied to a slice or value")
return errors.New("enum can only be applied to a slice or value")
default:
enumSlice := value.EnumSlice()
+2 -2
View File
@@ -8,5 +8,5 @@ type ParseError struct {
Context *Context
}
// Cause returns the original cause of the error.
func (p *ParseError) Cause() error { return p.error }
// Unwrap returns the original cause of the error.
func (p *ParseError) Unwrap() error { return p.error }
-1
View File
@@ -3,7 +3,6 @@ module github.com/alecthomas/kong
require (
github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.7.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
-2
View File
@@ -3,8 +3,6 @@ github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142/go.mod h1:2kn6fqh/
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+5 -3
View File
@@ -1,6 +1,7 @@
package kong
import (
"errors"
"fmt"
"io"
"os"
@@ -378,13 +379,14 @@ func (k *Kong) FatalIfErrorf(err error, args ...interface{}) {
msg = fmt.Sprintf(args[0].(string), args[1:]...) + ": " + err.Error()
}
// Maybe display usage information.
if err, ok := err.(*ParseError); ok {
var parseErr *ParseError
if errors.As(err, &parseErr) {
switch k.usageOnError {
case fullUsage:
_ = k.help(k.helpOptions, err.Context)
_ = k.help(k.helpOptions, parseErr.Context)
fmt.Fprintln(k.Stdout)
case shortUsage:
_ = k.shortHelp(k.helpOptions, err.Context)
_ = k.shortHelp(k.helpOptions, parseErr.Context)
fmt.Fprintln(k.Stdout)
}
}
+1 -1
View File
@@ -2,11 +2,11 @@ package kong_test
import (
"bytes"
"errors"
"fmt"
"strings"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
"github.com/alecthomas/kong"
+37 -35
View File
@@ -3,6 +3,7 @@ package kong
import (
"encoding"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"math/bits"
@@ -12,8 +13,6 @@ import (
"strconv"
"strings"
"time"
"github.com/pkg/errors"
)
var (
@@ -295,14 +294,14 @@ func (boolMapper) Decode(ctx *DecodeContext, target reflect.Value) error {
target.SetBool(false)
default:
return errors.Errorf("bool value must be true, 1, yes, false, 0 or no but got %q", v)
return fmt.Errorf("bool value must be true, 1, yes, false, 0 or no but got %q", v)
}
case bool:
target.SetBool(v)
default:
return errors.Errorf("expected bool but got %q (%T)", token.Value, token.Value)
return fmt.Errorf("expected bool but got %q (%T)", token.Value, token.Value)
}
} else {
target.SetBool(true)
@@ -322,12 +321,12 @@ func durationDecoder() MapperFunc {
case string:
d, err = time.ParseDuration(v)
if err != nil {
return errors.Errorf("expected duration but got %q: %s", v, err)
return fmt.Errorf("expected duration but got %q: %v", v, err)
}
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
d = reflect.ValueOf(v).Convert(reflect.TypeOf(time.Duration(0))).Interface().(time.Duration) // nolint: forcetypeassert
default:
return errors.Errorf("expected duration but got %q", v)
return fmt.Errorf("expected duration but got %q", v)
}
target.Set(reflect.ValueOf(d))
return nil
@@ -368,11 +367,11 @@ func intDecoder(bits int) MapperFunc { // nolint: dupl
sv = fmt.Sprintf("%v", v)
default:
return errors.Errorf("expected an int but got %q (%T)", t, t.Value)
return fmt.Errorf("expected an int but got %q (%T)", t, t.Value)
}
n, err := strconv.ParseInt(sv, 10, bits)
if err != nil {
return errors.Errorf("expected a valid %d bit int but got %q", bits, sv)
return fmt.Errorf("expected a valid %d bit int but got %q", bits, sv)
}
target.SetInt(n)
return nil
@@ -394,11 +393,11 @@ func uintDecoder(bits int) MapperFunc { // nolint: dupl
sv = fmt.Sprintf("%v", v)
default:
return errors.Errorf("expected an int but got %q (%T)", t, t.Value)
return fmt.Errorf("expected an int but got %q (%T)", t, t.Value)
}
n, err := strconv.ParseUint(sv, 10, bits)
if err != nil {
return errors.Errorf("expected a valid %d bit uint but got %q", bits, sv)
return fmt.Errorf("expected a valid %d bit uint but got %q", bits, sv)
}
target.SetUint(n)
return nil
@@ -415,7 +414,7 @@ func floatDecoder(bits int) MapperFunc {
case string:
n, err := strconv.ParseFloat(v, bits)
if err != nil {
return errors.Errorf("expected a float but got %q (%T)", t, t.Value)
return fmt.Errorf("expected a float but got %q (%T)", t, t.Value)
}
target.SetFloat(n)
@@ -429,7 +428,7 @@ func floatDecoder(bits int) MapperFunc {
target.Set(reflect.ValueOf(v))
default:
return errors.Errorf("expected an int but got %q (%T)", t, t.Value)
return fmt.Errorf("expected an int but got %q (%T)", t, t.Value)
}
return nil
}
@@ -447,7 +446,7 @@ func mapDecoder(r *Registry) MapperFunc {
t := ctx.Scan.Pop()
// If decoding a flag, we need an argument.
if t.IsEOL() {
return errors.Errorf("unexpected EOL")
return errors.New("unexpected EOL")
}
switch v := t.Value.(type) {
case string:
@@ -457,7 +456,7 @@ func mapDecoder(r *Registry) MapperFunc {
for _, m := range v {
err := jsonTranscode(m, target.Addr().Interface())
if err != nil {
return errors.WithStack(err)
return err
}
}
return nil
@@ -466,7 +465,7 @@ func mapDecoder(r *Registry) MapperFunc {
return jsonTranscode(v, target.Addr().Interface())
default:
return errors.Errorf("invalid map value %q (of type %T)", t, t.Value)
return fmt.Errorf("invalid map value %q (of type %T)", t, t.Value)
}
} else {
tokens := ctx.Scan.PopWhile(func(t Token) bool { return t.IsValue() })
@@ -480,7 +479,7 @@ func mapDecoder(r *Registry) MapperFunc {
}
parts := strings.SplitN(token, "=", 2)
if len(parts) != 2 {
return errors.Errorf("expected \"<key>=<value>\" but got %q", token)
return fmt.Errorf("expected \"<key>=<value>\" but got %q", token)
}
key, value := parts[0], parts[1]
@@ -488,7 +487,7 @@ func mapDecoder(r *Registry) MapperFunc {
if typ := ctx.Value.Tag.Type; typ != "" {
parts := strings.Split(typ, ":")
if len(parts) != 2 {
return errors.Errorf("type:\"\" on map field must be in the form \"[<keytype>]:[<valuetype>]\"")
return errors.New("type:\"\" on map field must be in the form \"[<keytype>]:[<valuetype>]\"")
}
keyTypeName, valueTypeName = parts[0], parts[1]
}
@@ -497,14 +496,14 @@ func mapDecoder(r *Registry) MapperFunc {
keyDecoder := r.ForNamedType(keyTypeName, el.Key())
keyValue := reflect.New(el.Key()).Elem()
if err := keyDecoder.Decode(ctx.WithScanner(keyScanner), keyValue); err != nil {
return errors.Errorf("invalid map key %q", key)
return fmt.Errorf("invalid map key %q", key)
}
valueScanner := Scan(value)
valueDecoder := r.ForNamedType(valueTypeName, el.Elem())
valueValue := reflect.New(el.Elem()).Elem()
if err := valueDecoder.Decode(ctx.WithScanner(valueScanner), valueValue); err != nil {
return errors.Errorf("invalid map value %q", value)
return fmt.Errorf("invalid map value %q", value)
}
target.SetMapIndex(keyValue, valueValue)
@@ -522,7 +521,7 @@ func sliceDecoder(r *Registry) MapperFunc {
t := ctx.Scan.Pop()
// If decoding a flag, we need an argument.
if t.IsEOL() {
return errors.Errorf("unexpected EOL")
return errors.New("unexpected EOL")
}
switch v := t.Value.(type) {
case string:
@@ -541,13 +540,13 @@ func sliceDecoder(r *Registry) MapperFunc {
}
childDecoder := r.ForNamedType(ctx.Value.Tag.Type, el)
if childDecoder == nil {
return errors.Errorf("no mapper for element type of %s", target.Type())
return fmt.Errorf("no mapper for element type of %s", target.Type())
}
for !childScanner.Peek().IsEOL() {
childValue := reflect.New(el).Elem()
err := childDecoder.Decode(ctx.WithScanner(childScanner), childValue)
if err != nil {
return errors.WithStack(err)
return err
}
target.Set(reflect.Append(target, childValue))
}
@@ -561,7 +560,7 @@ func pathMapper(r *Registry) MapperFunc {
return sliceDecoder(r)(ctx, target)
}
if target.Kind() != reflect.String {
return errors.Errorf("\"path\" type must be applied to a string not %s", target.Type())
return fmt.Errorf("\"path\" type must be applied to a string not %s", target.Type())
}
var path string
err := ctx.Scan.PopValueInto("file", &path)
@@ -607,7 +606,7 @@ func existingFileMapper(r *Registry) MapperFunc {
return sliceDecoder(r)(ctx, target)
}
if target.Kind() != reflect.String {
return errors.Errorf("\"existingfile\" type must be applied to a string not %s", target.Type())
return fmt.Errorf("\"existingfile\" type must be applied to a string not %s", target.Type())
}
var path string
err := ctx.Scan.PopValueInto("file", &path)
@@ -621,7 +620,7 @@ func existingFileMapper(r *Registry) MapperFunc {
return err
}
if stat.IsDir() {
return errors.Errorf("%q exists but is a directory", path)
return fmt.Errorf("%q exists but is a directory", path)
}
}
target.SetString(path)
@@ -635,7 +634,7 @@ func existingDirMapper(r *Registry) MapperFunc {
return sliceDecoder(r)(ctx, target)
}
if target.Kind() != reflect.String {
return errors.Errorf("\"existingdir\" must be applied to a string not %s", target.Type())
return fmt.Errorf("\"existingdir\" must be applied to a string not %s", target.Type())
}
var path string
err := ctx.Scan.PopValueInto("file", &path)
@@ -648,7 +647,7 @@ func existingDirMapper(r *Registry) MapperFunc {
return err
}
if !stat.IsDir() {
return errors.Errorf("%q exists but is not a directory", path)
return fmt.Errorf("%q exists but is not a directory", path)
}
target.SetString(path)
return nil
@@ -666,7 +665,7 @@ func counterMapper() MapperFunc {
case string:
n, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return errors.Errorf("expected a counter but got %q (%T)", t, t.Value)
return fmt.Errorf("expected a counter but got %q (%T)", t, t.Value)
}
target.SetInt(n)
@@ -674,7 +673,7 @@ func counterMapper() MapperFunc {
target.Set(reflect.ValueOf(v))
default:
return errors.Errorf("expected a counter but got %q (%T)", t, t.Value)
return fmt.Errorf("expected a counter but got %q (%T)", t, t.Value)
}
return nil
}
@@ -690,7 +689,7 @@ func counterMapper() MapperFunc {
target.SetFloat(target.Float() + 1)
default:
return errors.Errorf("type:\"counter\" must be used with a numeric field")
return fmt.Errorf("type:\"counter\" must be used with a numeric field")
}
return nil
}
@@ -705,7 +704,7 @@ func urlMapper() MapperFunc {
}
url, err := url.Parse(urlStr)
if err != nil {
return errors.WithStack(err)
return err
}
target.Set(reflect.ValueOf(url))
return nil
@@ -775,7 +774,7 @@ func (f *NamedFileContentFlag) Decode(ctx *DecodeContext) error { // nolint: rev
filename = ExpandPath(filename)
data, err := ioutil.ReadFile(filename) // nolint: gosec
if err != nil {
return errors.Errorf("failed to open %q: %s", filename, err)
return fmt.Errorf("failed to open %q: %v", filename, err)
}
f.Contents = data
f.Filename = filename
@@ -799,7 +798,7 @@ func (f *FileContentFlag) Decode(ctx *DecodeContext) error { // nolint: revive
filename = ExpandPath(filename)
data, err := ioutil.ReadFile(filename) // nolint: gosec
if err != nil {
return errors.Errorf("failed to open %q: %s", filename, err)
return fmt.Errorf("failed to open %q: %v", filename, err)
}
*f = data
return nil
@@ -808,7 +807,10 @@ func (f *FileContentFlag) Decode(ctx *DecodeContext) error { // nolint: revive
func jsonTranscode(in, out interface{}) error {
data, err := json.Marshal(in)
if err != nil {
return errors.WithStack(err)
return err
}
return errors.Wrapf(json.Unmarshal(data, out), "%#v -> %T", in, out)
if err = json.Unmarshal(data, out); err != nil {
return fmt.Errorf("%#v -> %T: %v", in, out, err)
}
return nil
}
+1 -3
View File
@@ -7,8 +7,6 @@ import (
"reflect"
"strconv"
"strings"
"github.com/pkg/errors"
)
// A Visitable component in the model.
@@ -335,7 +333,7 @@ func (v *Value) Parse(scan *Scanner, target reflect.Value) (err error) {
}
err = v.Mapper.Decode(&DecodeContext{Value: v, Scan: scan}, target)
if err != nil {
return errors.Wrap(err, v.ShortSummary())
return fmt.Errorf("%s: %w", v.ShortSummary(), err)
}
v.Set = true
return nil
+4 -4
View File
@@ -1,6 +1,8 @@
package kong
import (
"errors"
"fmt"
"io"
"os"
"os/user"
@@ -8,8 +10,6 @@ import (
"reflect"
"regexp"
"strings"
"github.com/pkg/errors"
)
// An Option applies optional changes to the Kong application.
@@ -344,7 +344,7 @@ func IgnoreFields(regexes ...string) Option {
re, err := regexp.Compile(r)
if err != nil {
return errors.Wrap(err, "unable to compile regex")
return fmt.Errorf("unable to compile regex: %v", err)
}
k.ignoreFields = append(k.ignoreFields, re)
@@ -380,7 +380,7 @@ func Configuration(loader ConfigurationLoader, paths ...string) Option {
resolver, err := k.LoadConfig(path)
if err != nil {
return errors.Wrap(err, path)
return fmt.Errorf("%s: %v", path, err)
}
if resolver != nil {
k.resolvers = append(k.resolvers, resolver)