Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
96 changes: 93 additions & 3 deletions cmd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package config

import (
"encoding/json"
"errors"
"fmt"
"os"

Expand Down Expand Up @@ -54,9 +55,44 @@ func run() func(*cobra.Command, []string) error {

fmt.Fprint(cmd.OutOrStdout(), string(configJSON)+"\n")
case viper.GetBool(SetFlag):
fmt.Fprintln(cmd.OutOrStdout(), "called --set flag")
case viper.GetBool(UnsetFlag):
fmt.Fprintln(cmd.OutOrStdout(), "called --unset flag")
// flag needs two arguments: a key and value
if len(args)%2 != 0 {
return errors.New("flag needs an argument: --set")
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is the same error that cobra shows for a flag that requires a single value.

}

rawConfig, v, err := getRawConfig()
if err != nil {
return err
}

// add arg pairs to config
// where each argument is --set arg1 val1 --set arg2 val2
for i, a := range args {
if i%2 == 0 {
rawConfig[a] = struct{}{}
} else {
rawConfig[args[i-1]] = a
}
}

setKeyFn := func(key string, value interface{}, v *viper.Viper) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Using a filter function here will be more obvious in the next PR that supports --unset.

v.Set(key, value)
}

return writeConfig(config.NewConfig(rawConfig), v, setKeyFn)
case viper.IsSet(UnsetFlag):
config, v, err := getConfig()
if err != nil {
return err
}

unsetKeyFn := func(key string, value interface{}, v *viper.Viper) {
if key != viper.GetString("unset") {
v.Set(key, value)
}
}

return writeConfig(config, v, unsetKeyFn)
}

return nil
Expand Down Expand Up @@ -84,6 +120,27 @@ func getConfig() (config.ConfigFile, *viper.Viper, error) {
return c, v, nil
}

// getRawConfig builds a map of the values in the config file.
func getRawConfig() (map[string]interface{}, *viper.Viper, error) {
v, err := getViperWithConfigFile()
if err != nil {
return nil, nil, err
}

data, err := os.ReadFile(v.ConfigFileUsed())
if err != nil {
return nil, nil, err
}

config := make(map[string]interface{}, 0)
err = yaml.Unmarshal([]byte(data), &config)
if err != nil {
return nil, nil, err
}

return config, v, nil
}

// getViperWithConfigFile ensures the viper instance has a config file written to the filesystem.
// We want to write the file when someone runs a config command.
func getViperWithConfigFile() (*viper.Viper, error) {
Expand All @@ -105,3 +162,36 @@ func getViperWithConfigFile() (*viper.Viper, error) {

return v, nil
}

// writeConfig writes the values in config to the config file based on the filter function.
func writeConfig(
conf config.ConfigFile,
v *viper.Viper,
filterFn func(key string, value interface{}, v *viper.Viper),
) error {
// create a new viper instance since the existing one has the command name and flags already set,
// and these will get written to the config file.
newViper := viper.New()
newViper.SetConfigFile(v.ConfigFileUsed())

configYAML, err := yaml.Marshal(conf)
if err != nil {
return err
}
rawConfig := make(map[string]interface{})
err = yaml.Unmarshal(configYAML, &rawConfig)
if err != nil {
return err
}

for key, value := range rawConfig {
filterFn(key, value, newViper)
}

err = newViper.WriteConfig()
if err != nil {
return err
}

return nil
}
1 change: 1 addition & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func GetConfigPath() string {
}
configPath = filepath.Join(home, ".config")
}

return filepath.Join(configPath, "ldcli")
}

Expand Down