From 351bfe9719e59c39c308342edbf087a6cb65f30b Mon Sep 17 00:00:00 2001 From: Matti R Date: Tue, 3 Dec 2019 10:46:17 -0500 Subject: [PATCH] loop through ini sections pass tests write out ini file & tests go fmt Update viper_test.go fix test gofmt --- viper.go | 38 ++++++++++++++++++++++++++++++++-- viper_test.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 91 insertions(+), 4 deletions(-) diff --git a/viper.go b/viper.go index a475e95..6014bf7 100644 --- a/viper.go +++ b/viper.go @@ -47,6 +47,7 @@ import ( jww "github.com/spf13/jwalterweatherman" "github.com/spf13/pflag" "github.com/subosito/gotenv" + "gopkg.in/ini.v1" ) // ConfigMarshalError happens when failing to marshal the configuration. @@ -240,7 +241,7 @@ func New() *Viper { // can use it in their testing as well. func Reset() { v = New() - SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "dotenv", "env"} + SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "dotenv", "env", "ini"} SupportedRemoteProviders = []string{"etcd", "consul"} } @@ -279,7 +280,7 @@ type RemoteProvider interface { } // SupportedExts are universally supported extensions. -var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "dotenv", "env"} +var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "dotenv", "env", "ini"} // SupportedRemoteProviders are universally supported remote providers. var SupportedRemoteProviders = []string{"etcd", "consul"} @@ -1462,6 +1463,23 @@ func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error { // set innermost value deepestMap[lastKey] = value } + + case "ini": + cfg := ini.Empty() + err := cfg.Append(buf.Bytes()) + if err != nil { + return ConfigParseError{err} + } + sections := cfg.Sections() + for i := 0; i < len(sections); i++ { + section := sections[i] + keys := section.Keys() + for j := 0; j < len(keys); j++ { + key := keys[j] + value := cfg.Section(section.Name()).Key(key.Name()).String() + c[section.Name()+"."+key.Name()] = value + } + } } insensitiviseMap(c) @@ -1545,6 +1563,22 @@ func (v *Viper) marshalWriter(f afero.File, configType string) error { if _, err = f.WriteString(string(b)); err != nil { return ConfigMarshalError{err} } + + case "ini": + keys := v.AllKeys() + cfg := ini.Empty() + ini.PrettyFormat = false + for i := 0; i < len(keys); i++ { + key := keys[i] + lastSep := strings.LastIndex(key, ".") + sectionName := key[:(lastSep)] + keyName := key[(lastSep + 1):] + if sectionName == "default" { + sectionName = "" + } + cfg.Section(sectionName).Key(keyName).SetValue(Get(key).(string)) + } + cfg.WriteTo(f) } return nil } diff --git a/viper_test.go b/viper_test.go index 85c2d02..f8349ac 100644 --- a/viper_test.go +++ b/viper_test.go @@ -118,6 +118,24 @@ var remoteExample = []byte(`{ "newkey":"remote" }`) +var iniExample = []byte(`; Package name +NAME = ini +; Package version +VERSION = v1 +; Package import path +IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s + +# Information about package author +# Bio can be written in multiple lines. +[author] +NAME = Unknwon ; Succeeding comment +E-MAIL = fake@localhost +GITHUB = https://github.com/%(NAME)s +BIO = """Gopher. +Coding addict. +Good man. +""" # Succeeding comment`) + func initConfigs() { Reset() var r io.Reader @@ -148,6 +166,10 @@ func initConfigs() { SetConfigType("json") remote := bytes.NewReader(remoteExample) unmarshalReader(remote, v.kvstore) + + SetConfigType("ini") + r = bytes.NewReader(iniExample) + unmarshalReader(r, v.config) } func initConfig(typ, config string) { @@ -204,6 +226,14 @@ func initHcl() { unmarshalReader(r, v.config) } +func initIni() { + Reset() + SetConfigType("ini") + r := bytes.NewReader(iniExample) + + unmarshalReader(r, v.config) +} + // make directories for testing func initDirs(t *testing.T) (string, string, func()) { @@ -396,6 +426,11 @@ func TestHCL(t *testing.T) { assert.NotEqual(t, "cronut", Get("type")) } +func TestIni(t *testing.T) { + initIni() + assert.Equal(t, "ini", Get("default.name")) +} + func TestRemotePrecedence(t *testing.T) { initJSON() @@ -521,6 +556,10 @@ func TestAllKeys(t *testing.T) { ks := sort.StringSlice{ "title", + "author.bio", + "author.e-mail", + "author.github", + "author.name", "newkey", "owner.organization", "owner.dob", @@ -532,6 +571,9 @@ func TestAllKeys(t *testing.T) { "hobbies", "clothing.jacket", "clothing.trousers", + "default.import_path", + "default.name", + "default.version", "clothing.pants.size", "age", "hacker", @@ -556,13 +598,24 @@ func TestAllKeys(t *testing.T) { "dob": dob, }, "title": "TOML Example", - "ppu": 0.55, - "eyes": "brown", + "author": map[string]interface{}{ + "e-mail": "fake@localhost", + "github": "https://github.com/Unknwon", + "name": "Unknwon", + "bio": "Gopher.\nCoding addict.\nGood man.\n", + }, + "ppu": 0.55, + "eyes": "brown", "clothing": map[string]interface{}{ "trousers": "denim", "jacket": "leather", "pants": map[string]interface{}{"size": "large"}, }, + "default": map[string]interface{}{ + "import_path": "gopkg.in/ini.v1", + "name": "ini", + "version": "v1", + }, "id": "0001", "batters": map[string]interface{}{ "batter": []interface{}{