cosmossdk.io/client/v2@v2.0.0-beta.1/autocli/flag/messager_binder.go (about) 1 package flag 2 3 import ( 4 "fmt" 5 6 "github.com/spf13/cobra" 7 "github.com/spf13/pflag" 8 "google.golang.org/protobuf/reflect/protoreflect" 9 ) 10 11 // SignerInfo contains information about the signer field. 12 // That field is special because it needs to be known for signing. 13 // This struct keeps track of the field name and whether it is a flag. 14 // IsFlag and PositionalArgIndex are mutually exclusive. 15 type SignerInfo struct { 16 PositionalArgIndex int 17 IsFlag bool 18 FieldName string 19 } 20 21 // MessageBinder binds multiple flags in a flag set to a protobuf message. 22 type MessageBinder struct { 23 CobraArgs cobra.PositionalArgs 24 SignerInfo SignerInfo 25 26 positionalFlagSet *pflag.FlagSet 27 positionalArgs []fieldBinding 28 hasVarargs bool 29 hasOptional bool 30 mandatoryArgUntil int 31 32 flagBindings []fieldBinding 33 messageType protoreflect.MessageType 34 } 35 36 // BuildMessage builds and returns a new message for the bound flags. 37 func (m MessageBinder) BuildMessage(positionalArgs []string) (protoreflect.Message, error) { 38 msg := m.messageType.New() 39 err := m.Bind(msg, positionalArgs) 40 return msg, err 41 } 42 43 // Bind binds the flag values to an existing protobuf message. 44 func (m MessageBinder) Bind(msg protoreflect.Message, positionalArgs []string) error { 45 // first set positional args in the positional arg flag set 46 n := len(positionalArgs) 47 for i := range m.positionalArgs { 48 if i == n { 49 break 50 } 51 52 name := fmt.Sprintf("%d", i) 53 if i == m.mandatoryArgUntil && m.hasVarargs { 54 for _, v := range positionalArgs[i:] { 55 if err := m.positionalFlagSet.Set(name, v); err != nil { 56 return err 57 } 58 } 59 } else { 60 if err := m.positionalFlagSet.Set(name, positionalArgs[i]); err != nil { 61 return err 62 } 63 } 64 } 65 66 // bind positional arg values to the message 67 for _, arg := range m.positionalArgs { 68 if err := arg.bind(msg); err != nil { 69 return err 70 } 71 } 72 73 // bind flag values to the message 74 for _, binding := range m.flagBindings { 75 if err := binding.bind(msg); err != nil { 76 return err 77 } 78 } 79 80 return nil 81 } 82 83 // Get calls BuildMessage and wraps the result in a protoreflect.Value. 84 func (m MessageBinder) Get(protoreflect.Value) (protoreflect.Value, error) { 85 msg, err := m.BuildMessage(nil) 86 return protoreflect.ValueOfMessage(msg), err 87 } 88 89 type fieldBinding struct { 90 hasValue HasValue 91 field protoreflect.FieldDescriptor 92 } 93 94 func (f fieldBinding) bind(msg protoreflect.Message) error { 95 field := f.field 96 val, err := f.hasValue.Get(msg.NewField(field)) 97 if err != nil { 98 return err 99 } 100 101 if field.IsMap() { 102 return nil 103 } 104 105 if msg.IsValid() && val.IsValid() { 106 msg.Set(f.field, val) 107 } 108 109 return nil 110 }