Skip to content

Commit

Permalink
feat: use viper standard for command inputs (#645)
Browse files Browse the repository at this point in the history
* feat: use viper standard for command inputs

* chore: update check logic for disk space (#647)

Signed-off-by: João Vanzuita <joao@kubeshop.io>
  • Loading branch information
João Paulo Vanzuita authored Nov 3, 2022
1 parent 635dc40 commit 23ebd1e
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 12 deletions.
4 changes: 0 additions & 4 deletions cmd/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,7 @@ func NewCommand() *cobra.Command {
localCmd.Flags().StringVar(&metaphorBranch, "metaphor-branch", "main", "metaphro application branch")
localCmd.Flags().StringVar(&gitOpsBranch, "gitops-branch", "main", "version/branch used on git clone - former: version-gitops flag")
localCmd.Flags().StringVar(&gitOpsRepo, "gitops-repo", "gitops", "")

localCmd.Flags().BoolVar(&enableConsole, "enable-console", true, "If hand-off screen will be presented on a browser UI")
// todo:
//initCmd.Flags().StringP("config", "c", "", "File to be imported to bootstrap configs")
//viper.BindPFlag("config.file", currentCommand.Flags().Lookup("config-load"))

return localCmd
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/local/prerun.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func validateLocal(cmd *cobra.Command, args []string) error {

// convert available disk size to GB format
availableDiskSize := float64(free) / humanize.GByte
if availableDiskSize > pkg.MinimumAvailableDiskSize {
if availableDiskSize < pkg.MinimumAvailableDiskSize {
return fmt.Errorf(
"there is not enough space to proceed with the installation, a minimum of %d GB is required to proceed",
pkg.MinimumAvailableDiskSize,
Expand Down
12 changes: 5 additions & 7 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"github.com/kubefirst/kubefirst/cmd/local"
"github.com/kubefirst/kubefirst/configs"
"os"

"github.com/kubefirst/kubefirst/internal/progressPrinter"
Expand All @@ -16,8 +17,11 @@ var rootCmd = &cobra.Command{
Long: `kubefirst management cluster installer provisions an
open source application delivery platform in under an hour.
checkout the docs at docs.kubefirst.io.`,
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
// wire viper config for flags for all commands
return configs.InitializeViperConfig(cmd)
},
Run: func(cmd *cobra.Command, args []string) {
//log.Println(viper.Get("name"))
fmt.Println("To learn more about kubefirst, run:")
fmt.Println(" kubefirst help")
},
Expand All @@ -38,11 +42,5 @@ func Execute() {

func init() {
cobra.OnInitialize()

// Cobra also supports local flags, which will only run, when this action is called directly.
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

// todo: temporary, move it into CLI tree
rootCmd.AddCommand(local.NewCommand())

}
99 changes: 99 additions & 0 deletions configs/viperConfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package configs

// code from: https://github.com/carolynvs/stingoftheviper

import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"strings"
)

// it follows Viper precedence:
// 1. explicit call to Set
// 2. flag
// 3. env
// 4. config
// 5. key/value store
// 6. default

// the input file that is able to provide is called kubefirst.yaml, and should be at the root folder, where the user has
// it's Kubefirst binary. Following the flag name convention is enough to have a Kubefirst config file.

// FLAGS VARIABLE
// example loading values from flags:
// go run . command-name --admin-email user@example.com

// ENVIRONMENT VARIABLE
// example loading environment variables:
// export KUBEFIRST_CLOUD=k3d
// command line commands loads the values from the environment variable and override the command flag.

// YAML
// example of a YAML Kubefirst file:
// admin-email: user@example.com
// cloud: k3d
// command line commands loads the value from the kubefirst.yaml and override the command flags.

const (
// The name of our config file, without the file extension because viper supports many different config file languages.
defaultConfigFilename = "kubefirst"

// The environment variable prefix of all environment variables bound to our command line flags.
// For example, --number is bound to STING_NUMBER.
envPrefix = "KUBEFIRST"
)

func InitializeViperConfig(cmd *cobra.Command) error {
v := viper.New()

// Set the base name of the config file, without the file extension.
v.SetConfigName(defaultConfigFilename)
v.SetConfigType("yaml")

// Set as many paths as you like where viper should look for the
// config file. We are only looking in the current working directory.
v.AddConfigPath(".")

// Attempt to read the config file, gracefully ignoring errors
// caused by a config file not being found. Return an error
// if we cannot parse the config file.
if err := v.ReadInConfig(); err != nil {
// It's okay if there isn't a config file
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
return err
}
}

// When we bind flags to environment variables expect that the
// environment variables are prefixed, e.g. a flag like --number
// binds to an environment variable STING_NUMBER. This helps
// avoid conflicts.
v.SetEnvPrefix(envPrefix)

// Bind to environment variables
// Works great for simple config names, but needs help for names
// like --favorite-color which we fix in the bindFlags function
v.AutomaticEnv()

// Bind the current command's flags to viper
bindFlags(cmd, v)

return nil
}

// Bind each cobra flag to its associated viper configuration (config file and environment variable)
func bindFlags(cmd *cobra.Command, v *viper.Viper) {
cmd.Flags().VisitAll(func(f *pflag.Flag) {
// Environment variables can't have dashes in them, so bind them to their equivalent
// keys with underscores, e.g. --favorite-color to STING_FAVORITE_COLOR
v.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))

// Apply the viper config value to the flag when the flag is not set and viper has a value
if !f.Changed && v.IsSet(f.Name) {
val := v.Get(f.Name)
cmd.Flags().Set(f.Name, fmt.Sprintf("%v", val))
}
})
}

0 comments on commit 23ebd1e

Please sign in to comment.