Co-authored-by: Julien Robert <julien@rbrt.fr>
This commit is contained in:
parent
ab6a1e6dcb
commit
14d163a69c
@ -92,8 +92,6 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m
|
||||
}
|
||||
|
||||
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)
|
||||
@ -114,7 +112,7 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m
|
||||
return nil, fmt.Errorf("varargs positional argument %s must be the last argument", arg.ProtoField)
|
||||
}
|
||||
|
||||
hasVarargs = true
|
||||
handler.hasVarargs = true
|
||||
}
|
||||
|
||||
if arg.Optional {
|
||||
@ -122,7 +120,7 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m
|
||||
return nil, fmt.Errorf("optional positional argument %s must be the last argument", arg.ProtoField)
|
||||
}
|
||||
|
||||
hasOptional = true
|
||||
handler.hasOptional = true
|
||||
}
|
||||
|
||||
_, hasValue, err := b.addFieldFlag(
|
||||
@ -142,14 +140,15 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m
|
||||
})
|
||||
}
|
||||
|
||||
if hasVarargs {
|
||||
if handler.hasVarargs {
|
||||
handler.CobraArgs = cobra.MinimumNArgs(n - 1)
|
||||
handler.hasVarargs = true
|
||||
} else if hasOptional {
|
||||
handler.MandatoryArgUntil = n - 1
|
||||
} else if handler.hasOptional {
|
||||
handler.CobraArgs = cobra.RangeArgs(n-1, n)
|
||||
handler.hasOptional = true
|
||||
handler.MandatoryArgUntil = n - 1
|
||||
} else {
|
||||
handler.CobraArgs = cobra.ExactArgs(n)
|
||||
handler.MandatoryArgUntil = n
|
||||
}
|
||||
|
||||
// validate flag options
|
||||
|
||||
@ -2,6 +2,8 @@ package flag
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
@ -36,6 +38,10 @@ func (c *coinValue) String() string {
|
||||
}
|
||||
|
||||
func (c *coinValue) Set(stringValue string) error {
|
||||
if strings.Contains(stringValue, ",") {
|
||||
return fmt.Errorf("coin flag must be a single coin, specific multiple coins with multiple flags or spaces")
|
||||
}
|
||||
|
||||
coin, err := coins.ParseCoin(stringValue)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@ -10,7 +10,8 @@ import (
|
||||
|
||||
// MessageBinder binds multiple flags in a flag set to a protobuf message.
|
||||
type MessageBinder struct {
|
||||
CobraArgs cobra.PositionalArgs
|
||||
MandatoryArgUntil int
|
||||
CobraArgs cobra.PositionalArgs
|
||||
|
||||
positionalFlagSet *pflag.FlagSet
|
||||
positionalArgs []fieldBinding
|
||||
@ -38,10 +39,9 @@ func (m MessageBinder) Bind(msg protoreflect.Message, positionalArgs []string) e
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("%d", i)
|
||||
if i == n-1 && m.hasVarargs {
|
||||
if i == m.MandatoryArgUntil && m.hasVarargs {
|
||||
for _, v := range positionalArgs[i:] {
|
||||
err := m.positionalFlagSet.Set(name, v)
|
||||
if err != nil {
|
||||
if err := m.positionalFlagSet.Set(name, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,16 +191,51 @@ func TestCoin(t *testing.T) {
|
||||
fixture := initFixture(t)
|
||||
|
||||
_, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
|
||||
"echo",
|
||||
"1",
|
||||
"abc",
|
||||
"1234foo,4321bar",
|
||||
"100uatom",
|
||||
"--a-coin", "100000foo",
|
||||
)
|
||||
assert.ErrorContains(t, err, "coin flag must be a single coin, specific multiple coins with multiple flags or spaces")
|
||||
|
||||
_, err = runCmd(fixture.conn, fixture.b, buildModuleQueryCommand,
|
||||
"echo",
|
||||
"1",
|
||||
"abc",
|
||||
"1234foo",
|
||||
"4321bar",
|
||||
"100uatom",
|
||||
"--a-coin", "100000foo",
|
||||
"--duration", "4h3s",
|
||||
"--coins", "100000bar",
|
||||
"--coins", "100uatom",
|
||||
)
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, fixture.conn.lastRequest, fixture.conn.lastResponse.(*testpb.EchoResponse).Request, protocmp.Transform())
|
||||
expectedResp := &testpb.EchoResponse{
|
||||
Request: &testpb.EchoRequest{
|
||||
Positional1: 1,
|
||||
Positional2: "abc",
|
||||
Positional3Varargs: []*basev1beta1.Coin{
|
||||
{Amount: "1234", Denom: "foo"},
|
||||
{Amount: "4321", Denom: "bar"},
|
||||
{Amount: "100", Denom: "uatom"},
|
||||
},
|
||||
ACoin: &basev1beta1.Coin{
|
||||
Amount: "100000",
|
||||
Denom: "foo",
|
||||
},
|
||||
Coins: []*basev1beta1.Coin{
|
||||
{Amount: "100000", Denom: "bar"},
|
||||
{Amount: "100", Denom: "uatom"},
|
||||
},
|
||||
Page: &queryv1beta1.PageRequest{},
|
||||
I32: 3,
|
||||
U64: 5,
|
||||
},
|
||||
}
|
||||
assert.DeepEqual(t, fixture.conn.lastResponse.(*testpb.EchoResponse), expectedResp, protocmp.Transform())
|
||||
}
|
||||
|
||||
func TestOptional(t *testing.T) {
|
||||
@ -354,7 +389,7 @@ func TestEverything(t *testing.T) {
|
||||
Positional2: "abc",
|
||||
Positional3Varargs: []*basev1beta1.Coin{
|
||||
{Amount: "123.123123124", Denom: "foo"},
|
||||
// {Amount: "4321", Denom: "bar"}, // TODO fix repeated fields
|
||||
{Amount: "4321", Denom: "bar"},
|
||||
},
|
||||
ABool: true,
|
||||
AnEnum: testpb.Enum_ENUM_ONE,
|
||||
|
||||
@ -12,6 +12,7 @@ Flags:
|
||||
--an-enum Enum (unspecified | one | two | five | neg-three) (default unspecified)
|
||||
--bools bools (default [])
|
||||
--bz binary
|
||||
--coins cosmos.base.v1beta1.Coin (repeated)
|
||||
--deprecated-field string
|
||||
--duration duration
|
||||
--durations duration (repeated)
|
||||
|
||||
1
client/v2/autocli/testdata/help-echo.golden
vendored
1
client/v2/autocli/testdata/help-echo.golden
vendored
@ -19,6 +19,7 @@ Flags:
|
||||
--an-enum Enum (unspecified | one | two | five | neg-three) (default unspecified)
|
||||
--bools bools (default [])
|
||||
--bz binary some bytes
|
||||
--coins cosmos.base.v1beta1.Coin (repeated)
|
||||
--deprecated-field string (DEPRECATED: don't use this)
|
||||
--duration duration some random duration
|
||||
--durations duration (repeated)
|
||||
|
||||
@ -1,8 +1,4 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc (unknown)
|
||||
// source: testpb/msg.proto
|
||||
|
||||
package testpb
|
||||
|
||||
@ -18,10 +14,6 @@ import (
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
const (
|
||||
Msg_Send_FullMethodName = "/testpb.Msg/Send"
|
||||
)
|
||||
|
||||
// MsgClient is the client API for Msg service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
@ -40,7 +32,7 @@ func NewMsgClient(cc grpc.ClientConnInterface) MsgClient {
|
||||
|
||||
func (c *msgClient) Send(ctx context.Context, in *MsgRequest, opts ...grpc.CallOption) (*MsgResponse, error) {
|
||||
out := new(MsgResponse)
|
||||
err := c.cc.Invoke(ctx, Msg_Send_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/testpb.Msg/Send", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -86,7 +78,7 @@ func _Msg_Send_Handler(srv interface{}, ctx context.Context, dec func(interface{
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Msg_Send_FullMethodName,
|
||||
FullMethod: "/testpb.Msg/Send",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(MsgServer).Send(ctx, req.(*MsgRequest))
|
||||
|
||||
@ -48,6 +48,8 @@ message EchoRequest {
|
||||
map<string, cosmos.base.v1beta1.Coin> map_string_coin = 35;
|
||||
string a_validator_address = 36 [(cosmos_proto.scalar) = "cosmos.ValidatorAddressString"];
|
||||
string a_consensus_address = 37 [(cosmos_proto.scalar) = "cosmos.ConsensusAddressString"];
|
||||
|
||||
repeated cosmos.base.v1beta1.Coin coins = 38;
|
||||
}
|
||||
|
||||
enum Enum {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,4 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc (unknown)
|
||||
// source: testpb/query.proto
|
||||
|
||||
package testpb
|
||||
|
||||
@ -18,10 +14,6 @@ import (
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
const (
|
||||
Query_Echo_FullMethodName = "/testpb.Query/Echo"
|
||||
)
|
||||
|
||||
// QueryClient is the client API for Query service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
@ -40,7 +32,7 @@ func NewQueryClient(cc grpc.ClientConnInterface) QueryClient {
|
||||
|
||||
func (c *queryClient) Echo(ctx context.Context, in *EchoRequest, opts ...grpc.CallOption) (*EchoResponse, error) {
|
||||
out := new(EchoResponse)
|
||||
err := c.cc.Invoke(ctx, Query_Echo_FullMethodName, in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/testpb.Query/Echo", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -86,7 +78,7 @@ func _Query_Echo_Handler(srv interface{}, ctx context.Context, dec func(interfac
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Query_Echo_FullMethodName,
|
||||
FullMethod: "/testpb.Query/Echo",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(QueryServer).Echo(ctx, req.(*EchoRequest))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user