Optional yaml and json config files
parent
290492b4ef
commit
8b2b095c10
|
|
@ -102,14 +102,23 @@ func (a *Arg) Set(value interface{}) error {
|
||||||
err := fmt.Errorf("incompatible set of type %T for arg $%v/-%v type %v", value, a.Env, a.Flag, a.ArgType)
|
err := fmt.Errorf("incompatible set of type %T for arg $%v/-%v type %v", value, a.Env, a.Flag, a.ArgType)
|
||||||
switch a.ArgType {
|
switch a.ArgType {
|
||||||
case INT:
|
case INT:
|
||||||
i, ok := value.(int)
|
switch value.(type) {
|
||||||
if ok {
|
case int:
|
||||||
a.Value = i
|
a.Value = value.(int)
|
||||||
err = nil
|
|
||||||
} else if s, ok := value.(string); !ok {
|
|
||||||
} else if i, err = strconv.Atoi(s); err == nil {
|
|
||||||
a.Value = i
|
|
||||||
err = nil
|
err = nil
|
||||||
|
case string:
|
||||||
|
s := value.(string)
|
||||||
|
var i int
|
||||||
|
if i, err = strconv.Atoi(s); err == nil {
|
||||||
|
a.Value = i
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
case float64:
|
||||||
|
f := value.(float64)
|
||||||
|
if f-float64(int(f)) == 0 {
|
||||||
|
a.Value = int(f)
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case STRING:
|
case STRING:
|
||||||
i, ok := value.(string)
|
i, ok := value.(string)
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,28 @@
|
||||||
package args
|
package args
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
yaml "gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ArgSet struct {
|
type ArgSet struct {
|
||||||
parsed bool
|
parsed bool
|
||||||
args []*Arg
|
args []*Arg
|
||||||
|
configFiles []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewArgSet() *ArgSet {
|
func NewArgSet(configFiles ...string) *ArgSet {
|
||||||
return &ArgSet{
|
return &ArgSet{
|
||||||
args: []*Arg{},
|
args: []*Arg{},
|
||||||
|
configFiles: configFiles,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,6 +53,9 @@ func (as *ArgSet) Parse() error {
|
||||||
if err := as.setValueFromDefaults(); err != nil {
|
if err := as.setValueFromDefaults(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := as.setValueFromFiles(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := as.setValueFromEnv(); err != nil {
|
if err := as.setValueFromEnv(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -122,3 +133,39 @@ func (as *ArgSet) setValueFromFlags() error {
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (as *ArgSet) setValueFromFiles() error {
|
||||||
|
for _, file := range as.configFiles {
|
||||||
|
if err := as.setValueFromFile(file); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (as *ArgSet) setValueFromFile(path string) error {
|
||||||
|
b, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var config map[string]interface{}
|
||||||
|
if strings.HasSuffix(path, ".json") {
|
||||||
|
err = json.Unmarshal(b, &config)
|
||||||
|
} else if strings.HasSuffix(path, ".yaml") {
|
||||||
|
err = yaml.Unmarshal(b, &config)
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("unknown config file suffix: %s", path)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := range as.args {
|
||||||
|
key := as.args[i].Flag
|
||||||
|
if v, ok := config[key]; ok {
|
||||||
|
if err := as.args[i].Set(v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
package args
|
package args
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -68,6 +71,11 @@ func TestParseFloatTime(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGet(t *testing.T) {
|
func TestGet(t *testing.T) {
|
||||||
|
was := os.Args
|
||||||
|
defer func() {
|
||||||
|
os.Args = was
|
||||||
|
}()
|
||||||
|
os.Args = []string{"exec", "-testkey1", "5"}
|
||||||
as := NewArgSet()
|
as := NewArgSet()
|
||||||
as.Append(INT, "testkey1", "help", 1)
|
as.Append(INT, "testkey1", "help", 1)
|
||||||
as.Append(INT, "testkey2", "help", 2)
|
as.Append(INT, "testkey2", "help", 2)
|
||||||
|
|
@ -79,3 +87,68 @@ func TestGet(t *testing.T) {
|
||||||
t.Errorf("cannot get parsed at %q", "testkey1")
|
t.Errorf("cannot get parsed at %q", "testkey1")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSetValueFromFileYAML(t *testing.T) {
|
||||||
|
was := os.Args
|
||||||
|
defer func() {
|
||||||
|
os.Args = was
|
||||||
|
}()
|
||||||
|
os.Args = []string{"exec"}
|
||||||
|
testSetValueFromFile(t, "yaml", `
|
||||||
|
1: 5
|
||||||
|
2: hello
|
||||||
|
3: 5m
|
||||||
|
4: true
|
||||||
|
5: 2019-01-01
|
||||||
|
6: 5.5
|
||||||
|
`)
|
||||||
|
testSetValueFromFile(t, "json", `
|
||||||
|
{
|
||||||
|
"1": 5,
|
||||||
|
"2": "hello",
|
||||||
|
"3": "5m",
|
||||||
|
"4": true,
|
||||||
|
"5": "2019-01-01",
|
||||||
|
"6": 5.5
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSetValueFromFile(t *testing.T, suffix, content string) {
|
||||||
|
d, err := ioutil.TempDir(os.TempDir(), "prefix")
|
||||||
|
defer os.RemoveAll(d)
|
||||||
|
f, err := os.Create(path.Join(d, "conf."+suffix))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(f, content)
|
||||||
|
f.Close()
|
||||||
|
as := NewArgSet(f.Name())
|
||||||
|
as.Append(INT, "1", "help", 1)
|
||||||
|
as.Append(STRING, "2", "help", "world")
|
||||||
|
as.Append(DURATION, "3", "help", time.Hour)
|
||||||
|
as.Append(BOOL, "4", "help", false)
|
||||||
|
as.Append(TIME, "5", "help", time.Now())
|
||||||
|
as.Append(FLOAT, "6", "help", 1.1)
|
||||||
|
if err := as.Parse(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if v := as.Get("1").GetInt(); v != 5 {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
if v := as.Get("2").GetString(); v != "hello" {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
if v := as.Get("3").GetDuration(); v != time.Minute*5 {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
if v := as.Get("4").GetBool(); v != true {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
if v := as.Get("5").GetTime(); v != time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC) {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
if v := as.Get("6").GetFloat(); v != 5.5 {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue