refactor(client/v2): refactor of flags (#17306)

This commit is contained in:
Julien Robert 2023-08-07 15:53:02 +02:00 committed by GitHub
parent b61c72fc66
commit 6f29897bf0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 377 additions and 432 deletions

View File

@ -17,7 +17,7 @@ import (
type addressStringType struct{}
func (a addressStringType) NewValue(ctx context.Context, b *Builder) Value {
func (a addressStringType) NewValue(_ context.Context, b *Builder) Value {
return &addressValue{addressCodec: b.AddressCodec}
}
@ -27,7 +27,7 @@ func (a addressStringType) DefaultValue() string {
type validatorAddressStringType struct{}
func (a validatorAddressStringType) NewValue(ctx context.Context, b *Builder) Value {
func (a validatorAddressStringType) NewValue(_ context.Context, b *Builder) Value {
return &addressValue{addressCodec: b.ValidatorAddressCodec}
}
@ -61,7 +61,7 @@ func (a *addressValue) Set(s string) error {
}
func (a addressValue) Type() string {
return "bech32 account address key name"
return "bech32 account address"
}
type consensusAddressStringType struct{}

View File

@ -14,7 +14,7 @@ type binaryType struct{}
var _ Value = (*fileBinaryValue)(nil)
func (f binaryType) NewValue(_ context.Context, _ *Builder) Value {
func (f binaryType) NewValue(context.Context, *Builder) Value {
return &fileBinaryValue{}
}

View File

@ -1,10 +1,20 @@
package flag
import (
"context"
"fmt"
"strconv"
cosmos_proto "github.com/cosmos/cosmos-proto"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
"cosmossdk.io/client/v2/internal/util"
"cosmossdk.io/core/address"
)
@ -55,3 +65,296 @@ func (b *Builder) DefineScalarFlagType(scalarName string, flagType Type) {
b.init()
b.scalarFlagTypes[scalarName] = flagType
}
func (b *Builder) AddMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, messageType protoreflect.MessageType, commandOptions *autocliv1.RpcCommandOptions) (*MessageBinder, error) {
return b.addMessageFlags(ctx, flagSet, messageType, commandOptions, namingOptions{})
}
// AddMessageFlags adds flags for each field in the message to the flag set.
func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, messageType protoreflect.MessageType, commandOptions *autocliv1.RpcCommandOptions, options namingOptions) (*MessageBinder, error) {
fields := messageType.Descriptor().Fields()
numFields := fields.Len()
handler := &MessageBinder{
messageType: messageType,
}
isPositional := map[string]bool{}
hasVarargs := false
hasOptional := false
n := len(commandOptions.PositionalArgs)
// positional args are also parsed using a FlagSet so that we can reuse all the same parsers
handler.positionalFlagSet = pflag.NewFlagSet("positional", pflag.ContinueOnError)
for i, arg := range commandOptions.PositionalArgs {
isPositional[arg.ProtoField] = true
field := fields.ByName(protoreflect.Name(arg.ProtoField))
if field == nil {
return nil, fmt.Errorf("can't find field %s on %s", arg.ProtoField, messageType.Descriptor().FullName())
}
if arg.Optional && arg.Varargs {
return nil, fmt.Errorf("positional argument %s can't be both optional and varargs", arg.ProtoField)
}
if arg.Varargs {
if i != n-1 {
return nil, fmt.Errorf("varargs positional argument %s must be the last argument", arg.ProtoField)
}
hasVarargs = true
}
if arg.Optional {
if i != n-1 {
return nil, fmt.Errorf("optional positional argument %s must be the last argument", arg.ProtoField)
}
hasOptional = true
}
_, hasValue, err := b.addFieldFlag(
ctx,
handler.positionalFlagSet,
field,
&autocliv1.FlagOptions{Name: fmt.Sprintf("%d", i)},
namingOptions{},
)
if err != nil {
return nil, err
}
handler.positionalArgs = append(handler.positionalArgs, fieldBinding{
field: field,
hasValue: hasValue,
})
}
if hasVarargs {
handler.CobraArgs = cobra.MinimumNArgs(n - 1)
handler.hasVarargs = true
} else if hasOptional {
handler.CobraArgs = cobra.RangeArgs(n-1, n)
handler.hasOptional = true
} else {
handler.CobraArgs = cobra.ExactArgs(n)
}
// validate flag options
for name := range commandOptions.FlagOptions {
if fields.ByName(protoreflect.Name(name)) == nil {
return nil, fmt.Errorf("can't find field %s on %s specified as a flag", name, messageType.Descriptor().FullName())
}
}
flagOptsByFlagName := map[string]*autocliv1.FlagOptions{}
for i := 0; i < numFields; i++ {
field := fields.Get(i)
if isPositional[string(field.Name())] {
continue
}
flagOpts := commandOptions.FlagOptions[string(field.Name())]
name, hasValue, err := b.addFieldFlag(ctx, flagSet, field, flagOpts, options)
flagOptsByFlagName[name] = flagOpts
if err != nil {
return nil, err
}
handler.flagBindings = append(handler.flagBindings, fieldBinding{
hasValue: hasValue,
field: field,
})
}
flagSet.VisitAll(func(flag *pflag.Flag) {
opts := flagOptsByFlagName[flag.Name]
if opts != nil {
// This is a bit of hacking around the pflag API, but
// we need to set these options here using Flag.VisitAll because the flag
// constructors that pflag gives us (StringP, Int32P, etc.) do not
// actually return the *Flag instance
flag.Deprecated = opts.Deprecated
flag.ShorthandDeprecated = opts.ShorthandDeprecated
flag.Hidden = opts.Hidden
}
})
return handler, nil
}
// bindPageRequest create a flag for pagination
func (b *Builder) bindPageRequest(ctx context.Context, flagSet *pflag.FlagSet, field protoreflect.FieldDescriptor) (HasValue, error) {
return b.addMessageFlags(
ctx,
flagSet,
util.ResolveMessageType(b.TypeResolver, field.Message()),
&autocliv1.RpcCommandOptions{},
namingOptions{Prefix: "page-"},
)
}
// namingOptions specifies internal naming options for flags.
type namingOptions struct {
// Prefix is a prefix to prepend to all flags.
Prefix string
}
// addFieldFlag adds a flag for the provided field to the flag set.
func (b *Builder) addFieldFlag(ctx context.Context, flagSet *pflag.FlagSet, field protoreflect.FieldDescriptor, opts *autocliv1.FlagOptions, options namingOptions) (name string, hasValue HasValue, err error) {
if opts == nil {
opts = &autocliv1.FlagOptions{}
}
if field.Kind() == protoreflect.MessageKind && field.Message().FullName() == "cosmos.base.query.v1beta1.PageRequest" {
hasValue, err := b.bindPageRequest(ctx, flagSet, field)
return "", hasValue, err
}
name = opts.Name
if name == "" {
name = options.Prefix + util.DescriptorKebabName(field)
}
usage := opts.Usage
if usage == "" {
usage = util.DescriptorDocs(field)
}
shorthand := opts.Shorthand
defaultValue := opts.DefaultValue
if typ := b.resolveFlagType(field); typ != nil {
if defaultValue == "" {
defaultValue = typ.DefaultValue()
}
val := typ.NewValue(ctx, b)
flagSet.AddFlag(&pflag.Flag{
Name: name,
Shorthand: shorthand,
Usage: usage,
DefValue: defaultValue,
Value: val,
})
return name, val, nil
}
// use the built-in pflag StringP, Int32P, etc. functions
var val HasValue
if field.IsList() {
val = bindSimpleListFlag(flagSet, field.Kind(), name, shorthand, usage)
} else if field.IsMap() {
keyKind := field.MapKey().Kind()
valKind := field.MapValue().Kind()
val = bindSimpleMapFlag(flagSet, keyKind, valKind, name, shorthand, usage)
} else {
val = bindSimpleFlag(flagSet, field.Kind(), name, shorthand, usage)
}
// This is a bit of hacking around the pflag API, but the
// defaultValue is set in this way because this is much easier than trying
// to parse the string into the types that StringSliceP, Int32P, etc. expect
if defaultValue != "" {
err = flagSet.Set(name, defaultValue)
}
return name, val, err
}
func (b *Builder) resolveFlagType(field protoreflect.FieldDescriptor) Type {
typ := b.resolveFlagTypeBasic(field)
if field.IsList() {
if typ != nil {
return compositeListType{simpleType: typ}
}
return nil
}
if field.IsMap() {
keyKind := field.MapKey().Kind()
valType := b.resolveFlagType(field.MapValue())
if valType != nil {
switch keyKind {
case protoreflect.StringKind:
ct := new(compositeMapType[string])
ct.keyValueResolver = func(s string) (string, error) { return s, nil }
ct.valueType = valType
ct.keyType = "string"
return ct
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
ct := new(compositeMapType[int32])
ct.keyValueResolver = func(s string) (int32, error) {
i, err := strconv.ParseInt(s, 10, 32)
return int32(i), err
}
ct.valueType = valType
ct.keyType = "int32"
return ct
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
ct := new(compositeMapType[int64])
ct.keyValueResolver = func(s string) (int64, error) {
i, err := strconv.ParseInt(s, 10, 64)
return i, err
}
ct.valueType = valType
ct.keyType = "int64"
return ct
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
ct := new(compositeMapType[uint32])
ct.keyValueResolver = func(s string) (uint32, error) {
i, err := strconv.ParseUint(s, 10, 32)
return uint32(i), err
}
ct.valueType = valType
ct.keyType = "uint32"
return ct
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
ct := new(compositeMapType[uint64])
ct.keyValueResolver = func(s string) (uint64, error) {
i, err := strconv.ParseUint(s, 10, 64)
return i, err
}
ct.valueType = valType
ct.keyType = "uint64"
return ct
case protoreflect.BoolKind:
ct := new(compositeMapType[bool])
ct.keyValueResolver = strconv.ParseBool
ct.valueType = valType
ct.keyType = "bool"
return ct
}
return nil
}
return nil
}
return typ
}
func (b *Builder) resolveFlagTypeBasic(field protoreflect.FieldDescriptor) Type {
scalar := proto.GetExtension(field.Options(), cosmos_proto.E_Scalar)
if scalar != nil {
b.init()
if typ, ok := b.scalarFlagTypes[scalar.(string)]; ok {
return typ
}
}
switch field.Kind() {
case protoreflect.BytesKind:
return binaryType{}
case protoreflect.EnumKind:
return enumType{enum: field.Enum()}
case protoreflect.MessageKind:
b.init()
if flagType, ok := b.messageFlagTypes[field.Message().FullName()]; ok {
return flagType
}
return jsonMessageFlagType{
messageDesc: field.Message(),
}
default:
return nil
}
}

View File

@ -15,7 +15,7 @@ type coinValue struct {
value *basev1beta1.Coin
}
func (c coinType) NewValue(_ context.Context, _ *Builder) Value {
func (c coinType) NewValue(context.Context, *Builder) Value {
return &coinValue{}
}

View File

@ -1,180 +0,0 @@
package flag
import (
"context"
"strconv"
cosmos_proto "github.com/cosmos/cosmos-proto"
"github.com/spf13/pflag"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
"cosmossdk.io/client/v2/internal/util"
)
// namingOptions specifies internal naming options for flags.
type namingOptions struct {
// Prefix is a prefix to prepend to all flags.
Prefix string
}
// addFieldFlag adds a flag for the provided field to the flag set.
func (b *Builder) addFieldFlag(ctx context.Context, flagSet *pflag.FlagSet, field protoreflect.FieldDescriptor, opts *autocliv1.FlagOptions, options namingOptions) (name string, hasValue HasValue, err error) {
if opts == nil {
opts = &autocliv1.FlagOptions{}
}
if field.Kind() == protoreflect.MessageKind && field.Message().FullName() == "cosmos.base.query.v1beta1.PageRequest" {
hasValue, err := b.bindPageRequest(ctx, flagSet, field)
return "", hasValue, err
}
name = opts.Name
if name == "" {
name = options.Prefix + util.DescriptorKebabName(field)
}
usage := opts.Usage
if usage == "" {
usage = util.DescriptorDocs(field)
}
shorthand := opts.Shorthand
defaultValue := opts.DefaultValue
if typ := b.resolveFlagType(field); typ != nil {
if defaultValue == "" {
defaultValue = typ.DefaultValue()
}
val := typ.NewValue(ctx, b)
flagSet.AddFlag(&pflag.Flag{
Name: name,
Shorthand: shorthand,
Usage: usage,
DefValue: defaultValue,
Value: val,
})
return name, val, nil
}
// use the built-in pflag StringP, Int32P, etc. functions
var val HasValue
if field.IsList() {
val = bindSimpleListFlag(flagSet, field.Kind(), name, shorthand, usage)
} else if field.IsMap() {
keyKind := field.MapKey().Kind()
valKind := field.MapValue().Kind()
val = bindSimpleMapFlag(flagSet, keyKind, valKind, name, shorthand, usage)
} else {
val = bindSimpleFlag(flagSet, field.Kind(), name, shorthand, usage)
}
// This is a bit of hacking around the pflag API, but the
// defaultValue is set in this way because this is much easier than trying
// to parse the string into the types that StringSliceP, Int32P, etc. expect
if defaultValue != "" {
err = flagSet.Set(name, defaultValue)
}
return name, val, err
}
func (b *Builder) resolveFlagType(field protoreflect.FieldDescriptor) Type {
typ := b.resolveFlagTypeBasic(field)
if field.IsList() {
if typ != nil {
return compositeListType{simpleType: typ}
}
return nil
}
if field.IsMap() {
keyKind := field.MapKey().Kind()
valType := b.resolveFlagType(field.MapValue())
if valType != nil {
switch keyKind {
case protoreflect.StringKind:
ct := new(compositeMapType[string])
ct.keyValueResolver = func(s string) (string, error) { return s, nil }
ct.valueType = valType
ct.keyType = "string"
return ct
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
ct := new(compositeMapType[int32])
ct.keyValueResolver = func(s string) (int32, error) {
i, err := strconv.ParseInt(s, 10, 32)
return int32(i), err
}
ct.valueType = valType
ct.keyType = "int32"
return ct
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
ct := new(compositeMapType[int64])
ct.keyValueResolver = func(s string) (int64, error) {
i, err := strconv.ParseInt(s, 10, 64)
return i, err
}
ct.valueType = valType
ct.keyType = "int64"
return ct
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
ct := new(compositeMapType[uint32])
ct.keyValueResolver = func(s string) (uint32, error) {
i, err := strconv.ParseUint(s, 10, 32)
return uint32(i), err
}
ct.valueType = valType
ct.keyType = "uint32"
return ct
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
ct := new(compositeMapType[uint64])
ct.keyValueResolver = func(s string) (uint64, error) {
i, err := strconv.ParseUint(s, 10, 64)
return i, err
}
ct.valueType = valType
ct.keyType = "uint64"
return ct
case protoreflect.BoolKind:
ct := new(compositeMapType[bool])
ct.keyValueResolver = strconv.ParseBool
ct.valueType = valType
ct.keyType = "bool"
return ct
}
return nil
}
return nil
}
return typ
}
func (b *Builder) resolveFlagTypeBasic(field protoreflect.FieldDescriptor) Type {
scalar := proto.GetExtension(field.Options(), cosmos_proto.E_Scalar)
if scalar != nil {
b.init()
if typ, ok := b.scalarFlagTypes[scalar.(string)]; ok {
return typ
}
}
switch field.Kind() {
case protoreflect.BytesKind:
return binaryType{}
case protoreflect.EnumKind:
return enumType{enum: field.Enum()}
case protoreflect.MessageKind:
b.init()
if flagType, ok := b.messageFlagTypes[field.Message().FullName()]; ok {
return flagType
}
return jsonMessageFlagType{
messageDesc: field.Message(),
}
default:
return nil
}
}

View File

@ -1,10 +1,22 @@
package flag
import (
"context"
"github.com/spf13/pflag"
"google.golang.org/protobuf/reflect/protoreflect"
)
// Type specifies a custom flag type.
type Type interface {
// NewValue returns a new pflag.Value which must also implement either
// SimpleValue or ListValue.
NewValue(context.Context, *Builder) Value
// DefaultValue is the default value for this type.
DefaultValue() string
}
// Value represents a single pflag.Value value.
type Value interface {
pflag.Value

View File

@ -8,6 +8,8 @@ import (
"github.com/cockroachdb/errors"
"github.com/spf13/pflag"
"google.golang.org/protobuf/reflect/protoreflect"
"cosmossdk.io/client/v2/autocli/flag/maps"
)
func bindSimpleMapFlag(flagSet *pflag.FlagSet, keyKind, valueKind protoreflect.Kind, name, shorthand, usage string) HasValue {
@ -18,126 +20,126 @@ func bindSimpleMapFlag(flagSet *pflag.FlagSet, keyKind, valueKind protoreflect.K
val := flagSet.StringToStringP(name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfString)
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
val := StringToInt32P(flagSet, name, shorthand, nil, usage)
val := maps.StringToInt32P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfInt32)
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
val := flagSet.StringToInt64P(name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfInt64)
case protoreflect.Uint32Kind:
val := StringToUint32P(flagSet, name, shorthand, nil, usage)
val := maps.StringToUint32P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfUint32)
case protoreflect.Uint64Kind:
val := StringToUint64P(flagSet, name, shorthand, nil, usage)
val := maps.StringToUint64P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfUint64)
case protoreflect.BoolKind:
val := StringToBoolP(flagSet, name, shorthand, nil, usage)
val := maps.StringToBoolP(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfBool)
}
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
switch valueKind {
case protoreflect.StringKind:
val := Int32ToStringP(flagSet, name, shorthand, nil, usage)
val := maps.Int32ToStringP(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfString)
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
val := Int32ToInt32P(flagSet, name, shorthand, nil, usage)
val := maps.Int32ToInt32P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfInt32)
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
val := Int32ToInt64P(flagSet, name, shorthand, nil, usage)
val := maps.Int32ToInt64P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfInt64)
case protoreflect.Uint32Kind:
val := Int32ToUint32P(flagSet, name, shorthand, nil, usage)
val := maps.Int32ToUint32P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfUint32)
case protoreflect.Uint64Kind:
val := Int32ToUint64P(flagSet, name, shorthand, nil, usage)
val := maps.Int32ToUint64P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfUint64)
case protoreflect.BoolKind:
val := Int32ToBoolP(flagSet, name, shorthand, nil, usage)
val := maps.Int32ToBoolP(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfBool)
}
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
switch valueKind {
case protoreflect.StringKind:
val := Int64ToStringP(flagSet, name, shorthand, nil, usage)
val := maps.Int64ToStringP(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfString)
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
val := Int64ToInt32P(flagSet, name, shorthand, nil, usage)
val := maps.Int64ToInt32P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfInt32)
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
val := Int64ToInt64P(flagSet, name, shorthand, nil, usage)
val := maps.Int64ToInt64P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfInt64)
case protoreflect.Uint32Kind:
val := Int64ToUint32P(flagSet, name, shorthand, nil, usage)
val := maps.Int64ToUint32P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfUint32)
case protoreflect.Uint64Kind:
val := Int64ToUint64P(flagSet, name, shorthand, nil, usage)
val := maps.Int64ToUint64P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfUint64)
case protoreflect.BoolKind:
val := Int64ToBoolP(flagSet, name, shorthand, nil, usage)
val := maps.Int64ToBoolP(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfBool)
}
case protoreflect.Uint32Kind:
switch valueKind {
case protoreflect.StringKind:
val := Uint32ToStringP(flagSet, name, shorthand, nil, usage)
val := maps.Uint32ToStringP(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfString)
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
val := Uint32ToInt32P(flagSet, name, shorthand, nil, usage)
val := maps.Uint32ToInt32P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfInt32)
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
val := Uint32ToInt64P(flagSet, name, shorthand, nil, usage)
val := maps.Uint32ToInt64P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfInt64)
case protoreflect.Uint32Kind:
val := Uint32ToUint32P(flagSet, name, shorthand, nil, usage)
val := maps.Uint32ToUint32P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfUint32)
case protoreflect.Uint64Kind:
val := Uint32ToUint64P(flagSet, name, shorthand, nil, usage)
val := maps.Uint32ToUint64P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfUint64)
case protoreflect.BoolKind:
val := Uint32ToBoolP(flagSet, name, shorthand, nil, usage)
val := maps.Uint32ToBoolP(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfBool)
}
case protoreflect.Uint64Kind:
switch valueKind {
case protoreflect.StringKind:
val := Uint64ToStringP(flagSet, name, shorthand, nil, usage)
val := maps.Uint64ToStringP(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfString)
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
val := Uint64ToInt32P(flagSet, name, shorthand, nil, usage)
val := maps.Uint64ToInt32P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfInt32)
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
val := Uint64ToInt64P(flagSet, name, shorthand, nil, usage)
val := maps.Uint64ToInt64P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfInt64)
case protoreflect.Uint32Kind:
val := Uint64ToUint32P(flagSet, name, shorthand, nil, usage)
val := maps.Uint64ToUint32P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfUint32)
case protoreflect.Uint64Kind:
val := Uint64ToUint64P(flagSet, name, shorthand, nil, usage)
val := maps.Uint64ToUint64P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfUint64)
case protoreflect.BoolKind:
val := Uint64ToBoolP(flagSet, name, shorthand, nil, usage)
val := maps.Uint64ToBoolP(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfBool)
}
case protoreflect.BoolKind:
switch valueKind {
case protoreflect.StringKind:
val := BoolToStringP(flagSet, name, shorthand, nil, usage)
val := maps.BoolToStringP(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfString)
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
val := BoolToInt32P(flagSet, name, shorthand, nil, usage)
val := maps.BoolToInt32P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfInt32)
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
val := BoolToInt64P(flagSet, name, shorthand, nil, usage)
val := maps.BoolToInt64P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfInt64)
case protoreflect.Uint32Kind:
val := BoolToUint32P(flagSet, name, shorthand, nil, usage)
val := maps.BoolToUint32P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfUint32)
case protoreflect.Uint64Kind:
val := BoolToUint64P(flagSet, name, shorthand, nil, usage)
val := maps.BoolToUint64P(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfUint64)
case protoreflect.BoolKind:
val := BoolToBoolP(flagSet, name, shorthand, nil, usage)
val := maps.BoolToBoolP(flagSet, name, shorthand, nil, usage)
return newMapValue(val, protoreflect.ValueOfBool)
}

View File

@ -1,4 +1,4 @@
package flag
package maps
import (
"strings"

View File

@ -1,4 +1,4 @@
package flag
package maps
import (
"strconv"

View File

@ -1,4 +1,4 @@
package flag
package maps
import (
"strconv"

View File

@ -1,4 +1,4 @@
package flag
package maps
import (
"strconv"

View File

@ -1,4 +1,4 @@
package flag
package maps
import (
"strconv"

View File

@ -1,4 +1,4 @@
package flag
package maps
import (
"strconv"

View File

@ -1,4 +1,4 @@
package flag
package maps
import (
"strconv"

View File

@ -89,6 +89,7 @@ func (f fieldBinding) bind(msg protoreflect.Message) error {
if err != nil {
return err
}
kind := f.field.Kind()
if !(field.IsList() ||
field.IsMap() ||
@ -96,5 +97,6 @@ func (f fieldBinding) bind(msg protoreflect.Message) error {
kind == protoreflect.GroupKind) {
msg.Set(f.field, val)
}
return nil
}

View File

@ -1,21 +0,0 @@
package flag
import (
"context"
"github.com/spf13/pflag"
"google.golang.org/protobuf/reflect/protoreflect"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
"cosmossdk.io/client/v2/internal/util"
)
func (b *Builder) bindPageRequest(ctx context.Context, flagSet *pflag.FlagSet, field protoreflect.FieldDescriptor) (HasValue, error) {
return b.addMessageFlags(
ctx,
flagSet,
util.ResolveMessageType(b.TypeResolver, field.Message()),
&autocliv1.RpcCommandOptions{},
namingOptions{Prefix: "page-"},
)
}

View File

@ -1,128 +0,0 @@
package flag
import (
"context"
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"google.golang.org/protobuf/reflect/protoreflect"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
)
func (b *Builder) AddMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, messageType protoreflect.MessageType, commandOptions *autocliv1.RpcCommandOptions) (*MessageBinder, error) {
return b.addMessageFlags(ctx, flagSet, messageType, commandOptions, namingOptions{})
}
// AddMessageFlags adds flags for each field in the message to the flag set.
func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, messageType protoreflect.MessageType, commandOptions *autocliv1.RpcCommandOptions, options namingOptions) (*MessageBinder, error) {
fields := messageType.Descriptor().Fields()
numFields := fields.Len()
handler := &MessageBinder{
messageType: messageType,
}
isPositional := map[string]bool{}
hasVarargs := false
hasOptional := false
n := len(commandOptions.PositionalArgs)
// positional args are also parsed using a FlagSet so that we can reuse all the same parsers
handler.positionalFlagSet = pflag.NewFlagSet("positional", pflag.ContinueOnError)
for i, arg := range commandOptions.PositionalArgs {
isPositional[arg.ProtoField] = true
field := fields.ByName(protoreflect.Name(arg.ProtoField))
if field == nil {
return nil, fmt.Errorf("can't find field %s on %s", arg.ProtoField, messageType.Descriptor().FullName())
}
if arg.Optional && arg.Varargs {
return nil, fmt.Errorf("positional argument %s can't be both optional and varargs", arg.ProtoField)
}
if arg.Varargs {
if i != n-1 {
return nil, fmt.Errorf("varargs positional argument %s must be the last argument", arg.ProtoField)
}
hasVarargs = true
}
if arg.Optional {
if i != n-1 {
return nil, fmt.Errorf("optional positional argument %s must be the last argument", arg.ProtoField)
}
hasOptional = true
}
_, hasValue, err := b.addFieldFlag(
ctx,
handler.positionalFlagSet,
field,
&autocliv1.FlagOptions{Name: fmt.Sprintf("%d", i)},
namingOptions{},
)
if err != nil {
return nil, err
}
handler.positionalArgs = append(handler.positionalArgs, fieldBinding{
field: field,
hasValue: hasValue,
})
}
if hasVarargs {
handler.CobraArgs = cobra.MinimumNArgs(n - 1)
handler.hasVarargs = true
} else if hasOptional {
handler.CobraArgs = cobra.RangeArgs(n-1, n)
handler.hasOptional = true
} else {
handler.CobraArgs = cobra.ExactArgs(n)
}
// validate flag options
for name := range commandOptions.FlagOptions {
if fields.ByName(protoreflect.Name(name)) == nil {
return nil, fmt.Errorf("can't find field %s on %s specified as a flag", name, messageType.Descriptor().FullName())
}
}
flagOptsByFlagName := map[string]*autocliv1.FlagOptions{}
for i := 0; i < numFields; i++ {
field := fields.Get(i)
if isPositional[string(field.Name())] {
continue
}
flagOpts := commandOptions.FlagOptions[string(field.Name())]
name, hasValue, err := b.addFieldFlag(ctx, flagSet, field, flagOpts, options)
flagOptsByFlagName[name] = flagOpts
if err != nil {
return nil, err
}
handler.flagBindings = append(handler.flagBindings, fieldBinding{
hasValue: hasValue,
field: field,
})
}
flagSet.VisitAll(func(flag *pflag.Flag) {
opts := flagOptsByFlagName[flag.Name]
if opts != nil {
// This is a bit of hacking around the pflag API, but
// we need to set these options here using Flag.VisitAll because the flag
// constructors that pflag gives us (StringP, Int32P, etc.) do not
// actually return the *Flag instance
flag.Deprecated = opts.Deprecated
flag.ShorthandDeprecated = opts.ShorthandDeprecated
flag.Hidden = opts.Hidden
}
})
return handler, nil
}

View File

@ -1,15 +0,0 @@
package flag
import (
"context"
)
// Type specifies a custom flag type.
type Type interface {
// NewValue returns a new pflag.Value which must also implement either
// SimpleValue or ListValue.
NewValue(context.Context, *Builder) Value
// DefaultValue is the default value for this type.
DefaultValue() string
}

View File

@ -114,9 +114,7 @@ func (b *Builder) BuildQueryMethodCommand(descriptor protoreflect.MethodDescript
}
output := outputType.New()
ctx := cmd.Context()
err = clientConn.Invoke(ctx, methodName, input.Interface(), output.Interface())
if err != nil {
if err := clientConn.Invoke(cmd.Context(), methodName, input.Interface(), output.Interface()); err != nil {
return err
}

View File

@ -1,28 +0,0 @@
tx:
service: cosmos.bank.v1beta1.Msg
rpc_command_options:
- rpc_method: Send
use: send [from_key_or_address] [to_address] [amount...]
positional_args:
- proto_field: from_address
- proto_field: to_address
- proto_field: amount
varargs: true
query:
service: cosmos.bank.v1beta1.Query
rpc_command_options:
- rpc_method: Balance
use: balance [address] [denom]
positional_args:
- proto_field: address
- proto_field: denom
- rpc_method: SupplyOf
# this is a contrived example of how to customize flag options
# we would likely prefer positional args here, but this demonstrates usage
use: supply-of --denom [denom]
flag_options:
# flag_options is a map of proto field names to customization options
denom:
shorthand: d
usage: the denom to query

View File

@ -8,9 +8,9 @@ Flags:
--a-bool
--a-coin cosmos.base.v1beta1.Coin
--a-message testpb.AMessage (json)
--a-validator-address bech32 account address key name
--a-validator-address bech32 account address
-a, --account-number uint The account number of the signing account (offline mode only)
--an-address bech32 account address key name
--an-address bech32 account address
--an-enum Enum (unspecified | one | two | five | neg-three) (default unspecified)
--aux Generate aux signer data instead of sending a tx
--bools bools (default [])

View File

@ -5,10 +5,10 @@ Usage:
Flags:
--a-bool
--a-coin cosmos.base.v1beta1.Coin
--a-consensus-address bech32 account address key name
--a-consensus-address bech32 account address
--a-message testpb.AMessage (json)
--a-validator-address bech32 account address key name
--an-address bech32 account address key name
--a-validator-address bech32 account address
--an-address bech32 account address
--an-enum Enum (unspecified | one | two | five | neg-three) (default unspecified)
--bools bools (default [])
--bz binary

View File

@ -13,9 +13,9 @@ Flags:
--a-bool
--a-coin cosmos.base.v1beta1.Coin
--a-message testpb.AMessage (json)
--a-validator-address bech32 account address key name
--a-validator-address bech32 account address
-a, --account-number uint The account number of the signing account (offline mode only)
--an-address bech32 account address key name
--an-address bech32 account address
--an-enum Enum (unspecified | one | two | five | neg-three) (default unspecified)
--aux Generate aux signer data instead of sending a tx
--bools bools (default [])

View File

@ -12,10 +12,10 @@ echo 1 abc {}
Flags:
--a-bool
--a-coin cosmos.base.v1beta1.Coin some random coin
--a-consensus-address bech32 account address key name
--a-consensus-address bech32 account address
--a-message testpb.AMessage (json)
--a-validator-address bech32 account address key name
--an-address bech32 account address key name
--a-validator-address bech32 account address
--an-address bech32 account address
--an-enum Enum (unspecified | one | two | five | neg-three) (default unspecified)
--bools bools (default [])
--bz binary some bytes

View File

@ -143,7 +143,7 @@ In order to enable this behavior, set in `AutoCLIOptions()` the `EnhanceCustomCo
```go reference
https://github.com/cosmos/cosmos-sdk/blob/julien/custom-commands/x/gov/autocli.go#L98
https://github.com/cosmos/cosmos-sdk/blob/fa4d87ef7e6d87aaccc94c337ffd2fe90fcb7a9d/x/gov/autocli.go#L98
```
If not set to true, `AutoCLI` will not generate commands for the module if there are already commands registered for the module (when `GetTxCmd()` or `GetTxCmd()` are defined).