feat: Allow app developers to override default appConfig template (#9550)
<!-- The default pull request template is for types feat, fix, or refactor. For other templates, add one of the following parameters to the url: - template=docs.md - template=other.md --> ## Description Closes: #5540 <!-- Add a description of the changes that this PR introduces and the files that are the most critical to review. --> --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [x] included comments for [documenting Go code](https://blog.golang.org/godoc) - [x] updated the relevant documentation or specification - [x] reviewed "Files changed" and left comments if necessary - [x] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable)
This commit is contained in:
parent
899b097da4
commit
1c77766717
|
@ -60,7 +60,13 @@ The root command (called `rootCmd`) is what the user first types into the comman
|
|||
|
||||
Next is an example `rootCmd` function from the `simapp` application. It instantiates the root command, adds a [_persistent_ flag](#flags) and `PreRun` function to be run before every execution, and adds all of the necessary subcommands.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/simapp/simd/cmd/root.go#L37-L93
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/4eea4cafd3b8b1c2cd493886db524500c9dd745c/simapp/simd/cmd/root.go#L37-L150
|
||||
|
||||
`rootCmd` has a function called `initAppConfig()` which is useful for setting the application's custom configs.
|
||||
By default app uses Tendermint app config template from SDK, which can be over-written via `initAppConfig()`.
|
||||
Here's an example code to override default `appConfig` and `app.toml` template.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/4eea4cafd3b8b1c2cd493886db524500c9dd745c/simapp/simd/cmd/root.go#L84-L117
|
||||
|
||||
The root-level `status` and `keys` subcommands are common across most applications and do not interact with application state. The bulk of an application's functionality - what users can actually _do_ with it - is enabled by its `tx` and `query` commands.
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
tmos "github.com/tendermint/tendermint/libs/os"
|
||||
)
|
||||
|
||||
const defaultConfigTemplate = `# This is a TOML config file.
|
||||
const DefaultConfigTemplate = `# This is a TOML config file.
|
||||
# For more information, see https://github.com/toml-lang/toml
|
||||
|
||||
###############################################################################
|
||||
|
@ -210,7 +210,7 @@ func init() {
|
|||
|
||||
tmpl := template.New("appConfigFileTemplate")
|
||||
|
||||
if configTemplate, err = tmpl.Parse(defaultConfigTemplate); err != nil {
|
||||
if configTemplate, err = tmpl.Parse(DefaultConfigTemplate); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
@ -224,9 +224,21 @@ func ParseConfig(v *viper.Viper) (*Config, error) {
|
|||
return conf, err
|
||||
}
|
||||
|
||||
// SetConfigTemplate sets the custom app config template for
|
||||
// the application
|
||||
func SetConfigTemplate(customTemplate string) {
|
||||
var err error
|
||||
|
||||
tmpl := template.New("appConfigFileTemplate")
|
||||
|
||||
if configTemplate, err = tmpl.Parse(customTemplate); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// WriteConfigFile renders config using the template and writes it to
|
||||
// configFilePath.
|
||||
func WriteConfigFile(configFilePath string, config *Config) {
|
||||
func WriteConfigFile(configFilePath string, config interface{}) {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
if err := configTemplate.Execute(&buffer, config); err != nil {
|
||||
|
|
|
@ -22,6 +22,9 @@ value called `rpc.laddr` would be read from an environmental variable called
|
|||
Running the `InterceptConfigsPreRunHandler` also reads `app.toml`
|
||||
and `config.toml` from the home directory under the `config` directory.
|
||||
If `config.toml` or `app.toml` do not exist then those files are created
|
||||
and populated with default values.
|
||||
and populated with default values. `InterceptConfigsPreRunHandler` takes
|
||||
two parameters to set/update a custom template to create custom `app.toml`.
|
||||
If these parameters are empty, the server then creates a default template
|
||||
provided by the SDK.
|
||||
*/
|
||||
package server
|
||||
|
|
|
@ -99,10 +99,13 @@ func bindFlags(basename string, cmd *cobra.Command, v *viper.Viper) (err error)
|
|||
// application command. It will create a Viper literal and a default server
|
||||
// Context. The server Tendermint configuration will either be read and parsed
|
||||
// or created and saved to disk, where the server Context is updated to reflect
|
||||
// the Tendermint configuration. The Viper literal is used to read and parse
|
||||
// the application configuration. Command handlers can fetch the server Context
|
||||
// to get the Tendermint configuration or to get access to Viper.
|
||||
func InterceptConfigsPreRunHandler(cmd *cobra.Command) error {
|
||||
// the Tendermint configuration. It takes custom app config template and config
|
||||
// settings to create a custom Tendermint configuration. If the custom template
|
||||
// is empty, it uses default-template provided by the server. The Viper literal
|
||||
// is used to read and parse the application configuration. Command handlers can
|
||||
// fetch the server Context to get the Tendermint configuration or to get access
|
||||
// to Viper.
|
||||
func InterceptConfigsPreRunHandler(cmd *cobra.Command, customAppConfigTemplate string, customAppConfig interface{}) error {
|
||||
serverCtx := NewDefaultContext()
|
||||
|
||||
// Get the executable name and configure the viper instance so that environmental
|
||||
|
@ -123,7 +126,7 @@ func InterceptConfigsPreRunHandler(cmd *cobra.Command) error {
|
|||
serverCtx.Viper.AutomaticEnv()
|
||||
|
||||
// intercept configuration files, using both Viper instances separately
|
||||
config, err := interceptConfigs(serverCtx.Viper)
|
||||
config, err := interceptConfigs(serverCtx.Viper, customAppConfigTemplate, customAppConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -181,7 +184,7 @@ func SetCmdServerContext(cmd *cobra.Command, serverCtx *Context) error {
|
|||
// configuration file. The Tendermint configuration file is parsed given a root
|
||||
// Viper object, whereas the application is parsed with the private package-aware
|
||||
// viperCfg object.
|
||||
func interceptConfigs(rootViper *viper.Viper) (*tmcfg.Config, error) {
|
||||
func interceptConfigs(rootViper *viper.Viper, customAppTemplate string, customConfig interface{}) (*tmcfg.Config, error) {
|
||||
rootDir := rootViper.GetString(flags.FlagHome)
|
||||
configPath := filepath.Join(rootDir, "config")
|
||||
tmCfgFile := filepath.Join(configPath, "config.toml")
|
||||
|
@ -226,12 +229,22 @@ func interceptConfigs(rootViper *viper.Viper) (*tmcfg.Config, error) {
|
|||
|
||||
appCfgFilePath := filepath.Join(configPath, "app.toml")
|
||||
if _, err := os.Stat(appCfgFilePath); os.IsNotExist(err) {
|
||||
appConf, err := config.ParseConfig(rootViper)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse %s: %w", appCfgFilePath, err)
|
||||
}
|
||||
if customAppTemplate != "" {
|
||||
config.SetConfigTemplate(customAppTemplate)
|
||||
|
||||
config.WriteConfigFile(appCfgFilePath, appConf)
|
||||
if err = rootViper.Unmarshal(&customConfig); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse %s: %w", appCfgFilePath, err)
|
||||
}
|
||||
|
||||
config.WriteConfigFile(appCfgFilePath, customConfig)
|
||||
} else {
|
||||
appConf, err := config.ParseConfig(rootViper)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse %s: %w", appCfgFilePath, err)
|
||||
}
|
||||
|
||||
config.WriteConfigFile(appCfgFilePath, appConf)
|
||||
}
|
||||
}
|
||||
|
||||
rootViper.SetConfigType("toml")
|
||||
|
|
|
@ -20,7 +20,7 @@ var CancelledInPreRun = errors.New("Canelled in prerun")
|
|||
// Used in each test to run the function under test via Cobra
|
||||
// but to always halt the command
|
||||
func preRunETestImpl(cmd *cobra.Command, args []string) error {
|
||||
err := InterceptConfigsPreRunHandler(cmd)
|
||||
err := InterceptConfigsPreRunHandler(cmd, "", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
|
||||
"github.com/spf13/cast"
|
||||
"github.com/spf13/cobra"
|
||||
tmcli "github.com/tendermint/tendermint/libs/cli"
|
||||
|
@ -14,7 +15,7 @@ import (
|
|||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
config "github.com/cosmos/cosmos-sdk/client/config"
|
||||
"github.com/cosmos/cosmos-sdk/client/config"
|
||||
"github.com/cosmos/cosmos-sdk/client/debug"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
|
@ -66,7 +67,9 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) {
|
|||
return err
|
||||
}
|
||||
|
||||
return server.InterceptConfigsPreRunHandler(cmd)
|
||||
customAppTemplate, customAppConfig := initAppConfig()
|
||||
|
||||
return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig)
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -75,6 +78,45 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) {
|
|||
return rootCmd, encodingConfig
|
||||
}
|
||||
|
||||
// initAppConfig helps to override default appConfig template and configs.
|
||||
// return "", nil if no custom configuration is required for the application.
|
||||
func initAppConfig() (string, interface{}) {
|
||||
// The following code snippet is just for reference.
|
||||
|
||||
// WASMConfig defines configuration for the wasm module.
|
||||
type WASMConfig struct {
|
||||
// This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries
|
||||
QueryGasLimit uint64 `mapstructure:"query_gas_limit"`
|
||||
|
||||
// Address defines the gRPC-web server to listen on
|
||||
LruSize uint64 `mapstructure:"lru_size"`
|
||||
}
|
||||
|
||||
type CustomAppConfig struct {
|
||||
serverconfig.Config
|
||||
|
||||
WASM WASMConfig `mapstructure:"wasm"`
|
||||
}
|
||||
|
||||
customAppConfig := CustomAppConfig{
|
||||
Config: *serverconfig.DefaultConfig(),
|
||||
WASM: WASMConfig{
|
||||
LruSize: 1,
|
||||
QueryGasLimit: 300000,
|
||||
},
|
||||
}
|
||||
|
||||
customAppTemplate := serverconfig.DefaultConfigTemplate + `
|
||||
[wasm]
|
||||
# This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries
|
||||
query_gas_limit = 300000
|
||||
# This is the number of wasm vm instances we keep cached in memory for speed-up
|
||||
# Warning: this is currently unstable and may lead to crashes, best to keep for 0 unless testing locally
|
||||
lru_size = 0`
|
||||
|
||||
return customAppTemplate, customAppConfig
|
||||
}
|
||||
|
||||
func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) {
|
||||
cfg := sdk.GetConfig()
|
||||
cfg.Seal()
|
||||
|
|
Loading…
Reference in New Issue