cosmossdk.io/client/v2@v2.0.0-beta.1/autocli/app.go (about) 1 package autocli 2 3 import ( 4 "github.com/spf13/cobra" 5 "google.golang.org/grpc" 6 "google.golang.org/protobuf/reflect/protoregistry" 7 8 autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" 9 "cosmossdk.io/client/v2/autocli/flag" 10 "cosmossdk.io/client/v2/autocli/keyring" 11 "cosmossdk.io/core/address" 12 "cosmossdk.io/core/appmodule" 13 "cosmossdk.io/depinject" 14 15 "github.com/cosmos/cosmos-sdk/client" 16 sdkflags "github.com/cosmos/cosmos-sdk/client/flags" 17 "github.com/cosmos/cosmos-sdk/runtime" 18 "github.com/cosmos/cosmos-sdk/x/auth/tx" 19 ) 20 21 // AppOptions are autocli options for an app. These options can be built via depinject based on an app config. Ex: 22 // Ex: 23 // 24 // var autoCliOpts autocli.AppOptions 25 // err := depinject.Inject(appConfig, &encodingConfig.InterfaceRegistry, &autoCliOpts) 26 // 27 // If depinject isn't used, options can be provided manually or extracted from modules and the address codec can be provided by the auth keeper. 28 // One method for extracting autocli options is via the github.com/cosmos/cosmos-sdk/runtime/services.ExtractAutoCLIOptions function. 29 type AppOptions struct { 30 depinject.In 31 32 // Modules are the AppModule implementations for the modules in the app. 33 Modules map[string]appmodule.AppModule 34 35 // ModuleOptions are autocli options to be used for modules instead of what 36 // is specified on the module's AppModule implementation. This allows an 37 // app to override module options if they are either not provided by a 38 // module or need to be improved. 39 ModuleOptions map[string]*autocliv1.ModuleOptions `optional:"true"` 40 41 // AddressCodec is the address codec to use for the app. 42 AddressCodec address.Codec 43 ValidatorAddressCodec runtime.ValidatorAddressCodec 44 ConsensusAddressCodec runtime.ConsensusAddressCodec 45 46 // Keyring is the keyring to use for client/v2. 47 Keyring keyring.Keyring `optional:"true"` 48 49 // ClientCtx contains the necessary information needed to execute the commands. 50 ClientCtx client.Context 51 52 // TxConfigOptions are the transactions config options. 53 TxConfigOpts tx.ConfigOptions 54 } 55 56 // EnhanceRootCommand enhances the provided root command with autocli AppOptions, 57 // only adding missing commands and doesn't override commands already 58 // in the root command. This allows for the graceful integration of autocli with 59 // existing app CLI commands where autocli simply automatically adds things that 60 // weren't manually provided. It does take into account custom commands 61 // provided by modules with the HasCustomQueryCommand or HasCustomTxCommand extension interface. 62 // Example Usage: 63 // 64 // var autoCliOpts autocli.AppOptions 65 // err := depinject.Inject(appConfig, &autoCliOpts) 66 // if err != nil { 67 // panic(err) 68 // } 69 // rootCmd := initRootCmd() 70 // err = autoCliOpts.EnhanceRootCommand(rootCmd) 71 func (appOptions AppOptions) EnhanceRootCommand(rootCmd *cobra.Command) error { 72 builder := &Builder{ 73 Builder: flag.Builder{ 74 TypeResolver: protoregistry.GlobalTypes, 75 FileResolver: appOptions.ClientCtx.InterfaceRegistry, 76 AddressCodec: appOptions.AddressCodec, 77 ValidatorAddressCodec: appOptions.ValidatorAddressCodec, 78 ConsensusAddressCodec: appOptions.ConsensusAddressCodec, 79 Keyring: appOptions.Keyring, 80 }, 81 ClientCtx: appOptions.ClientCtx, 82 TxConfigOpts: appOptions.TxConfigOpts, 83 GetClientConn: func(cmd *cobra.Command) (grpc.ClientConnInterface, error) { 84 return client.GetClientQueryContext(cmd) 85 }, 86 AddQueryConnFlags: sdkflags.AddQueryFlagsToCmd, 87 AddTxConnFlags: sdkflags.AddTxFlagsToCmd, 88 } 89 90 return appOptions.EnhanceRootCommandWithBuilder(rootCmd, builder) 91 } 92 93 func (appOptions AppOptions) EnhanceRootCommandWithBuilder(rootCmd *cobra.Command, builder *Builder) error { 94 if err := builder.ValidateAndComplete(); err != nil { 95 return err 96 } 97 98 // extract any custom commands from modules 99 customQueryCmds, customMsgCmds := map[string]*cobra.Command{}, map[string]*cobra.Command{} 100 for name, module := range appOptions.Modules { 101 if queryModule, ok := module.(HasCustomQueryCommand); ok { 102 queryCmd := queryModule.GetQueryCmd() 103 // filter any nil commands 104 if queryCmd != nil { 105 customQueryCmds[name] = queryCmd 106 } 107 } 108 if msgModule, ok := module.(HasCustomTxCommand); ok { 109 msgCmd := msgModule.GetTxCmd() 110 // filter any nil commands 111 if msgCmd != nil { 112 customMsgCmds[name] = msgCmd 113 } 114 } 115 } 116 117 if queryCmd := findSubCommand(rootCmd, "query"); queryCmd != nil { 118 if err := builder.enhanceCommandCommon(queryCmd, queryCmdType, appOptions, customQueryCmds); err != nil { 119 return err 120 } 121 } else { 122 queryCmd, err := builder.BuildQueryCommand(appOptions, customQueryCmds) 123 if err != nil { 124 return err 125 } 126 127 rootCmd.AddCommand(queryCmd) 128 } 129 130 if msgCmd := findSubCommand(rootCmd, "tx"); msgCmd != nil { 131 if err := builder.enhanceCommandCommon(msgCmd, msgCmdType, appOptions, customMsgCmds); err != nil { 132 return err 133 } 134 } else { 135 subCmd, err := builder.BuildMsgCommand(appOptions, customMsgCmds) 136 if err != nil { 137 return err 138 } 139 140 rootCmd.AddCommand(subCmd) 141 } 142 143 return nil 144 }