Produce a more useful error when flag-like values are used for flag values.
eg. myapp: error: --log-level: expected string value but got "--foo" (long flag); perhaps try --log-level="--foo"?
This commit is contained in:
@@ -5,6 +5,8 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Path records the nodes and parsed values from the current command-line.
|
// Path records the nodes and parsed values from the current command-line.
|
||||||
@@ -504,6 +506,9 @@ func (c *Context) parseFlag(flags []*Flag, match string) (err error) {
|
|||||||
c.scan.Pop()
|
c.scan.Pop()
|
||||||
err := flag.Parse(c.scan, c.getValue(flag.Value))
|
err := flag.Parse(c.scan, c.getValue(flag.Value))
|
||||||
if err != nil {
|
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)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.Path = append(c.Path, &Path{Flag: flag})
|
c.Path = append(c.Path, &Path{Flag: flag})
|
||||||
|
|||||||
+1
-1
@@ -715,7 +715,7 @@ func TestNumericParamErrors(t *testing.T) {
|
|||||||
}
|
}
|
||||||
parser := mustNew(t, &cli)
|
parser := mustNew(t, &cli)
|
||||||
_, err := parser.Parse([]string{"--name", "-10"})
|
_, err := parser.Parse([]string{"--name", "-10"})
|
||||||
require.EqualError(t, err, `--name: expected string value but got "-10" (short flag)`)
|
require.EqualError(t, err, `--name: expected string value but got "-10" (short flag); perhaps try --name="-10"?`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDefaultValueIsHyphen(t *testing.T) {
|
func TestDefaultValueIsHyphen(t *testing.T) {
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Visitable component in the model.
|
// A Visitable component in the model.
|
||||||
@@ -289,7 +291,7 @@ func (v *Value) Parse(scan *Scanner, target reflect.Value) (err error) {
|
|||||||
if rerr := recover(); rerr != nil {
|
if rerr := recover(); rerr != nil {
|
||||||
switch rerr := rerr.(type) {
|
switch rerr := rerr.(type) {
|
||||||
case Error:
|
case Error:
|
||||||
err = fmt.Errorf("%s: %s", v.ShortSummary(), rerr)
|
err = errors.Wrap(rerr, v.ShortSummary())
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("mapper %T failed to apply to %s: %s", v.Mapper, v.Summary(), rerr))
|
panic(fmt.Sprintf("mapper %T failed to apply to %s: %s", v.Mapper, v.Summary(), rerr))
|
||||||
}
|
}
|
||||||
@@ -297,7 +299,7 @@ func (v *Value) Parse(scan *Scanner, target reflect.Value) (err error) {
|
|||||||
}()
|
}()
|
||||||
err = v.Mapper.Decode(&DecodeContext{Value: v, Scan: scan}, target)
|
err = v.Mapper.Decode(&DecodeContext{Value: v, Scan: scan}, target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s: %s", v.ShortSummary(), err)
|
return errors.Wrap(err, v.ShortSummary())
|
||||||
}
|
}
|
||||||
v.Set = true
|
v.Set = true
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+18
-11
@@ -3,8 +3,6 @@ package kong
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TokenType is the type of a token.
|
// TokenType is the type of a token.
|
||||||
@@ -14,11 +12,11 @@ type TokenType int
|
|||||||
const (
|
const (
|
||||||
UntypedToken TokenType = iota
|
UntypedToken TokenType = iota
|
||||||
EOLToken
|
EOLToken
|
||||||
FlagToken // --<flag>
|
FlagToken // --<flag>
|
||||||
FlagValueToken // =<value>
|
FlagValueToken // =<value>
|
||||||
ShortFlagToken // -<short>[<tail]
|
ShortFlagToken // -<short>[<tail]
|
||||||
ShortFlagTailToken // <tail>
|
ShortFlagTailToken // <tail>
|
||||||
PositionalArgumentToken // <arg>
|
PositionalArgumentToken // <arg>
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t TokenType) String() string {
|
func (t TokenType) String() string {
|
||||||
@@ -142,13 +140,22 @@ func (s *Scanner) Pop() Token {
|
|||||||
return arg
|
return arg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type expectedError struct {
|
||||||
|
context string
|
||||||
|
token Token
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *expectedError) Error() string {
|
||||||
|
return fmt.Sprintf("expected %s value but got %q (%s)", e.context, e.token, e.token.InferredType())
|
||||||
|
}
|
||||||
|
|
||||||
// PopValue pops a value token, or returns an error.
|
// PopValue pops a value token, or returns an error.
|
||||||
//
|
//
|
||||||
// "context" is used to assist the user if the value can not be popped, eg. "expected <context> value but got <type>"
|
// "context" is used to assist the user if the value can not be popped, eg. "expected <context> value but got <type>"
|
||||||
func (s *Scanner) PopValue(context string) (Token, error) {
|
func (s *Scanner) PopValue(context string) (Token, error) {
|
||||||
t := s.Pop()
|
t := s.Pop()
|
||||||
if !t.IsValue() {
|
if !t.IsValue() {
|
||||||
return t, errors.Errorf("expected %s value but got %q (%s)", context, t, t.InferredType())
|
return t, &expectedError{context, t}
|
||||||
}
|
}
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
@@ -157,9 +164,9 @@ func (s *Scanner) PopValue(context string) (Token, error) {
|
|||||||
//
|
//
|
||||||
// "context" is used to assist the user if the value can not be popped, eg. "expected <context> value but got <type>"
|
// "context" is used to assist the user if the value can not be popped, eg. "expected <context> value but got <type>"
|
||||||
func (s *Scanner) PopValueInto(context string, target interface{}) error {
|
func (s *Scanner) PopValueInto(context string, target interface{}) error {
|
||||||
t := s.Pop()
|
t, err := s.PopValue(context)
|
||||||
if !t.IsValue() {
|
if err != nil {
|
||||||
return errors.Errorf("expected %s value but got %q (%s)", context, t, t.InferredType())
|
return err
|
||||||
}
|
}
|
||||||
return jsonTranscode(t.Value, target)
|
return jsonTranscode(t.Value, target)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user