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  }