2

Is there a way to remove a key/value pair from the loaded config file?

viper.Set("key", nil)

does not work

RoKK
  • 617
  • 8
  • 17
  • There's no way to remove things as far as I can tell either, but you could selectively set things. It's a bit more work, but it may be necessary in this case. Use `viper.New` to create a new `*viper.Viper` and load your config, range over the config settings, and for the settings you want enabled, use `viper.Set` to manually set them on the global `Viper` instance. This methodology can also be applied to other config sources as necessary, though merging them together will obviously involve more work (ideally you'd use the same priorities for your sources as viper does.) Just an idea. –  Sep 14 '18 at 22:40

3 Answers3

2

Try

delete(viper.Get("path.to.key").(map[string]interface{}), "key")

Example:

[backends]
  [backends.setibe]
    [backends.setibe.servers]
      [backends.setibe.servers.server0]
      url = "http://192.168.1.20:80"
      weight = 1
      [backends.setibe.servers.server1]
      url = "http://192.168.1.21:80"
      weight = 1

To delete "backends.setibe.servers.server1"

delete(viper.Get("backends.setibe.servers").(map[string]interface{}), "server2")
GuidoV
  • 44
  • 2
  • 1
    This did not seem to work for me with Viper 1.7.0, the latest version. – makeworld Jun 23 '20 at 20:01
  • TLDR; This is dangerous and doesn't work. This method doesn't work in tricky ways. If you `viper.Set` a key at all for the path then the `viper.Get` will return the map from the `override` list, which then won't let you delete any keys in the `config` list. So if your app adds and removes things, you may find it fails to delete with this method. – Will Brode May 11 '23 at 07:29
0

Building on the comment by @user539810, I have the following:

var rootCmd = &cobra.Command{
    //...
    PersistentPreRunE: writeConfig, //if --writeCfg, write viper config file and exit
}
func writeConfig(cmd *cobra.Command, args []string) error {
    if !writeCfg {
        return nil
    }
    cfg := viper.New()
    for k, v := range viper.AllSettings() {
        switch k {
        case "writecfg", "config", "dryrun":
            //do not propagate these
        default:
            //TODO: also check for zero values and exclude
            cfg.Set(k, v)
        }
    }
    if cfgFile == "" {
        filename := "." + os.Args[0] + ".yaml"
        home, err := os.UserHomeDir()
        cobra.CheckErr(err)
        cfgFile = filepath.Join(home, filename)
    }

    cfg.SetConfigFile(cfgFile)
    var err error
    if _, err = os.Stat(cfgFile); err != nil {
        err = os.WriteFile(cfgFile, nil, 0644)
        cobra.CheckErr(err)
    }
    err = cfg.WriteConfig()
    cobra.CheckErr(err)
    fmt.Println("config written successfully:")
    f, err := os.Open(cfgFile)
    cobra.CheckErr(err)
    defer f.Close()
    _, err = io.Copy(os.Stdout, f)
    cobra.CheckErr(err)
    os.Exit(0)
    return nil //unreachable
}
Mark
  • 1,035
  • 2
  • 11
  • 24
0
func Save(ignoredkeys ...string) error {
    file := viper.ConfigFileUsed()
    if len(file) == 0 {
        file = "./default.yml"
    }

    configMap := viper.AllSettings()
    for _, key := range ignoredkeys {
        delete(configMap, key)
    }

    content, err := yaml.Marshal(configMap)
    if err != nil {
        return err
    }

    fs.WriteTextFile(file, string(content))

    return nil
}

This will "flatten" all the config sources into one, then remove the key, then write the file.

Source: https://github.com/spf13/viper/pull/519#issuecomment-858683594

Will Brode
  • 1,026
  • 2
  • 10
  • 27