Skip to content

Commit

Permalink
Implement issue #1 Add builtin flag: -config
Browse files Browse the repository at this point in the history
  • Loading branch information
fulldump committed Jul 27, 2016
1 parent 4542a42 commit 4f96a1c
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 10 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Arguments are parsed from command line with the standard `flag` library.
- [How to use](#how-to-use)
- [Supported types](#supported-types)
- [Builtin configuration keys](#builtin-configuration-keys)
- [-help](#-help)
- [-config](#-config)
- [Contribute](#contribute)
- [Testing](#testing)
- [Example project](#example-project)
Expand Down Expand Up @@ -100,9 +102,32 @@ Type `slice` or `array` is also being considered.

# Builtin configuration keys

## -help

Since `flag` library is using the key `-help` to show usage, Goconf is behaving
in the same way.

## -config

Builtin flag `-config` allow read configuration from a file. For the example
configuration above, this is a sample config.json file:

```json
{
"name": "Fulanito",
"usersdb": {
"host": "localhost",
"user": "admin",
"pass": "123"
}
}
```

Configuration precedence is as follows (higher to lower):
* Arg command line
* Json config file
* Default value


# Contribute

Expand Down
81 changes: 71 additions & 10 deletions goconfig.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,45 @@
package goconfig

import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"os"
"reflect"
"strings"
)

var values = map[string]interface{}{}

func Read(c interface{}) {

path := []string{}

parse_struct(c, path)
// Add builtin -config flag
filename := ""
flag.StringVar(&filename, "config", filename, "Configuration JSON file")

parse_struct(c, path)
flag.Parse()

// Put default values
flag.VisitAll(func(f *flag.Flag) {
if v, e := values[f.Name]; e {
Set(v, f.Value)
}
})

// Read from file JSON
read_json(c, filename)

// Overwrite configuration with command line args:
flag.Visit(func(f *flag.Flag) {
if v, e := values[f.Name]; e {
Set(v, f.Value)
}
})

}

func parse_struct(c interface{}, p []string) {
Expand All @@ -40,39 +66,74 @@ func parse_struct(c interface{}, p []string) {
// Do nothing

} else if reflect.Bool == kind {
flag.BoolVar(ptr.(*bool), name_path, value.Interface().(bool), usage)
flag.Bool(name_path, value.Interface().(bool), usage)

} else if reflect.Float64 == kind {
flag.Float64Var(ptr.(*float64), name_path, value.Interface().(float64), usage)
flag.Float64(name_path, value.Interface().(float64), usage)

} else if reflect.Int64 == kind {
flag.Int64Var(ptr.(*int64), name_path, value.Interface().(int64), usage)
flag.Int64(name_path, value.Interface().(int64), usage)

} else if reflect.Int == kind {
flag.IntVar(ptr.(*int), name_path, value.Interface().(int), usage)
flag.Int(name_path, value.Interface().(int), usage)

} else if reflect.String == kind {
flag.StringVar(ptr.(*string), name_path, value.Interface().(string), usage)
flag.String(name_path, value.Interface().(string), usage)

} else if reflect.Uint64 == kind {
flag.Uint64Var(ptr.(*uint64), name_path, value.Interface().(uint64), usage)
flag.Uint64(name_path, value.Interface().(uint64), usage)

} else if reflect.Uint == kind {
flag.UintVar(ptr.(*uint), name_path, value.Interface().(uint), usage)
flag.Uint(name_path, value.Interface().(uint), usage)

} else if reflect.Struct == kind {
// fmt.Println("TODO: Struct")
parse_struct(ptr, p)

} else if reflect.Slice == kind {
panic("Slice is not supported by goconfig at this moment.")

} else {
panic("Kind `" + kind.String() + "` is not supported by goconfig (field `" + name + "`)")
panic("Kind `" + kind.String() +
"` is not supported by goconfig (field `" + name + "`)")
}

values[name_path] = ptr

p = p[0 : len(p)-1]

}

}

func read_json(c interface{}, filename string) {
if "" == filename {
return
}

data, err := ioutil.ReadFile(filename)
if nil != err {
fmt.Println("Unable to read config file `" + filename + "`!")
os.Exit(1)
}

err = json.Unmarshal(data, &c)
if nil != err {
fmt.Println("Config file should be a valid JSON")
os.Exit(1)
}

// f, err := os.Open(filename)
// if nil != err {
// fmt.Println("Unable to read config file `" + filename + "`!")
// os.Exit(1)
// }
// json.NewDecoder(f).Decode(&c)
}

func Set(dest, value interface{}) {
dest_v := reflect.ValueOf(dest)
dest_t := reflect.TypeOf(dest)
value_v := reflect.ValueOf(value)

dest_v.Elem().Set(value_v.Convert(dest_t).Elem())
}

0 comments on commit 4f96a1c

Please sign in to comment.