Skip to content

Commit

Permalink
add suport for flag layer
Browse files Browse the repository at this point in the history
refs #4 wait for pflag version
Also add go 1.5 to travis build matrix
  • Loading branch information
fzerorubigd committed Aug 27, 2015
1 parent 0b6a098 commit 13c4d1f
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 0 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go:
- 1.2
- 1.3
- 1.4
- 1.5
- tip
before_install:
- go get -v github.com/smartystreets/goconvey
Expand Down
104 changes: 104 additions & 0 deletions flagslayer/loader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Package flagslayer is used to handle flags as a configuration layer
// this package is compatible with standard flags library
package flagslayer

import (
"flag"
"os"
"time"

"github.com/fzerorubigd/onion"
)

// FlagLayer is for handling the layer
type FlagLayer interface {
onion.Layer

// SetBool set a boolean value
SetBool(configkey, name string, value bool, usage string)
// SetDuration set a duration value
SetDuration(configkey, name string, value time.Duration, usage string)
//SetInt64 set an int64 value from flags library
SetInt64(configkey, name string, value int64, usage string)
//SetString set a string
SetString(configkey, name string, value string, usage string)

// GetDelimiter is used to get current delimiter for this layer. since
// this layer needs to work with keys, the delimiter is needed
GetDelimiter() string
// SetDelimiter is used to set delimiter on this layer
SetDelimiter(d string)
}

type flagLayer struct {
flags *flag.FlagSet

delimiter string
data map[string]interface{}
}

func (fl *flagLayer) Load() (map[string]interface{}, error) {
if !fl.flags.Parsed() {
fl.flags.Parse(os.Args[1:])
}

// The default layer has the ablity to deal with nested key. do not copy/paste code here :)
inner := onion.NewDefaultLayer()
inner.SetDelimiter(fl.GetDelimiter())
for i := range fl.data {
switch p := fl.data[i].(type) {
case *bool:
inner.SetDefault(i, *p)
case *time.Duration:
inner.SetDefault(i, *p)
case *int64:
inner.SetDefault(i, *p)
case *string:
inner.SetDefault(i, *p)
}
}

return inner.Load()
}

// SetBool set a boolean value
func (fl *flagLayer) SetBool(configkey, name string, value bool, usage string) {
fl.data[configkey] = fl.flags.Bool(name, value, usage)
}

// SetDuration set a duration value
func (fl *flagLayer) SetDuration(configkey, name string, value time.Duration, usage string) {
fl.data[configkey] = fl.flags.Duration(name, value, usage)
}

//SetInt64 set an int64 value from flags library
func (fl *flagLayer) SetInt64(configkey, name string, value int64, usage string) {
fl.data[configkey] = fl.flags.Int64(name, value, usage)
}

//SetString set a string
func (fl *flagLayer) SetString(configkey, name string, value string, usage string) {
fl.data[configkey] = fl.flags.String(name, value, usage)
}

func (fl *flagLayer) GetDelimiter() string {
if fl.delimiter == "" {
fl.delimiter = "."
}

return fl.delimiter
}

// SetDelimiter is used to set delimiter on this layer
func (fl *flagLayer) SetDelimiter(d string) {
fl.delimiter = d
}

// NewFlagLayer return a flag layer
func NewFlagLayer(f *flag.FlagSet) FlagLayer {
if f == nil {
f = flag.CommandLine
}

return &flagLayer{f, ".", make(map[string]interface{})}
}
74 changes: 74 additions & 0 deletions flagslayer/loader_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package flagslayer

import (
"flag"
"os"
"testing"
"time"

. "github.com/fzerorubigd/onion"
. "github.com/smartystreets/goconvey/convey"
)

func TestYamlLoader(t *testing.T) {
Convey("Load flag data in config", t, func() {
o := New()
flagset := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
layer := NewFlagLayer(flagset)
o.AddLayer(layer)
})

Convey("Load flag data in config default", t, func() {
o := New()
layer := NewFlagLayer(nil)
layer.SetBool("bool", "bool", false, "usage")
layer.SetDuration("duration", "duration", time.Minute, "usage")
layer.SetInt64("int", "int", 1, "usage")
layer.SetString("str", "str", "test", "usage")
o.AddLayer(layer)

So(o.GetBool("bool"), ShouldBeFalse)
So(o.GetDuration("duration"), ShouldEqual, time.Minute)
So(o.GetInt64("int"), ShouldEqual, 1)
So(o.GetString("str"), ShouldEqual, "test")
})

Convey("Load flag data in config with mock flagset", t, func() {
o := New()
flagset := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)

layer := NewFlagLayer(flagset)
layer.SetBool("bool", "bool", false, "usage")
layer.SetDuration("duration", "duration", time.Minute, "usage")
layer.SetInt64("int", "int", 1, "usage")
layer.SetString("str", "str", "test", "usage")
// Mock the layer
args := []string{"-bool=true", "-duration=1h2m3s", "-int=22", "-str=stringtest"}
flagset.Parse(args)

o.AddLayer(layer)
So(o.GetBool("bool"), ShouldBeTrue)
d, _ := time.ParseDuration("1h2m3s")
So(o.GetDuration("duration"), ShouldEqual, d)
So(o.GetInt64("int"), ShouldEqual, 22)
So(o.GetString("str"), ShouldEqual, "stringtest")
})

Convey("Load flag data in config with mock flagset", t, func() {
o := New()
flagset := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)

layer := NewFlagLayer(flagset)
layer.SetDelimiter("")
So(layer.GetDelimiter(), ShouldEqual, ".")

layer.SetBool("bool-nested", "bool", false, "usage")
layer.SetDelimiter("-")
// Mock the layer
args := []string{"-bool=true"}
flagset.Parse(args)

o.AddLayer(layer)
So(o.GetBool("bool.nested"), ShouldBeTrue)
})
}
2 changes: 2 additions & 0 deletions onion.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ func (o *Onion) GetDurationDefault(key string, def time.Duration) time.Duration
return time.Duration(v.(int))
case int64:
return time.Duration(v.(int64))
case time.Duration:
return v.(time.Duration)
default:
return def
}
Expand Down

0 comments on commit 13c4d1f

Please sign in to comment.