package cli import ( "errors" "fmt" "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" "github.com/spf13/viper" ) // configName is the base name of the optional configuration file looked // up in the config directory; viper tries every extension it supports, so // ~/.sneak.yaml, ~/.sneak.json, ~/.sneak.toml, and so on all work. const configName = ".sneak" // loadConfig runs before every command. It reads the optional // configuration file into a.config and makes environment variables // available through it. The file is the one named by --config, or else // configName in Params.ConfigDir, which defaults to the user's home // directory. A missing default file is not an error; a file that is named // explicitly but missing, or one that cannot be parsed, is. func (a *app) loadConfig(cmd *cobra.Command, _ []string) error { configDir := a.params.ConfigDir if configDir == "" { home, err := homedir.Dir() if err != nil { return fmt.Errorf("finding home directory: %w", err) } configDir = home } config := viper.New() config.AddConfigPath(configDir) config.SetConfigName(configName) config.AutomaticEnv() if a.configFile != "" { config.SetConfigFile(a.configFile) } err := config.ReadInConfig() _, isNotFound := errors.AsType[viper.ConfigFileNotFoundError](err) if isNotFound { a.config = config return nil } if err != nil { return fmt.Errorf("reading config file: %w", err) } a.config = config _, err = fmt.Fprintln( cmd.ErrOrStderr(), "Using config file:", config.ConfigFileUsed(), ) return err } // configFileUsed returns the path of the configuration file that // loadConfig read, or an empty string if there was none. func (a *app) configFileUsed() string { if a.config == nil { return "" } return a.config.ConfigFileUsed() }