feat(cli): dynamically generate query CLI commands (#11725)

* WIP on auto-generating CLi

* WIP

* WIP

* WIP

* add pagination.go

* handle more flag types

* WIP on refactoring

* WIP

* working tests

* add docs

* echo all flags

* add repeated tests

* remove comment

* fix compositeListValue issue

Co-authored-by: Anil Kumar Kammari <anil@vitwit.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
Aaron Craelius 2022-04-27 18:24:42 -04:00 committed by GitHub
parent e44a4a9d80
commit 1c8a2d9069
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 5069 additions and 0 deletions

2
client/v2/Makefile Normal file
View File

@ -0,0 +1,2 @@
codegen:
@(cd internal; buf generate)

20
client/v2/cli/builder.go Normal file
View File

@ -0,0 +1,20 @@
package cli
import (
"context"
"google.golang.org/grpc"
"github.com/cosmos/cosmos-sdk/client/v2/cli/flag"
)
// Builder manages options for building CLI commands.
type Builder struct {
// flag.Builder embeds the flag builder and its options.
flag.Builder
// GetClientConn specifies how CLI commands will resolve a grpc.ClientConnInterface
// from a given context.
GetClientConn func(context.Context) grpc.ClientConnInterface
}

View File

@ -0,0 +1,40 @@
package flag
import (
"context"
"github.com/spf13/pflag"
"google.golang.org/protobuf/reflect/protoreflect"
)
type addressStringType struct{}
func (a addressStringType) NewValue(_ context.Context, _ *Builder) pflag.Value {
return &addressValue{}
}
func (a addressStringType) DefaultValue() string {
return ""
}
type addressValue struct {
value string
}
func (a addressValue) Get() protoreflect.Value {
return protoreflect.ValueOfString(a.value)
}
func (a addressValue) String() string {
return a.value
}
func (a *addressValue) Set(s string) error {
a.value = s
// TODO handle bech32 validation
return nil
}
func (a addressValue) Type() string {
return "bech32 account address key name"
}

View File

@ -0,0 +1,47 @@
package flag
import (
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
// Builder manages options for building pflag flags for protobuf messages.
type Builder struct {
// TypeResolver specifies how protobuf types will be resolved. If it is
// nil protoregistry.GlobalTypes will be used.
TypeResolver interface {
protoregistry.MessageTypeResolver
protoregistry.ExtensionTypeResolver
}
// FileResolver specifies how protobuf file descriptors will be resolved. If it is
// nil protoregistry.GlobalFiles will be used.
FileResolver protodesc.Resolver
messageFlagTypes map[protoreflect.FullName]Type
scalarFlagTypes map[string]Type
}
func (b *Builder) init() {
if b.messageFlagTypes == nil {
b.messageFlagTypes = map[protoreflect.FullName]Type{}
b.messageFlagTypes["google.protobuf.Timestamp"] = timestampType{}
b.messageFlagTypes["google.protobuf.Duration"] = durationType{}
}
if b.scalarFlagTypes == nil {
b.scalarFlagTypes = map[string]Type{}
b.scalarFlagTypes["cosmos.AddressString"] = addressStringType{}
}
}
func (b *Builder) DefineMessageFlagType(messageName protoreflect.FullName, flagType Type) {
b.init()
b.messageFlagTypes[messageName] = flagType
}
func (b *Builder) DefineScalarFlagType(scalarName string, flagType Type) {
b.init()
b.scalarFlagTypes[scalarName] = flagType
}

View File

@ -0,0 +1,52 @@
package flag
import (
"context"
"time"
"github.com/spf13/pflag"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/known/durationpb"
)
type durationType struct{}
func (t durationType) NewValue(context.Context, *Builder) pflag.Value {
return &durationValue{}
}
func (t durationType) DefaultValue() string {
return ""
}
type durationValue struct {
value *durationpb.Duration
}
func (t durationValue) Get() protoreflect.Value {
if t.value == nil {
return protoreflect.Value{}
}
return protoreflect.ValueOfMessage(t.value.ProtoReflect())
}
func (v durationValue) String() string {
if v.value == nil {
return ""
}
return v.value.AsDuration().String()
}
func (v *durationValue) Set(s string) error {
dur, err := time.ParseDuration(s)
if err != nil {
return err
}
v.value = durationpb.New(dur)
return nil
}
func (v durationValue) Type() string {
return "duration"
}

View File

@ -0,0 +1,74 @@
package flag
import (
"context"
"fmt"
"strings"
"github.com/iancoleman/strcase"
"github.com/spf13/pflag"
"google.golang.org/protobuf/reflect/protoreflect"
)
type enumType struct {
enum protoreflect.EnumDescriptor
}
func (b enumType) NewValue(context.Context, *Builder) pflag.Value {
val := &enumValue{
enum: b.enum,
valMap: map[string]protoreflect.EnumValueDescriptor{},
}
n := b.enum.Values().Len()
for i := 0; i < n; i++ {
valDesc := b.enum.Values().Get(i)
val.valMap[enumValueName(b.enum, valDesc)] = valDesc
}
return val
}
func (b enumType) DefaultValue() string {
defValue := ""
if def := b.enum.Values().ByNumber(0); def != nil {
defValue = enumValueName(b.enum, def)
}
return defValue
}
type enumValue struct {
enum protoreflect.EnumDescriptor
value protoreflect.EnumNumber
valMap map[string]protoreflect.EnumValueDescriptor
}
func (e enumValue) Get() protoreflect.Value {
return protoreflect.ValueOfEnum(e.value)
}
func enumValueName(enum protoreflect.EnumDescriptor, enumValue protoreflect.EnumValueDescriptor) string {
name := string(enumValue.Name())
name = strings.TrimPrefix(name, strcase.ToScreamingSnake(string(enum.Name()))+"_")
return strcase.ToKebab(name)
}
func (e enumValue) String() string {
return enumValueName(e.enum, e.enum.Values().ByNumber(e.value))
}
func (e *enumValue) Set(s string) error {
valDesc, ok := e.valMap[s]
if !ok {
return fmt.Errorf("%s is not a valid value for enum %s", s, e.enum.FullName())
}
e.value = valDesc.Number()
return nil
}
func (e enumValue) Type() string {
var vals []string
n := e.enum.Values().Len()
for i := 0; i < n; i++ {
vals = append(vals, enumValueName(e.enum, e.enum.Values().Get(i)))
}
return fmt.Sprintf("%s (%s)", e.enum.Name(), strings.Join(vals, " | "))
}

129
client/v2/cli/flag/field.go Normal file
View File

@ -0,0 +1,129 @@
package flag
import (
"context"
"fmt"
cosmos_proto "github.com/cosmos/cosmos-proto"
"github.com/spf13/pflag"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/cosmos/cosmos-sdk/client/v2/internal/util"
)
// FieldValueBinder wraps a flag value in a way that allows it to be bound
// to a particular field in a protobuf message.
type FieldValueBinder interface {
Bind(message protoreflect.Message, field protoreflect.FieldDescriptor)
}
// Options specifies options for specific flags.
type Options 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, options Options) FieldValueBinder {
if field.Kind() == protoreflect.MessageKind && field.Message().FullName() == "cosmos.base.query.v1beta1.PageRequest" {
return b.bindPageRequest(ctx, flagSet, field)
}
name := options.Prefix + util.DescriptorKebabName(field)
usage := util.DescriptorDocs(field)
shorthand := ""
if typ := b.resolveFlagType(field); typ != nil {
val := typ.NewValue(ctx, b)
flagSet.AddFlag(&pflag.Flag{
Name: name,
Shorthand: shorthand,
Usage: usage,
DefValue: typ.DefaultValue(),
Value: val,
})
switch val := val.(type) {
case SimpleValue:
return simpleValueBinder{val}
case ListValue:
return listValueBinder{val}
default:
panic(fmt.Errorf("%T does not implement SimpleValue or ListValue", val))
}
}
if field.IsList() {
if value := bindSimpleListFlag(flagSet, field.Kind(), name, shorthand, usage); value != nil {
return listValueBinder{value}
}
return nil
}
if value := bindSimpleFlag(flagSet, field.Kind(), name, shorthand, usage); value != nil {
return simpleValueBinder{value}
}
return nil
}
func (b *Builder) resolveFlagType(field protoreflect.FieldDescriptor) Type {
typ := b.resolveFlagTypeBasic(field)
if field.IsList() {
if typ != nil {
return compositeListType{simpleType: typ}
}
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.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
}
}
type simpleValueBinder struct {
SimpleValue
}
func (s simpleValueBinder) Bind(message protoreflect.Message, field protoreflect.FieldDescriptor) {
val := s.Get()
if val.IsValid() {
message.Set(field, val)
} else {
message.Clear(field)
}
}
type listValueBinder struct {
ListValue
}
func (s listValueBinder) Bind(message protoreflect.Message, field protoreflect.FieldDescriptor) {
s.AppendTo(message.NewField(field).List())
}

107
client/v2/cli/flag/list.go Normal file
View File

@ -0,0 +1,107 @@
package flag
import (
"context"
"fmt"
"github.com/spf13/pflag"
"google.golang.org/protobuf/reflect/protoreflect"
)
func bindSimpleListFlag(flagSet *pflag.FlagSet, kind protoreflect.Kind, name, shorthand, usage string) ListValue {
switch kind {
case protoreflect.StringKind:
val := flagSet.StringSliceP(name, shorthand, nil, usage)
return listValue(func(list protoreflect.List) {
for _, x := range *val {
list.Append(protoreflect.ValueOfString(x))
}
})
case protoreflect.BytesKind:
// TODO
return nil
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind,
protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
val := flagSet.UintSliceP(name, shorthand, nil, usage)
return listValue(func(list protoreflect.List) {
for _, x := range *val {
list.Append(protoreflect.ValueOfUint64(uint64(x)))
}
})
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind,
protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
val := flagSet.IntSliceP(name, shorthand, nil, usage)
return listValue(func(list protoreflect.List) {
for _, x := range *val {
list.Append(protoreflect.ValueOfInt64(int64(x)))
}
})
case protoreflect.BoolKind:
val := flagSet.BoolSliceP(name, shorthand, nil, usage)
return listValue(func(list protoreflect.List) {
for _, x := range *val {
list.Append(protoreflect.ValueOfBool(x))
}
})
default:
return nil
}
}
type listValue func(protoreflect.List)
func (f listValue) AppendTo(list protoreflect.List) {
f(list)
}
type compositeListType struct {
simpleType Type
}
func (t compositeListType) NewValue(ctx context.Context, opts *Builder) pflag.Value {
return &compositeListValue{
simpleType: t.simpleType,
values: nil,
ctx: ctx,
opts: opts,
}
}
func (t compositeListType) DefaultValue() string {
return ""
}
type compositeListValue struct {
simpleType Type
values []protoreflect.Value
ctx context.Context
opts *Builder
}
func (c compositeListValue) AppendTo(list protoreflect.List) {
for _, value := range c.values {
list.Append(value)
}
}
func (c compositeListValue) String() string {
if len(c.values) == 0 {
return ""
}
return fmt.Sprintf("%+v", c.values)
}
func (c *compositeListValue) Set(val string) error {
simpleVal := c.simpleType.NewValue(c.ctx, c.opts)
err := simpleVal.Set(val)
if err != nil {
return err
}
c.values = append(c.values, simpleVal.(SimpleValue).Get())
return nil
}
func (c compositeListValue) Type() string {
return fmt.Sprintf("%s (repeated)", c.simpleType.NewValue(c.ctx, c.opts).Type())
}

View File

@ -0,0 +1,64 @@
package flag
import (
"context"
"fmt"
"github.com/spf13/pflag"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/cosmos/cosmos-sdk/client/v2/internal/util"
)
type jsonMessageFlagType struct {
messageDesc protoreflect.MessageDescriptor
}
func (j jsonMessageFlagType) NewValue(_ context.Context, builder *Builder) pflag.Value {
return &jsonMessageFlagValue{
messageType: util.ResolveMessageType(builder.TypeResolver, j.messageDesc),
jsonMarshalOptions: protojson.MarshalOptions{Resolver: builder.TypeResolver},
jsonUnmarshalOptions: protojson.UnmarshalOptions{Resolver: builder.TypeResolver},
}
}
func (j jsonMessageFlagType) DefaultValue() string {
return ""
}
type jsonMessageFlagValue struct {
jsonMarshalOptions protojson.MarshalOptions
jsonUnmarshalOptions protojson.UnmarshalOptions
messageType protoreflect.MessageType
message proto.Message
}
func (j jsonMessageFlagValue) Get() protoreflect.Value {
if j.message == nil {
return protoreflect.Value{}
}
return protoreflect.ValueOfMessage(j.message.ProtoReflect())
}
func (j jsonMessageFlagValue) String() string {
if j.message == nil {
return ""
}
bz, err := j.jsonMarshalOptions.Marshal(j.message)
if err != nil {
return err.Error()
}
return string(bz)
}
func (j *jsonMessageFlagValue) Set(s string) error {
j.message = j.messageType.New().Interface()
return j.jsonUnmarshalOptions.Unmarshal([]byte(s), j.message)
}
func (j jsonMessageFlagValue) Type() string {
return fmt.Sprintf("%s (json)", j.messageType.Descriptor().FullName())
}

View File

@ -0,0 +1,20 @@
package flag
import (
"context"
"github.com/spf13/pflag"
"google.golang.org/protobuf/reflect/protoreflect"
"github.com/cosmos/cosmos-sdk/client/v2/internal/util"
)
func (b *Builder) bindPageRequest(ctx context.Context, flagSet *pflag.FlagSet, field protoreflect.FieldDescriptor) FieldValueBinder {
handler := b.AddMessageFlags(
ctx,
flagSet,
util.ResolveMessageType(b.TypeResolver, field.Message()),
Options{Prefix: "page-"},
)
return simpleValueBinder{handler}
}

View File

@ -0,0 +1,59 @@
package flag
import (
"context"
"fmt"
"github.com/spf13/pflag"
"google.golang.org/protobuf/reflect/protoreflect"
)
// AddMessageFlags adds flags for each field in the message to the flag set.
func (b *Builder) AddMessageFlags(ctx context.Context, set *pflag.FlagSet, messageType protoreflect.MessageType, options Options) *MessageBinder {
fields := messageType.Descriptor().Fields()
numFields := fields.Len()
handler := &MessageBinder{
messageType: messageType,
}
for i := 0; i < numFields; i++ {
field := fields.Get(i)
binder := b.AddFieldFlag(ctx, set, field, options)
if binder == nil {
fmt.Printf("unable to bind field %s to a flag, support will be added soon\n", field)
continue
}
handler.flagFieldPairs = append(handler.flagFieldPairs, struct {
binder FieldValueBinder
field protoreflect.FieldDescriptor
}{binder: binder, field: field})
}
return handler
}
// MessageBinder binds multiple flags in a flag set to a protobuf message.
type MessageBinder struct {
flagFieldPairs []struct {
binder FieldValueBinder
field protoreflect.FieldDescriptor
}
messageType protoreflect.MessageType
}
// BuildMessage builds and returns a new message for the bound flags.
func (m MessageBinder) BuildMessage() protoreflect.Message {
msg := m.messageType.New()
m.Bind(msg)
return msg
}
// Bind binds the flag values to an existing protobuf message.
func (m MessageBinder) Bind(msg protoreflect.Message) {
for _, pair := range m.flagFieldPairs {
pair.binder.Bind(msg, pair.field)
}
}
// Get calls BuildMessage and wraps the result in a protoreflect.Value.
func (m MessageBinder) Get() protoreflect.Value {
return protoreflect.ValueOfMessage(m.BuildMessage())
}

View File

@ -0,0 +1,54 @@
package flag
import (
"github.com/spf13/pflag"
"google.golang.org/protobuf/reflect/protoreflect"
)
func bindSimpleFlag(flagSet *pflag.FlagSet, kind protoreflect.Kind, name, shorthand, usage string) SimpleValue {
switch kind {
case protoreflect.BytesKind:
val := flagSet.BytesBase64P(name, shorthand, nil, usage)
return simpleValue(func() protoreflect.Value {
return protoreflect.ValueOfBytes(*val)
})
case protoreflect.StringKind:
val := flagSet.StringP(name, shorthand, "", usage)
return simpleValue(func() protoreflect.Value {
return protoreflect.ValueOfString(*val)
})
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
val := flagSet.Uint32P(name, shorthand, 0, usage)
return simpleValue(func() protoreflect.Value {
return protoreflect.ValueOfUint32(*val)
})
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
val := flagSet.Uint64P(name, shorthand, 0, usage)
return simpleValue(func() protoreflect.Value {
return protoreflect.ValueOfUint64(*val)
})
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
val := flagSet.Int32P(name, shorthand, 0, usage)
return simpleValue(func() protoreflect.Value {
return protoreflect.ValueOfInt32(*val)
})
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
val := flagSet.Int64P(name, shorthand, 0, usage)
return simpleValue(func() protoreflect.Value {
return protoreflect.ValueOfInt64(*val)
})
case protoreflect.BoolKind:
val := flagSet.BoolP(name, shorthand, false, usage)
return simpleValue(func() protoreflect.Value {
return protoreflect.ValueOfBool(*val)
})
default:
return nil
}
}
type simpleValue func() protoreflect.Value
func (f simpleValue) Get() protoreflect.Value {
return f()
}

View File

@ -0,0 +1,51 @@
package flag
import (
"context"
"time"
"github.com/spf13/pflag"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/known/timestamppb"
)
type timestampType struct{}
func (t timestampType) NewValue(context.Context, *Builder) pflag.Value {
return &timestampValue{}
}
func (t timestampType) DefaultValue() string {
return ""
}
type timestampValue struct {
value *timestamppb.Timestamp
}
func (t timestampValue) Get() protoreflect.Value {
if t.value == nil {
return protoreflect.Value{}
}
return protoreflect.ValueOfMessage(t.value.ProtoReflect())
}
func (v timestampValue) String() string {
if v.value == nil {
return ""
}
return v.value.AsTime().Format(time.RFC3339)
}
func (v *timestampValue) Set(s string) error {
t, err := time.Parse(time.RFC3339, s)
if err != nil {
return err
}
v.value = timestamppb.New(t)
return nil
}
func (v timestampValue) Type() string {
return "timestamp (RFC 3339)"
}

View File

@ -0,0 +1,18 @@
package flag
import (
"context"
"github.com/spf13/pflag"
)
// 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) pflag.Value
// DefaultValue is the default value for this type.
DefaultValue() string
}

View File

@ -0,0 +1,19 @@
package flag
import (
"google.golang.org/protobuf/reflect/protoreflect"
)
// SimpleValue wraps a simple (non-list and non-map) protobuf value.
type SimpleValue interface {
// Get returns the value.
Get() protoreflect.Value
}
// ListValue wraps a protobuf list/repeating value.
type ListValue interface {
// AppendTo appends the values to the provided list.
AppendTo(protoreflect.List)
}

87
client/v2/cli/query.go Normal file
View File

@ -0,0 +1,87 @@
package cli
import (
"fmt"
"github.com/iancoleman/strcase"
"github.com/spf13/cobra"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"github.com/cosmos/cosmos-sdk/client/v2/cli/flag"
"github.com/cosmos/cosmos-sdk/client/v2/internal/util"
)
// AddQueryServiceCommands adds a sub-command to the provided command for each
// method in the specified service and returns the command.
func (b *Builder) AddQueryServiceCommands(command *cobra.Command, serviceName protoreflect.FullName) *cobra.Command {
resolver := b.FileResolver
if resolver == nil {
resolver = protoregistry.GlobalFiles
}
descriptor, err := resolver.FindDescriptorByName(serviceName)
if err != nil {
panic(err)
}
service := descriptor.(protoreflect.ServiceDescriptor)
methods := service.Methods()
n := methods.Len()
for i := 0; i < n; i++ {
cmd := b.CreateQueryMethodCommand(methods.Get(i))
command.AddCommand(cmd)
}
return command
}
// CreateQueryMethodCommand creates a gRPC query command for the given service method.
func (b *Builder) CreateQueryMethodCommand(descriptor protoreflect.MethodDescriptor) *cobra.Command {
serviceDescriptor := descriptor.Parent().(protoreflect.ServiceDescriptor)
docs := util.DescriptorDocs(descriptor)
getClientConn := b.GetClientConn
methodName := fmt.Sprintf("/%s/%s", serviceDescriptor.FullName(), descriptor.Name())
inputDesc := descriptor.Input()
inputType := util.ResolveMessageType(b.TypeResolver, inputDesc)
outputType := util.ResolveMessageType(b.TypeResolver, descriptor.Output())
cmd := &cobra.Command{
Use: protoNameToCliName(descriptor.Name()),
Long: docs,
}
binder := b.AddMessageFlags(cmd.Context(), cmd.Flags(), inputType, flag.Options{})
jsonMarshalOptions := protojson.MarshalOptions{
Indent: " ",
UseProtoNames: true,
UseEnumNumbers: false,
EmitUnpopulated: true,
Resolver: b.TypeResolver,
}
cmd.RunE = func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
clientConn := getClientConn(ctx)
input := binder.BuildMessage()
output := outputType.New()
err := clientConn.Invoke(ctx, methodName, input.Interface(), output.Interface())
if err != nil {
return err
}
bz, err := jsonMarshalOptions.Marshal(output.Interface())
if err != nil {
return err
}
_, err = fmt.Fprintln(cmd.OutOrStdout(), string(bz))
return err
}
return cmd
}
func protoNameToCliName(name protoreflect.Name) string {
return strcase.ToKebab(string(name))
}

117
client/v2/cli/query_test.go Normal file
View File

@ -0,0 +1,117 @@
package cli
import (
"bytes"
"context"
"net"
"testing"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/testing/protocmp"
"gotest.tools/v3/assert"
"gotest.tools/v3/golden"
"github.com/cosmos/cosmos-sdk/client/v2/internal/testpb"
)
func testExec(t *testing.T, args ...string) *testClientConn {
server := grpc.NewServer()
testpb.RegisterQueryServer(server, &testEchoServer{})
listener, err := net.Listen("tcp", "127.0.0.1:0")
assert.NilError(t, err)
go server.Serve(listener)
defer server.GracefulStop()
clientConn, err := grpc.Dial(listener.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials()))
assert.NilError(t, err)
defer clientConn.Close()
conn := &testClientConn{
ClientConn: clientConn,
t: t,
out: &bytes.Buffer{},
}
b := &Builder{
GetClientConn: func(ctx context.Context) grpc.ClientConnInterface {
return conn
},
}
cmd := b.AddQueryServiceCommands(&cobra.Command{Use: "test"}, protoreflect.FullName(testpb.Query_ServiceDesc.ServiceName))
cmd.SetArgs(args)
cmd.SetOut(conn.out)
assert.NilError(t, cmd.Execute())
return conn
}
func TestEcho(t *testing.T) {
conn := testExec(t,
"echo",
"--a-bool",
"--an-enum", "one",
"--a-message", `{"bar":"abc", "baz":-3}`,
"--duration", "4h3s",
"--u-32", "27",
"--u-64", "3267246890",
"--i-32", "-253",
"--i-64", "-234602347",
"--str", "def",
"--timestamp", "2019-01-02T00:01:02Z",
"--a-coin", `{"denom":"foo","amount":"100000"}`,
"--an-address", "cosmossdghdsfoi2134sdgh",
"--bz", "c2RncXdlZndkZ3NkZw==",
"--page-count-total",
"--page-key", "MTIzNTQ4N3NnaGRhcw==",
"--page-limit", "1000",
"--page-offset", "10",
"--page-reverse",
"--bools", "true",
"--bools", "false,false,true",
"--enums", "one",
"--enums", "five",
"--enums", "two",
"--strings", "abc",
"--strings", "xyz",
"--strings", "xyz,qrs",
"--durations", "3s",
"--durations", "5s",
"--durations", "10h",
"--some-messages", "{}",
"--some-messages", `{"bar":"baz"}`,
"--some-messages", `{"baz":-1}`,
"--uints", "1,2,3",
"--uints", "4",
)
assert.DeepEqual(t, conn.lastRequest, conn.lastResponse.(*testpb.EchoResponse).Request, protocmp.Transform())
}
func TestHelp(t *testing.T) {
conn := testExec(t, "echo", "-h")
golden.Assert(t, conn.out.String(), "help.golden")
}
type testClientConn struct {
*grpc.ClientConn
t *testing.T
lastRequest interface{}
lastResponse interface{}
out *bytes.Buffer
}
func (t *testClientConn) Invoke(ctx context.Context, method string, args interface{}, reply interface{}, opts ...grpc.CallOption) error {
err := t.ClientConn.Invoke(ctx, method, args, reply, opts...)
t.lastRequest = args
t.lastResponse = reply
return err
}
type testEchoServer struct {
testpb.UnimplementedQueryServer
}
func (t testEchoServer) Echo(_ context.Context, request *testpb.EchoRequest) (*testpb.EchoResponse, error) {
return &testpb.EchoResponse{Request: request}, nil
}
var _ testpb.QueryServer = testEchoServer{}

29
client/v2/cli/testdata/help.golden vendored Normal file
View File

@ -0,0 +1,29 @@
Usage:
test echo [flags]
Flags:
--a-bool
--a-coin cosmos.base.v1beta1.Coin (json)
--a-message testpb.AMessage (json)
--an-address bech32 account address key name
--an-enum Enum (unspecified | one | two | five | neg-three) (default unspecified)
--bools bools (default [])
--bz bytesBase64
--duration duration
--durations duration (repeated)
--enums Enum (unspecified | one | two | five | neg-three) (repeated)
-h, --help help for echo
--i-32 int32
--i-64 int
--page-count-total
--page-key bytesBase64
--page-limit uint
--page-offset uint
--page-reverse
--some-messages testpb.AMessage (json) (repeated)
--str string
--strings strings
--timestamp timestamp (RFC 3339)
--u-32 uint32
--u-64 uint
--uints uints (default [])

26
client/v2/go.mod Normal file
View File

@ -0,0 +1,26 @@
module github.com/cosmos/cosmos-sdk/client/v2
go 1.18
require (
github.com/cosmos/cosmos-sdk/api v0.1.0
github.com/iancoleman/strcase v0.2.0
github.com/spf13/cobra v1.4.0
github.com/spf13/pflag v1.0.5
google.golang.org/grpc v1.45.0
google.golang.org/protobuf v1.28.0
gotest.tools/v3 v3.1.0
)
require (
github.com/cosmos/cosmos-proto v1.0.0-alpha7 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.6 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect
golang.org/x/text v0.3.5 // indirect
google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb // indirect
)

181
client/v2/go.sum Normal file
View File

@ -0,0 +1,181 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cosmos/cosmos-proto v1.0.0-alpha7 h1:yqYUOHF2jopwZh4dVQp3xgqwftE5/2hkrwIV6vkUbO0=
github.com/cosmos/cosmos-proto v1.0.0-alpha7/go.mod h1:dosO4pSAbJF8zWCzCoTWP7nNsjcvSUBQmniFxDg5daw=
github.com/cosmos/cosmos-sdk/api v0.1.0 h1:xfSKM0e9p+EJTMQnf5PbWE6VT8ruxTABIJ64Rd064dE=
github.com/cosmos/cosmos-sdk/api v0.1.0/go.mod h1:CupqQBskAOiTXO1XDZ/wrtWzN/wTxUvbQmOqdUhR8wI=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb h1:ZrsicilzPCS/Xr8qtBZZLpy4P9TYXAfl49ctG1/5tgw=
google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.1.0 h1:rVV8Tcg/8jHUkPUorwjaMTtemIMVXfIPKiOqnhEhakk=
gotest.tools/v3 v3.1.0/go.mod h1:fHy7eyTmJFO5bQbUsEGQ1v4m2J3Jz9eWL54TP2/ZuYQ=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU=

View File

@ -0,0 +1,16 @@
version: v1
managed:
enabled: true
go_package_prefix:
default: github.com/cosmos/cosmos-sdk/client/v2/internal
except:
- buf.build/cosmos/cosmos-proto
override:
buf.build/cosmos/cosmos-sdk: github.com/cosmos/cosmos-sdk/api
plugins:
- name: go-pulsar
out: .
opt: paths=source_relative
- name: go-grpc
out: .
opt: paths=source_relative

View File

@ -0,0 +1,23 @@
# Generated by buf. DO NOT EDIT.
version: v1
deps:
- remote: buf.build
owner: cosmos
repository: cosmos-proto
branch: main
commit: 1935555c206d4afb9e94615dfd0fad31
- remote: buf.build
owner: cosmos
repository: cosmos-sdk
branch: main
commit: 86d2a697b026488089f13a71ceb3815c
- remote: buf.build
owner: cosmos
repository: gogo-proto
branch: main
commit: bee5511075b7499da6178d9e4aaa628b
- remote: buf.build
owner: googleapis
repository: googleapis
branch: main
commit: 40f07f5b563941f2b20b991a7aedd53d

View File

@ -0,0 +1,12 @@
version: v1
deps:
- buf.build/cosmos/cosmos-sdk
- buf.build/cosmos/cosmos-proto
lint:
use:
- DEFAULT
except:
- PACKAGE_VERSION_SUFFIX
breaking:
ignore:
- testpb

View File

@ -0,0 +1,55 @@
syntax = "proto3";
package testpb;
import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "cosmos/base/v1beta1/coin.proto";
service Query {
// Echo returns the request in the response
rpc Echo(EchoRequest) returns (EchoResponse);
}
message EchoRequest {
// u32 is an uint32
uint32 u32 = 1;
uint64 u64 = 2;
string str = 3;
bytes bz = 4;
google.protobuf.Timestamp timestamp = 5;
google.protobuf.Duration duration = 6;
int32 i32 = 7;
int64 i64 = 10;
bool a_bool = 15;
Enum an_enum = 16;
AMessage a_message = 17;
cosmos.base.v1beta1.Coin a_coin = 18;
string an_address = 19 [(cosmos_proto.scalar) = "cosmos.AddressString"];
cosmos.base.query.v1beta1.PageRequest page = 20;
repeated bool bools = 21;
repeated uint32 uints = 22;
repeated string strings = 23;
repeated Enum enums = 24;
repeated google.protobuf.Duration durations = 25;
repeated AMessage some_messages = 26;
}
enum Enum {
ENUM_UNSPECIFIED = 0;
ENUM_ONE = 1;
ENUM_TWO = 2;
ENUM_FIVE = 5;
ENUM_NEG_THREE = -3;
}
message AMessage {
string bar = 1;
int32 baz = 2;
}
message EchoResponse {
EchoRequest request = 1;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,107 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc (unknown)
// source: testpb/query.proto
package testpb
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// 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.
type QueryClient interface {
// Echo returns the request in the response
Echo(ctx context.Context, in *EchoRequest, opts ...grpc.CallOption) (*EchoResponse, error)
}
type queryClient struct {
cc grpc.ClientConnInterface
}
func NewQueryClient(cc grpc.ClientConnInterface) QueryClient {
return &queryClient{cc}
}
func (c *queryClient) Echo(ctx context.Context, in *EchoRequest, opts ...grpc.CallOption) (*EchoResponse, error) {
out := new(EchoResponse)
err := c.cc.Invoke(ctx, "/testpb.Query/Echo", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// QueryServer is the server API for Query service.
// All implementations must embed UnimplementedQueryServer
// for forward compatibility
type QueryServer interface {
// Echo returns the request in the response
Echo(context.Context, *EchoRequest) (*EchoResponse, error)
mustEmbedUnimplementedQueryServer()
}
// UnimplementedQueryServer must be embedded to have forward compatible implementations.
type UnimplementedQueryServer struct {
}
func (UnimplementedQueryServer) Echo(context.Context, *EchoRequest) (*EchoResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented")
}
func (UnimplementedQueryServer) mustEmbedUnimplementedQueryServer() {}
// UnsafeQueryServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to QueryServer will
// result in compilation errors.
type UnsafeQueryServer interface {
mustEmbedUnimplementedQueryServer()
}
func RegisterQueryServer(s grpc.ServiceRegistrar, srv QueryServer) {
s.RegisterService(&Query_ServiceDesc, srv)
}
func _Query_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(EchoRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(QueryServer).Echo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/testpb.Query/Echo",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(QueryServer).Echo(ctx, req.(*EchoRequest))
}
return interceptor(ctx, in, info, handler)
}
// Query_ServiceDesc is the grpc.ServiceDesc for Query service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Query_ServiceDesc = grpc.ServiceDesc{
ServiceName: "testpb.Query",
HandlerType: (*QueryServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Echo",
Handler: _Query_Echo_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "testpb/query.proto",
}

View File

@ -0,0 +1,29 @@
package util
import (
"github.com/iancoleman/strcase"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/dynamicpb"
)
func DescriptorKebabName(descriptor protoreflect.Descriptor) string {
return strcase.ToKebab(string(descriptor.Name()))
}
func DescriptorDocs(descriptor protoreflect.Descriptor) string {
return descriptor.ParentFile().SourceLocations().ByDescriptor(descriptor).LeadingComments
}
func ResolveMessageType(resolver protoregistry.MessageTypeResolver, descriptor protoreflect.MessageDescriptor) protoreflect.MessageType {
if resolver == nil {
resolver = protoregistry.GlobalTypes
}
typ, err := resolver.FindMessageByName(descriptor.FullName())
if err == nil {
return typ
}
return dynamicpb.NewMessageType(descriptor)
}