Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(simapp/v2): full AutoCLI support #22410

Merged
merged 16 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 74 additions & 4 deletions client/v2/autocli/app.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package autocli

import (
"github.com/cosmos/gogoproto/proto"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"google.golang.org/protobuf/reflect/protoregistry"
Expand All @@ -9,20 +10,23 @@ import (
"cosmossdk.io/client/v2/autocli/flag"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
"cosmossdk.io/x/tx/signing"

"github.com/cosmos/cosmos-sdk/client"
sdkflags "github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec/types"
)

// AppOptions are autocli options for an app. These options can be built via depinject based on an app config. Ex:
// Options are input options for an autocli enabled app. These options can be built via depinject based on an app config.
// Ex:
//
// var autoCliOpts autocli.AppOptions
// err := depinject.Inject(appConfig, &encodingConfig.InterfaceRegistry, &autoCliOpts)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should update this, to show that ProvideAppOptions is required in the app config

//
// 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.
// One method for extracting autocli options is via the github.com/cosmos/cosmos-sdk/runtime/services.ExtractAutoCLIOptions function.
type AppOptions struct {
type Options struct {
depinject.In

// Modules are the AppModule implementations for the modules in the app.
Expand All @@ -38,6 +42,24 @@ type AppOptions struct {
ClientCtx client.Context
}

// AppOptions are the autocli options for an app.
type AppOptions struct {
Modules map[string]appmodule.AppModule
ModuleOptions map[string]*autocliv1.ModuleOptions
ClientCtx client.Context

skipValidation bool
}

// ProvideAppOptions returns AppOptions with the provided Options.
func ProvideAppOptions(options Options) AppOptions {
return AppOptions{
Modules: options.Modules,
ModuleOptions: options.ModuleOptions,
ClientCtx: options.ClientCtx,
}
}

// EnhanceRootCommand enhances the provided root command with autocli AppOptions,
// only adding missing commands and doesn't override commands already
// in the root command. This allows for the graceful integration of autocli with
Expand Down Expand Up @@ -73,8 +95,10 @@ func (appOptions AppOptions) EnhanceRootCommand(rootCmd *cobra.Command) error {
}

func (appOptions AppOptions) EnhanceRootCommandWithBuilder(rootCmd *cobra.Command, builder *Builder) error {
if err := builder.ValidateAndComplete(); err != nil {
return err
if !appOptions.skipValidation {
if err := builder.ValidateAndComplete(); err != nil {
return err
}
}

// extract any custom commands from modules
Expand Down Expand Up @@ -124,3 +148,49 @@ func (appOptions AppOptions) EnhanceRootCommandWithBuilder(rootCmd *cobra.Comman

return nil
}

// NewAppOptionsFromConfig returns AppOptions for an app based on the provided modulesConfig and moduleOptions.
// It returns an AppOptions instance usable for CLI parsing but not execution. For an execution usable AppOptions
// see ProvideAppOptions, which expects input to be filled by depinject.
func NewAppOptionsFromConfig(
modulesConfig depinject.Config,
moduleOptions map[string]*autocliv1.ModuleOptions,
) (AppOptions, error) {
interfaceRegistry, err := types.NewInterfaceRegistryWithOptions(types.InterfaceRegistryOptions{
ProtoFiles: proto.HybridResolver,
SigningOptions: signing.Options{
AddressCodec: nopAddressCodec{},
ValidatorAddressCodec: nopAddressCodec{},
},
})
if err != nil {
return AppOptions{}, err
}
kocubinski marked this conversation as resolved.
Show resolved Hide resolved
cfg := struct {
depinject.In
Modules map[string]appmodule.AppModule
}{
Modules: nil,
}
err = depinject.Inject(depinject.Configs(
modulesConfig,
depinject.Supply(
log.NewNopLogger(),
)), &cfg)
if err != nil {
return AppOptions{}, err
}

return AppOptions{
Modules: cfg.Modules,
ClientCtx: client.Context{InterfaceRegistry: interfaceRegistry},
ModuleOptions: moduleOptions,
skipValidation: true,
}, nil
}
kocubinski marked this conversation as resolved.
Show resolved Hide resolved

type nopAddressCodec struct{}

func (nopAddressCodec) StringToBytes(_ string) ([]byte, error) { return nil, nil }

func (nopAddressCodec) BytesToString(_ []byte) (string, error) { return "", nil }
2 changes: 1 addition & 1 deletion client/v2/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ require (
cosmossdk.io/collections v0.4.1-0.20241104084251-838f1557af0a // indirect
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 // indirect
cosmossdk.io/errors v1.0.1 // indirect
cosmossdk.io/log v1.4.1 // indirect
cosmossdk.io/log v1.4.1
cosmossdk.io/math v1.3.0
cosmossdk.io/schema v0.3.1-0.20241010135032-192601639cac // indirect
cosmossdk.io/store v1.1.1-0.20240418092142-896cdf1971bc // indirect
Expand Down
3 changes: 3 additions & 0 deletions simapp/v2/app_di.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
_ "embed"
"fmt"

"cosmossdk.io/client/v2/autocli"
"cosmossdk.io/core/registry"
"cosmossdk.io/core/server"
"cosmossdk.io/core/transaction"
Expand Down Expand Up @@ -58,6 +59,8 @@ func AppConfig() depinject.Config {
multisigdepinject.ProvideAccount,
basedepinject.ProvideAccount,
lockupdepinject.ProvideAllLockupAccounts,
// autocli
autocli.ProvideAppOptions,

// provide base account options
basedepinject.ProvideSecp256K1PubKey,
Expand Down
19 changes: 15 additions & 4 deletions simapp/v2/simdv2/cmd/root_di.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@ func NewRootCmd[T transaction.Tx](
return nil, err
}

nodeCmds := nodeservice.NewNodeCommands()
autoCLIModuleOpts := make(map[string]*autocliv1.ModuleOptions)
autoCLIModuleOpts[nodeCmds.Name()] = nodeCmds.AutoCLIOptions()
autoCliOpts, err := autocli.NewAppOptionsFromConfig(
depinject.Configs(simapp.AppConfig(), depinject.Supply(runtime.GlobalConfig{})),
autoCLIModuleOpts,
)
if err != nil {
return nil, err
}

if err = autoCliOpts.EnhanceRootCommand(rootCommand); err != nil {
return nil, err
}
kocubinski marked this conversation as resolved.
Show resolved Hide resolved
subCommand, configMap, logger, err := factory.ParseCommand(rootCommand, args)
if err != nil {
if errors.Is(err, pflag.ErrHelp) {
Expand All @@ -48,7 +62,6 @@ func NewRootCmd[T transaction.Tx](
}

var (
autoCliOpts autocli.AppOptions
moduleManager *runtime.MM[T]
clientCtx client.Context
simApp *simapp.SimApp[T]
Expand Down Expand Up @@ -93,9 +106,7 @@ func NewRootCmd[T transaction.Tx](
if err != nil {
return nil, err
}
nodeCmds := nodeservice.NewNodeCommands()
autoCliOpts.ModuleOptions = make(map[string]*autocliv1.ModuleOptions)
autoCliOpts.ModuleOptions[nodeCmds.Name()] = nodeCmds.AutoCLIOptions()
autoCliOpts.ModuleOptions = autoCLIModuleOpts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove duplicate root command enhancement

The root command is being enhanced with AutoCLI options twice: once at the beginning of the function and again here. This could lead to unexpected behavior or duplicate command registration.

Remove the first enhancement at lines 52-55 and keep only this final enhancement that occurs after all options are properly configured.

-	if err = autoCliOpts.EnhanceRootCommand(rootCommand); err != nil {
-		return rootCommand, nil
-	}

Committable suggestion skipped: line range outside the PR's diff.

if err := autoCliOpts.EnhanceRootCommand(rootCommand); err != nil {
return nil, err
}
Expand Down
Loading