Skip to content

Commit

Permalink
up: pref some read and write config logic
Browse files Browse the repository at this point in the history
  • Loading branch information
inhere committed Sep 15, 2022
1 parent 319f605 commit 77c6467
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 98 deletions.
16 changes: 7 additions & 9 deletions dotenv/dotenv.go
Expand Up @@ -54,7 +54,8 @@ func DontUpperEnvKey() {
// Load parse .env file data to os ENV.
//
// Usage:
// dotenv.Load("./", ".env")
//
// dotenv.Load("./", ".env")
func Load(dir string, filenames ...string) (err error) {
if len(filenames) == 0 {
filenames = []string{DefaultName}
Expand Down Expand Up @@ -128,7 +129,7 @@ func Get(name string, defVal ...string) (val string) {
return
}

// NOTICE: if is windows OS, os.Getenv() Key is not case sensitive
// NOTICE: if is windows OS, os.Getenv() Key is not case-sensitive
if val = os.Getenv(name); val != "" {
return
}
Expand Down Expand Up @@ -171,10 +172,9 @@ func Int(name string, defVal ...int) (val int) {

// load and parse .env file data to os ENV
func loadFile(file string) (err error) {
// open file
fd, err := os.Open(file)
if err != nil {
if os.IsNotExist(err) && OnlyLoadExists {
if OnlyLoadExists && os.IsNotExist(err) {
return nil
}
return err
Expand All @@ -183,16 +183,14 @@ func loadFile(file string) (err error) {
//noinspection GoUnhandledErrorResult
defer fd.Close()

// parse file content
s := bufio.NewScanner(fd)
// parse file contents
p := parser.NewSimpled(parser.NoDefSection)

if _, err = p.ParseFrom(s); err != nil {
if _, err = p.ParseFrom(bufio.NewScanner(fd)); err != nil {
return
}

// set data to os ENV
if mp, ok := p.SimpleData()[p.DefSection]; ok {
if mp := p.LiteSection(p.DefSection); len(mp) > 0 {
err = LoadFromMap(mp)
}
return
Expand Down
37 changes: 8 additions & 29 deletions ini.go
Expand Up @@ -6,7 +6,6 @@ Source code and other details for the project are available at GitHub:
https://github.com/gookit/ini
INI parser is: https://github.com/gookit/ini/parser
*/
package ini

Expand Down Expand Up @@ -88,7 +87,8 @@ func New() *Ini {
// NewWithOptions new an instance and with some options
//
// Usage:
// ini.NewWithOptions(ini.ParseEnv, ini.Readonly)
//
// ini.NewWithOptions(ini.ParseEnv, ini.Readonly)
func NewWithOptions(opts ...func(*Options)) *Ini {
c := New()
// apply options
Expand Down Expand Up @@ -133,7 +133,8 @@ func (c *Ini) ensureInit() {
// newDefaultOptions create a new default Options
//
// Notice:
// Cannot use package var instead it. That will allow multiple instances to use the same Options
//
// Cannot use package var instead it. That will allow multiple instances to use the same Options
func newDefaultOptions() *Options {
return &Options{
ParseEnv: true,
Expand All @@ -158,15 +159,17 @@ func Readonly(opts *Options) {
// ParseVar on get value
//
// Usage:
// ini.WithOptions(ini.ParseVar)
//
// ini.WithOptions(ini.ParseVar)
func ParseVar(opts *Options) {
opts.ParseVar = true
}

// ParseEnv will parse ENV key on get value
//
// Usage:
// ini.WithOptions(ini.ParseEnv)
//
// ini.WithOptions(ini.ParseEnv)
func ParseEnv(opts *Options) {
opts.ParseEnv = true
}
Expand Down Expand Up @@ -424,18 +427,6 @@ func (c *Ini) formatKey(key string) string {
return key
}

// simple merge two string map
func mergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string {
for k, v := range src {
if ignoreCase {
k = strings.ToLower(k)
}

dst[k] = v
}
return dst
}

func mapKeyToLower(src map[string]string) map[string]string {
newMp := make(map[string]string)

Expand All @@ -445,15 +436,3 @@ func mapKeyToLower(src map[string]string) map[string]string {
}
return newMp
}

func stringToArray(str, sep string) (arr []string) {
str = strings.TrimSpace(str)
ss := strings.Split(str, sep)

for _, val := range ss {
if val = strings.TrimSpace(val); val != "" {
arr = append(arr, val)
}
}
return arr
}
98 changes: 48 additions & 50 deletions manage.go
Expand Up @@ -10,18 +10,21 @@ import (
"strings"

"github.com/gookit/goutil/envutil"
"github.com/gookit/goutil/maputil"
"github.com/gookit/goutil/strutil"
"github.com/mitchellh/mapstructure"
)

/*************************************************************
* get config
* read config value
*************************************************************/

// GetValue get a value by key string.
// you can use '.' split for get value in a special section
func GetValue(key string) (string, bool) { return dc.GetValue(key) }

// GetValue a value by key string.
//
// you can use '.' split for get value in a special section
func (c *Ini) GetValue(key string) (val string, ok bool) {
// if not is readonly
Expand Down Expand Up @@ -67,6 +70,7 @@ func (c *Ini) GetValue(key string) (val string, ok bool) {
func Get(key string, defVal ...string) string { return dc.Get(key, defVal...) }

// Get a value by key string.
//
// you can use '.' split for get value in a special section
func (c *Ini) Get(key string, defVal ...string) string {
value, ok := c.GetValue(key)
Expand Down Expand Up @@ -147,16 +151,8 @@ func Bool(key string, defVal ...bool) bool { return dc.Bool(key, defVal...) }

// Bool Looks up a value for a key in this section and attempts to parse that value as a boolean,
// along with a boolean result similar to a map lookup.
// of following(case insensitive):
// - true
// - false
// - yes
// - no
// - off
// - on
// - 0
// - 1
// The `ok` boolean will be false in the event that the value could not be parsed as a bool
//
// The `value` boolean will be false in the event that the value could not be parsed as a bool
func (c *Ini) Bool(key string, defVal ...bool) (value bool) {
rawVal, ok := c.GetValue(key)
if !ok {
Expand All @@ -166,15 +162,12 @@ func (c *Ini) Bool(key string, defVal ...bool) (value bool) {
return
}

lowerCase := strings.ToLower(rawVal)
switch lowerCase {
case "", "0", "false", "no", "off":
value = false
case "1", "true", "yes", "on":
value = true
default:
c.addErrorf("the value '%s' cannot be convert to bool", lowerCase)
var err error
value, err = strutil.ToBool(rawVal)
if err != nil {
c.err = err
}

return
}

Expand All @@ -188,16 +181,17 @@ func (c *Ini) Strings(key string, sep ...string) (ss []string) {
return
}

sepChar := ","
if len(sep) > 0 {
return stringToArray(str, sep[0])
sepChar = sep[0]
}
return stringToArray(str, ",")
return strutil.Split(str, sepChar)
}

// StringMap get a section data map
func StringMap(name string) map[string]string { return dc.StringMap(name) }

// StringMap get a section data map
// StringMap get a section data map by name
func (c *Ini) StringMap(name string) (mp map[string]string) {
name = c.formatKey(name)
// empty name, return default section
Expand All @@ -210,31 +204,35 @@ func (c *Ini) StringMap(name string) (mp map[string]string) {
return
}

// parser Var refer
if c.opts.ParseVar {
if c.opts.ParseVar || c.opts.ParseEnv {
for k, v := range mp {
mp[k] = c.parseVarReference(k, v, mp)
}
}
// parser Var refer
if c.opts.ParseVar {
v = c.parseVarReference(k, v, mp)
}

// if opts.ParseEnv is true. will parse like: "${SHELL}"
if c.opts.ParseEnv {
for k, v := range mp {
mp[k] = envutil.ParseEnvValue(v)
// parse ENV. like: "${SHELL}"
if c.opts.ParseEnv {
v = envutil.ParseEnvValue(v)
}

mp[k] = v
}
}

return
}

// MapStruct get config data and binding to the structure.
func MapStruct(key string, ptr interface{}) error { return dc.MapStruct(key, ptr) }

// MapStruct get config data and binding to the structure.
// If the key is empty, will binding all data to the struct ptr.
// If the key is empty, will bind all data to the struct ptr.
//
// Usage:
// user := &Db{}
// ini.MapStruct("user", &user)
//
// user := &Db{}
// ini.MapStruct("user", &user)
func (c *Ini) MapStruct(key string, ptr interface{}) error {
// binding all data
if key == "" {
Expand Down Expand Up @@ -265,10 +263,11 @@ func (c *Ini) MapStruct(key string, ptr interface{}) error {
return mapStruct(c.opts.TagName, data, ptr)
}

// Decode all data to struct pointer
func (c *Ini) Decode(ptr interface{}) error { return c.MapStruct("", ptr) }

// MapTo mapping all data to struct pointer
func (c *Ini) MapTo(ptr interface{}) error {
return c.MapStruct("", ptr)
}
func (c *Ini) MapTo(ptr interface{}) error { return c.MapStruct("", ptr) }

func mapStruct(tagName string, data interface{}, ptr interface{}) error {
mapConf := &mapstructure.DecoderConfig{
Expand All @@ -288,16 +287,18 @@ func mapStruct(tagName string, data interface{}, ptr interface{}) error {
}

/*************************************************************
* config set
* write config value
*************************************************************/

// Set a value to the section by key.
//
// if section is empty, will set to default section
func Set(key string, val interface{}, section ...string) error {
return dc.Set(key, val, section...)
}

// Set a value to the section by key.
//
// if section is empty, will set to default section
func (c *Ini) Set(key string, val interface{}, section ...string) (err error) {
// if is readonly
Expand Down Expand Up @@ -354,7 +355,6 @@ func (c *Ini) PrettyJSON() string {

// WriteToFile write config data to a file
func (c *Ini) WriteToFile(file string) (int64, error) {
// open file
fd, err := os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664)

if err != nil {
Expand Down Expand Up @@ -420,11 +420,9 @@ func (c *Ini) WriteTo(out io.Writer) (n int64, err error) {
*************************************************************/

// Section get a section data map. is alias of StringMap()
func (c *Ini) Section(name string) Section {
return c.StringMap(name)
}
func (c *Ini) Section(name string) Section { return c.StringMap(name) }

// SetSection if not exist, add new section. If exist, will merge to old section.
// SetSection if not exist, add new section. If existed, will merge to old section.
func (c *Ini) SetSection(name string, values map[string]string) (err error) {
// if is readonly
if c.opts.Readonly {
Expand All @@ -434,13 +432,14 @@ func (c *Ini) SetSection(name string, values map[string]string) (err error) {
name = c.formatKey(name)

if old, ok := c.data[name]; ok {
c.data[name] = mergeStringMap(values, old, c.opts.IgnoreCase)
} else {
if c.opts.IgnoreCase {
values = mapKeyToLower(values)
}
c.data[name] = values
c.data[name] = maputil.MergeStringMap(values, old, c.opts.IgnoreCase)
return
}

if c.opts.IgnoreCase {
values = mapKeyToLower(values)
}
c.data[name] = values
return
}

Expand Down Expand Up @@ -469,7 +468,6 @@ func (c *Ini) HasSection(name string) bool {

// DelSection del section by name
func (c *Ini) DelSection(name string) (ok bool) {
// if is readonly
if c.opts.Readonly {
return
}
Expand Down
2 changes: 1 addition & 1 deletion manage_test.go
Expand Up @@ -285,7 +285,7 @@ tag = golang
is.NoError(err)

u2 := &User{}
is.NoError(conf.MapStruct("", u2))
is.NoError(conf.Decode(u2))
is.Equal(23, u2.Age)
is.Equal("inhere", u2.UserName)
is.Equal("golang", u2.Subs.Tag)
Expand Down
8 changes: 2 additions & 6 deletions parser/decode_encode.go
Expand Up @@ -18,10 +18,6 @@ func Decode(blob []byte, ptr interface{}) error {
return fmt.Errorf("ini: Decode of non-pointer %s", reflect.TypeOf(ptr))
}

// if rv.IsNil() {
// return fmt.Errorf("ini: Decode of nil %s", reflect.TypeOf(v))
// }

p, err := Parse(string(blob), ModeFull, NoDefSection)
if err != nil {
return err
Expand All @@ -30,10 +26,10 @@ func Decode(blob []byte, ptr interface{}) error {
return p.MapStruct(ptr)
}

// Encode golang data to INI string.
// Encode golang data(map, struct) to INI string.
func Encode(v interface{}) ([]byte, error) { return EncodeWithDefName(v) }

// EncodeWithDefName golang data to INI, can set default section name
// EncodeWithDefName golang data(map, struct) to INI, can set default section name
func EncodeWithDefName(v interface{}, defSection ...string) (out []byte, err error) {
switch vd := v.(type) {
case map[string]interface{}: // from full mode
Expand Down

0 comments on commit 77c6467

Please sign in to comment.