diff --git a/changelog.md b/changelog.md index 6522299203..518029deda 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,7 @@ ### Fixes +- [#3827](https://github.com/ignite/cli/pull/3827) Change ignite apps to be able to run in any directory - [#3831](https://github.com/ignite/cli/pull/3831) Correct ignite app gRPC server stop memory issue - [#3825](https://github.com/ignite/cli/pull/3825) Fix a minor Keplr type-checking bug in TS client - [#3836](https://github.com/ignite/cli/pull/3836) Add missing IBC commands for scaffolded chain diff --git a/ignite/cmd/plugin.go b/ignite/cmd/plugin.go index f7d4d4fb1f..7284e345ed 100644 --- a/ignite/cmd/plugin.go +++ b/ignite/cmd/plugin.go @@ -16,6 +16,7 @@ import ( "github.com/ignite/cli/v28/ignite/pkg/cliui" "github.com/ignite/cli/v28/ignite/pkg/cliui/icons" "github.com/ignite/cli/v28/ignite/pkg/cosmosanalysis" + "github.com/ignite/cli/v28/ignite/pkg/gomodule" "github.com/ignite/cli/v28/ignite/pkg/xgit" "github.com/ignite/cli/v28/ignite/services/plugin" ) @@ -197,8 +198,6 @@ func linkPluginHook(rootCmd *cobra.Command, p *plugin.Plugin, hook *plugin.Hook) preRun := cmd.PreRunE cmd.PreRunE = func(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() - if preRun != nil { err := preRun(cmd, args) if err != nil { @@ -206,12 +205,15 @@ func linkPluginHook(rootCmd *cobra.Command, p *plugin.Plugin, hook *plugin.Hook) } } - execHook := newExecutedHook(hook, cmd, args) + // Get chain when the plugin runs inside an blockchain app c, err := newChainWithHomeFlags(cmd) - if err != nil { + if err != nil && !errors.Is(err, gomodule.ErrGoModNotFound) { return err } - err = p.Interface.ExecuteHookPre(ctx, execHook, plugin.NewClientAPI(c)) + + ctx := cmd.Context() + execHook := newExecutedHook(hook, cmd, args) + err = p.Interface.ExecuteHookPre(ctx, execHook, plugin.NewClientAPI(plugin.WithChain(c))) if err != nil { return fmt.Errorf("app %q ExecuteHookPre() error: %w", p.Path, err) } @@ -225,13 +227,15 @@ func linkPluginHook(rootCmd *cobra.Command, p *plugin.Plugin, hook *plugin.Hook) err := runCmd(cmd, args) // if the command has failed the `PostRun` will not execute. here we execute the cleanup step before returnning. if err != nil { - ctx := cmd.Context() - execHook := newExecutedHook(hook, cmd, args) + // Get chain when the plugin runs inside an blockchain app c, err := newChainWithHomeFlags(cmd) - if err != nil { + if err != nil && !errors.Is(err, gomodule.ErrGoModNotFound) { return err } - err = p.Interface.ExecuteHookCleanUp(ctx, execHook, plugin.NewClientAPI(c)) + + ctx := cmd.Context() + execHook := newExecutedHook(hook, cmd, args) + err = p.Interface.ExecuteHookCleanUp(ctx, execHook, plugin.NewClientAPI(plugin.WithChain(c))) if err != nil { cmd.Printf("app %q ExecuteHookCleanUp() error: %v", p.Path, err) } @@ -245,16 +249,17 @@ func linkPluginHook(rootCmd *cobra.Command, p *plugin.Plugin, hook *plugin.Hook) postCmd := cmd.PostRunE cmd.PostRunE = func(cmd *cobra.Command, args []string) error { - ctx := cmd.Context() - execHook := newExecutedHook(hook, cmd, args) - + // Get chain when the plugin runs inside an blockchain app c, err := newChainWithHomeFlags(cmd) - if err != nil { + if err != nil && !errors.Is(err, gomodule.ErrGoModNotFound) { return err } + ctx := cmd.Context() + execHook := newExecutedHook(hook, cmd, args) + defer func() { - err := p.Interface.ExecuteHookCleanUp(ctx, execHook, plugin.NewClientAPI(c)) + err := p.Interface.ExecuteHookCleanUp(ctx, execHook, plugin.NewClientAPI(plugin.WithChain(c))) if err != nil { cmd.Printf("app %q ExecuteHookCleanUp() error: %v", p.Path, err) } @@ -268,7 +273,7 @@ func linkPluginHook(rootCmd *cobra.Command, p *plugin.Plugin, hook *plugin.Hook) } } - err = p.Interface.ExecuteHookPost(ctx, execHook, plugin.NewClientAPI(c)) + err = p.Interface.ExecuteHookPost(ctx, execHook, plugin.NewClientAPI(plugin.WithChain(c))) if err != nil { return fmt.Errorf("app %q ExecuteHookPost() error : %w", p.Path, err) } @@ -331,6 +336,13 @@ func linkPluginCmd(rootCmd *cobra.Command, p *plugin.Plugin, pluginCmd *plugin.C newCmd.RunE = func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() return clictx.Do(ctx, func() error { + // Get chain when the plugin runs inside an blockchain app + c, err := newChainWithHomeFlags(cmd) + if err != nil && !errors.Is(err, gomodule.ErrGoModNotFound) { + return err + } + + // Call the plugin Execute execCmd := &plugin.ExecutedCommand{ Use: cmd.Use, Path: cmd.CommandPath(), @@ -339,12 +351,8 @@ func linkPluginCmd(rootCmd *cobra.Command, p *plugin.Plugin, pluginCmd *plugin.C With: p.With, } execCmd.ImportFlags(cmd) - // Call the plugin Execute - c, err := newChainWithHomeFlags(cmd) - if err != nil { - return err - } - err = p.Interface.Execute(ctx, execCmd, plugin.NewClientAPI(c)) + err = p.Interface.Execute(ctx, execCmd, plugin.NewClientAPI(plugin.WithChain(c))) + // NOTE(tb): This pause gives enough time for go-plugin to sync the // output from stdout/stderr of the plugin. Without that pause, this // output can be discarded and not printed in the user console. diff --git a/ignite/services/plugin/client_api.go b/ignite/services/plugin/client_api.go index 6bfde13ccf..13ecf2549b 100644 --- a/ignite/services/plugin/client_api.go +++ b/ignite/services/plugin/client_api.go @@ -2,8 +2,12 @@ package plugin import ( "context" + "errors" ) +// ErrAppChainNotFound indicates that the plugin command is not running inside a blockchain app. +var ErrAppChainNotFound = errors.New("blockchain app not found") + type Chainer interface { // AppPath returns the configured App's path. AppPath() string @@ -18,30 +22,60 @@ type Chainer interface { RPCPublicAddress() (string, error) } +// APIOption defines options for the client API. +type APIOption func(*apiOptions) + +type apiOptions struct { + chain Chainer +} + +// WithChain configures the chain to use for the client API. +func WithChain(c Chainer) APIOption { + return func(o *apiOptions) { + o.chain = c + } +} + // NewClientAPI creates a new app ClientAPI. -func NewClientAPI(c Chainer) ClientAPI { - return clientAPI{chain: c} +func NewClientAPI(options ...APIOption) ClientAPI { + o := apiOptions{} + for _, apply := range options { + apply(&o) + } + return clientAPI{o} } type clientAPI struct { - chain Chainer + o apiOptions } func (api clientAPI) GetChainInfo(context.Context) (*ChainInfo, error) { - chainID, err := api.chain.ID() + chain, err := api.getChain() + if err != nil { + return nil, err + } + + chainID, err := chain.ID() if err != nil { return nil, err } - rpc, err := api.chain.RPCPublicAddress() + rpc, err := chain.RPCPublicAddress() if err != nil { return nil, err } return &ChainInfo{ ChainId: chainID, - AppPath: api.chain.AppPath(), - ConfigPath: api.chain.ConfigPath(), + AppPath: chain.AppPath(), + ConfigPath: chain.ConfigPath(), RpcAddress: rpc, }, nil } + +func (api clientAPI) getChain() (Chainer, error) { + if api.o.chain == nil { + return nil, ErrAppChainNotFound + } + return api.o.chain, nil +}