release/v1.0.1 #4
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @ -5,5 +5,6 @@ go 1.14 | |||||||
| require ( | require ( | ||||||
| 	git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349 | 	git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349 | ||||||
| 	github.com/BurntSushi/toml v0.3.1 | 	github.com/BurntSushi/toml v0.3.1 | ||||||
|  | 	github.com/otakukaze/envconfig v1.0.4 | ||||||
| 	gopkg.in/yaml.v2 v2.3.0 | 	gopkg.in/yaml.v2 v2.3.0 | ||||||
| ) | ) | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							| @ -2,6 +2,8 @@ git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349 h1:V6ifeiJ3ExnjaUylTO | |||||||
| git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349/go.mod h1:yE+qbsUsijCTdwsaQRkPT1CXYk7ftMzXsCaaYx/0QI0= | git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349/go.mod h1:yE+qbsUsijCTdwsaQRkPT1CXYk7ftMzXsCaaYx/0QI0= | ||||||
| github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= | ||||||
| github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | ||||||
|  | github.com/otakukaze/envconfig v1.0.4 h1:/rZ8xq1vFpgWzqsqUkk61doDGNv9pIXqrog/mCvSx8Y= | ||||||
|  | github.com/otakukaze/envconfig v1.0.4/go.mod h1:v2dNv5NX1Lakw3FTAkbxYURyaiOy68M8QpMTZz+ogfs= | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
| gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= | ||||||
|  | |||||||
							
								
								
									
										77
									
								
								loader.go
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								loader.go
									
									
									
									
									
								
							| @ -9,6 +9,7 @@ import ( | |||||||
| 
 | 
 | ||||||
| 	"git.trj.tw/golang/utils" | 	"git.trj.tw/golang/utils" | ||||||
| 	"github.com/BurntSushi/toml" | 	"github.com/BurntSushi/toml" | ||||||
|  | 	"github.com/otakukaze/envconfig" | ||||||
| 	"gopkg.in/yaml.v2" | 	"gopkg.in/yaml.v2" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -27,6 +28,7 @@ type ConfigFile struct { | |||||||
| 
 | 
 | ||||||
| type LoadOptions struct { | type LoadOptions struct { | ||||||
| 	ConfigFile *ConfigFile | 	ConfigFile *ConfigFile | ||||||
|  | 	FromEnv    bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func Load(i interface{}, opts *LoadOptions) error { | func Load(i interface{}, opts *LoadOptions) error { | ||||||
| @ -50,48 +52,51 @@ func Load(i interface{}, opts *LoadOptions) error { | |||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// no config file | 	// load config file | ||||||
| 	if opts.ConfigFile == nil { | 	if opts.ConfigFile != nil { | ||||||
| 		return nil | 		if opts.ConfigFile.Path == "" { | ||||||
| 	} | 			return errors.New("config file path empty") | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 	if opts.ConfigFile.Path == "" { | 		// resolve file path | ||||||
| 		return errors.New("config file path empty") | 		opts.ConfigFile.Path = utils.ParsePath(opts.ConfigFile.Path) | ||||||
| 	} | 		// check file exists | ||||||
|  | 		if !utils.CheckExists(opts.ConfigFile.Path, false) { | ||||||
|  | 			return errors.New("config file not found") | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 	// resolve file path | 		filebyte, err := ioutil.ReadFile(opts.ConfigFile.Path) | ||||||
| 	opts.ConfigFile.Path = utils.ParsePath(opts.ConfigFile.Path) |  | ||||||
| 	// check file exists |  | ||||||
| 	if !utils.CheckExists(opts.ConfigFile.Path, false) { |  | ||||||
| 		return errors.New("config file not found") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	filebyte, err := ioutil.ReadFile(opts.ConfigFile.Path) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	switch opts.ConfigFile.Type { |  | ||||||
| 	case ConfigFileTypeJSON: |  | ||||||
| 		err := json.Unmarshal(filebyte, i) |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 		break | 
 | ||||||
| 	case ConfigFileTypeTOML: | 		switch opts.ConfigFile.Type { | ||||||
| 		err := toml.Unmarshal(filebyte, i) | 		case ConfigFileTypeJSON: | ||||||
| 		if err != nil { | 			err := json.Unmarshal(filebyte, i) | ||||||
| 			return err | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			break | ||||||
|  | 		case ConfigFileTypeTOML: | ||||||
|  | 			err := toml.Unmarshal(filebyte, i) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			break | ||||||
|  | 		case ConfigFileTypeYAML: | ||||||
|  | 			err := yaml.Unmarshal(filebyte, i) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			break | ||||||
|  | 		default: | ||||||
|  | 			return errors.New("file type not impl") | ||||||
| 		} | 		} | ||||||
| 		break | 	} | ||||||
| 	case ConfigFileTypeYAML: | 
 | ||||||
| 		err := yaml.Unmarshal(filebyte, i) | 	// load config from env | ||||||
| 		if err != nil { | 	if opts.FromEnv { | ||||||
| 			return err | 		envconfig.Parse(i) | ||||||
| 		} |  | ||||||
| 		break |  | ||||||
| 	default: |  | ||||||
| 		return errors.New("file type not impl") |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| package confloader | package confloader | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"os" | ||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"testing" | 	"testing" | ||||||
| ) | ) | ||||||
| @ -13,8 +14,8 @@ func TestLoad(t *testing.T) { | |||||||
| 		Key string `json:"key" yaml:"key" toml:"key"` | 		Key string `json:"key" yaml:"key" toml:"key"` | ||||||
| 	} | 	} | ||||||
| 	type Config struct { | 	type Config struct { | ||||||
| 		StrKey   string   `json:"strKey" yaml:"strKey" toml:"strKey" default:"def value"` | 		StrKey   string   `json:"strKey" yaml:"strKey" toml:"strKey" default:"def value" env:"TEST_STR"` | ||||||
| 		IntKey   int      `json:"intKey" yaml:"intKey" toml:"intKey"` | 		IntKey   int      `json:"intKey" yaml:"intKey" toml:"intKey" env:"TEST_INT"` | ||||||
| 		BoolKey  bool     `json:"boolKey" yaml:"boolKey" toml:"boolKey"` | 		BoolKey  bool     `json:"boolKey" yaml:"boolKey" toml:"boolKey"` | ||||||
| 		FloatKey float64  `json:"floatKey" yaml:"floatKey" toml:"floatKey"` | 		FloatKey float64  `json:"floatKey" yaml:"floatKey" toml:"floatKey"` | ||||||
| 		StrArr   []string `json:"strArr" yaml:"strArr" toml:"strArr" default:"arrval" length:"1"` | 		StrArr   []string `json:"strArr" yaml:"strArr" toml:"strArr" default:"arrval" length:"1"` | ||||||
| @ -23,6 +24,9 @@ func TestLoad(t *testing.T) { | |||||||
| 		ArrObj   []ArrObj `json:"arrObj" yaml:"arrObj" toml:"arrObj"` | 		ArrObj   []ArrObj `json:"arrObj" yaml:"arrObj" toml:"arrObj"` | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	os.Setenv("TEST_STR", "string value2") | ||||||
|  | 	os.Setenv("TEST_INT", "2000") | ||||||
|  | 
 | ||||||
| 	expected := Config{ | 	expected := Config{ | ||||||
| 		StrKey:   "string value", | 		StrKey:   "string value", | ||||||
| 		IntKey:   1000, | 		IntKey:   1000, | ||||||
| @ -35,8 +39,20 @@ func TestLoad(t *testing.T) { | |||||||
| 		}, | 		}, | ||||||
| 		ArrObj: []ArrObj{{Key: "val"}}, | 		ArrObj: []ArrObj{{Key: "val"}}, | ||||||
| 	} | 	} | ||||||
|  | 	expectedWithEnv := Config{ | ||||||
|  | 		StrKey:   "string value2", | ||||||
|  | 		IntKey:   2000, | ||||||
|  | 		BoolKey:  true, | ||||||
|  | 		FloatKey: 1.2345, | ||||||
|  | 		StrArr:   []string{"arr1"}, | ||||||
|  | 		StrArr2:  []string{"arrval2", "arrval2"}, | ||||||
|  | 		ObjKey: ObjKey{ | ||||||
|  | 			Name: "name", | ||||||
|  | 		}, | ||||||
|  | 		ArrObj: []ArrObj{{Key: "val"}}, | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	src := Config{} | 	// src := Config{} | ||||||
| 
 | 
 | ||||||
| 	type args struct { | 	type args struct { | ||||||
| 		i    interface{} | 		i    interface{} | ||||||
| @ -51,7 +67,7 @@ func TestLoad(t *testing.T) { | |||||||
| 		{ | 		{ | ||||||
| 			name: "test load json file with default", | 			name: "test load json file with default", | ||||||
| 			args: args{ | 			args: args{ | ||||||
| 				i: &src, | 				i: &Config{}, | ||||||
| 				opts: &LoadOptions{ | 				opts: &LoadOptions{ | ||||||
| 					ConfigFile: &ConfigFile{ | 					ConfigFile: &ConfigFile{ | ||||||
| 						Type: ConfigFileTypeJSON, | 						Type: ConfigFileTypeJSON, | ||||||
| @ -64,7 +80,7 @@ func TestLoad(t *testing.T) { | |||||||
| 		{ | 		{ | ||||||
| 			name: "test load yaml file with default", | 			name: "test load yaml file with default", | ||||||
| 			args: args{ | 			args: args{ | ||||||
| 				i: &src, | 				i: &Config{}, | ||||||
| 				opts: &LoadOptions{ | 				opts: &LoadOptions{ | ||||||
| 					ConfigFile: &ConfigFile{ | 					ConfigFile: &ConfigFile{ | ||||||
| 						Type: ConfigFileTypeYAML, | 						Type: ConfigFileTypeYAML, | ||||||
| @ -77,7 +93,7 @@ func TestLoad(t *testing.T) { | |||||||
| 		{ | 		{ | ||||||
| 			name: "test load toml file with default", | 			name: "test load toml file with default", | ||||||
| 			args: args{ | 			args: args{ | ||||||
| 				i: &src, | 				i: &Config{}, | ||||||
| 				opts: &LoadOptions{ | 				opts: &LoadOptions{ | ||||||
| 					ConfigFile: &ConfigFile{ | 					ConfigFile: &ConfigFile{ | ||||||
| 						Type: ConfigFileTypeTOML, | 						Type: ConfigFileTypeTOML, | ||||||
| @ -87,14 +103,34 @@ func TestLoad(t *testing.T) { | |||||||
| 			}, | 			}, | ||||||
| 			wantErr: false, | 			wantErr: false, | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "test load json file with default and env", | ||||||
|  | 			args: args{ | ||||||
|  | 				i: &Config{}, | ||||||
|  | 				opts: &LoadOptions{ | ||||||
|  | 					ConfigFile: &ConfigFile{ | ||||||
|  | 						Type: ConfigFileTypeJSON, | ||||||
|  | 						Path: "./test/config.json", | ||||||
|  | 					}, | ||||||
|  | 					FromEnv: true, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			wantErr: false, | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
| 	for _, tt := range tests { | 	for _, tt := range tests { | ||||||
| 		t.Run(tt.name, func(t *testing.T) { | 		t.Run(tt.name, func(t *testing.T) { | ||||||
| 			if err := Load(tt.args.i, tt.args.opts); (err != nil) != tt.wantErr { | 			if err := Load(tt.args.i, tt.args.opts); (err != nil) != tt.wantErr { | ||||||
| 				t.Errorf("Load() error = %v, wantErr %v", err, tt.wantErr) | 				t.Errorf("Load() error = %v, wantErr %v", err, tt.wantErr) | ||||||
| 			} | 			} | ||||||
| 			if !reflect.DeepEqual(src, expected) { | 			if tt.args.opts != nil && tt.args.opts.FromEnv { | ||||||
| 				t.Errorf("Load and expected not match") | 				if !reflect.DeepEqual(tt.args.i, expectedWithEnv) { | ||||||
|  | 					t.Errorf("Load and expected not match") | ||||||
|  | 				} | ||||||
|  | 			} else { | ||||||
|  | 				if !reflect.DeepEqual(tt.args.i, expected) { | ||||||
|  | 					t.Errorf("Load and expected not match") | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user