-
Notifications
You must be signed in to change notification settings - Fork 6
增加命令行设置配置参数 #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
jl2005
wants to merge
9
commits into
distributedio:master
Choose a base branch
from
jl2005:flags
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
增加命令行设置配置参数 #6
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
eb9c35c
add travel and flags
jl2005 dbfdd84
add some code
jl2005 dff722a
add travel test
jl2005 e1666db
handle array&slice as a whole
jl2005 e0b1cff
add tag for param
jl2005 3d25a21
add flag test
jl2005 edebc43
add flags comment
jl2005 c93b666
remove flagMap
jl2005 7dc7b42
change prefix
jl2005 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "flag" | ||
| "fmt" | ||
| "io/ioutil" | ||
| "log" | ||
|
|
||
| "github.com/distributedio/configo" | ||
| "github.com/distributedio/configo/example/conf" | ||
| ) | ||
|
|
||
| func main() { | ||
| c := &conf.Config{} | ||
|
|
||
| configo.AddFlags(flag.CommandLine, c, "listen", "redis", "redis.0.cluster") | ||
| flag.Parse() | ||
|
|
||
| data, err := ioutil.ReadFile("conf/example.toml") | ||
| if err != nil { | ||
| log.Fatalln(err) | ||
| } | ||
|
|
||
| err = configo.Unmarshal(data, c) | ||
| if err != nil { | ||
| log.Fatalln(err) | ||
| } | ||
| fmt.Printf("%#v\n", c) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,200 @@ | ||
| package configo | ||
|
|
||
| import ( | ||
| "flag" | ||
| "log" | ||
| "reflect" | ||
| "strconv" | ||
| "strings" | ||
| "time" | ||
|
|
||
| "github.com/shafreeck/toml" | ||
| ) | ||
|
|
||
| /* | ||
| `flags` 实现将对象中的变量添加到`flag`中,从而实现通过命令行设置变量的功能。 | ||
|
|
||
| import ( | ||
| "log" | ||
|
|
||
| "github.com/distributedio/configo" | ||
| ) | ||
|
|
||
| type Config struct { | ||
| Key string `cfg:"key; default;; simple type example"` | ||
| Child *Child `cfg:"child; ;; class type "` | ||
| Array []string `cfg:"array;;; simple array type"` | ||
| CompArray []*Child `cfg:"comp;;; complex array type"` | ||
| } | ||
|
|
||
| type Child struct { | ||
| Name string `cfg:"name; noname;; child class item` | ||
| } | ||
|
|
||
| func main() { | ||
| conf := &Config{} | ||
| configo.AddFlags(conf) | ||
| flag.Parse() | ||
|
|
||
| if err := configo.Load("conf/example.toml", conf); err != nil { | ||
| log.Fatalln(err) | ||
| } | ||
| } | ||
|
|
||
| 首先,需要在`flag.Parse()`之前调用`AddFlags()`将对象中的变量添加到`falg`中。 | ||
| `configo.Load()`会在内部调用`ApplyFlags()`方法,将`flag`中设置的变量应用到 | ||
| 对象中。 | ||
|
|
||
| 对象中的变量按照如下规则对应`flag`中的`key`: | ||
|
|
||
| * 简单数据类型,直接使用`cfg`中的`name`作为`flag`中的`key`。 | ||
| 如`Conf.Key`,对应`flag`中的`key`。 | ||
| * 对象数据类型,需要添加上一层对象的名称。 | ||
| 如 `Conf.Child.Name` 对应`flag`中的`child.name` | ||
| * 数组或slice类型,要增加下标作为一个层级。 | ||
| 如 `Conf.CompArray[0].Name`,对应`flag`中的`comp.0.name` | ||
| * 对于简单数据类型的数组或slice也可以使用名称作为`flag`中的`key`, | ||
| 使用字符串表示一个数组。 | ||
| 例如:`Conf.Array`,对应`flag`中的`array`。同时在执行中,使用如下的 | ||
| 方式设置`array`: | ||
| ./cmd -array="[\"a1\", \"a2\"]" | ||
| */ | ||
|
|
||
| const ( | ||
| ConfigoFlagSuffix = "[configo]" | ||
| ) | ||
|
|
||
| // AddFlags 将对象中的变量加入到flag中,从而可以通过命令行设置对应的变量。 | ||
| // | ||
| // * `obj` 为待加入到`flag`中的对象的实例 | ||
| // * `keys` 限定加入`flag`中变量的范围,**不设置**的时候表示将所有变量都加入到`flag`中。 | ||
| func AddFlags(fs *flag.FlagSet, obj interface{}, keys ...string) { | ||
| flagMap := make(map[string]struct{}, len(keys)) | ||
| for i := range keys { | ||
| flagMap[keys[i]] = struct{}{} | ||
| } | ||
| t := NewTravel(func(path string, tag *toml.CfgTag, fv reflect.Value) { | ||
jl2005 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if _, ok := flagMap[path]; len(flagMap) > 0 && !ok { | ||
| return | ||
| } | ||
| var err error | ||
| switch fv.Kind() { | ||
| case reflect.Int, reflect.Int8, reflect.Int16, | ||
| reflect.Int32, reflect.Int64: | ||
| var v int64 | ||
| if v, err = strconv.ParseInt(tag.Value, 10, 64); err != nil { | ||
| if fv.Kind() == reflect.Int64 { | ||
| //try to parse a time.Duration | ||
| if d, err := time.ParseDuration(tag.Value); err == nil { | ||
| fs.Duration(path, time.Duration(d), ConfigoFlagSuffix+tag.Description) | ||
| return | ||
| } | ||
| } | ||
| log.Fatalln(err) | ||
| return | ||
| } | ||
| fs.Int64(path, v, ConfigoFlagSuffix+tag.Description) | ||
| case reflect.Uint, reflect.Uint8, reflect.Uint16, | ||
| reflect.Uint32, reflect.Uint64: | ||
| var v uint64 | ||
| if v, err = strconv.ParseUint(tag.Value, 10, 64); err != nil { | ||
| log.Fatalln(err) | ||
| return | ||
| } | ||
| fs.Uint64(path, v, ConfigoFlagSuffix+tag.Description) | ||
| case reflect.Float32, reflect.Float64: | ||
| var v float64 | ||
| if v, err = strconv.ParseFloat(tag.Value, 64); err != nil { | ||
| log.Fatalln(err) | ||
| return | ||
| } | ||
| fs.Float64(path, v, ConfigoFlagSuffix+tag.Description) | ||
| case reflect.Bool: | ||
| var v bool | ||
| if v, err = strconv.ParseBool(tag.Value); err != nil { | ||
| log.Fatalln(err) | ||
| return | ||
| } | ||
| fs.Bool(path, v, ConfigoFlagSuffix+tag.Description) | ||
| case reflect.String: | ||
| fs.String(path, tag.Value, ConfigoFlagSuffix+tag.Description) | ||
| case reflect.Slice, reflect.Array: | ||
| // TODO 使用flag.Var设置变量 | ||
| fs.String(path, tag.Value, ConfigoFlagSuffix+tag.Description) | ||
| default: | ||
| log.Printf("unknow type %s for set flag", fv.Type()) | ||
| } | ||
| }) | ||
| t.Travel(obj) | ||
| } | ||
|
|
||
| // ApplyFlags 将命令行中设置的变量值应用到`obj`中。 | ||
| // | ||
| // **注意:** configo中的函数默认会调用这个函数设置配置文件,所以不需要显示调用。 | ||
| func ApplyFlags(fs *flag.FlagSet, obj interface{}) { | ||
| actualFlags := make(map[string]*flag.Flag) | ||
| fs.Visit(func(f *flag.Flag) { | ||
| if strings.Contains(f.Usage, ConfigoFlagSuffix) { | ||
| actualFlags[f.Name] = f | ||
| } | ||
| }) | ||
| t := NewTravel(func(path string, tag *toml.CfgTag, fv reflect.Value) { | ||
| f, ok := actualFlags[path] | ||
| if !ok { | ||
| return | ||
| } | ||
| var err error | ||
| switch fv.Kind() { | ||
| case reflect.Int, reflect.Int8, reflect.Int16, | ||
| reflect.Int32, reflect.Int64: | ||
| var v int64 | ||
| if v, err = strconv.ParseInt(f.Value.String(), 10, 64); err != nil { | ||
| if fv.Kind() == reflect.Int64 { | ||
| //try to parse a time.Duration | ||
| if d, err := time.ParseDuration(f.Value.String()); err == nil { | ||
| fv.SetInt(int64(d)) | ||
| return | ||
| } | ||
| } | ||
| log.Fatalln(err) | ||
| return | ||
| } | ||
| fv.SetInt(v) | ||
| case reflect.Uint, reflect.Uint8, reflect.Uint16, | ||
| reflect.Uint32, reflect.Uint64: | ||
| var v uint64 | ||
| if v, err = strconv.ParseUint(f.Value.String(), 10, 64); err != nil { | ||
| log.Fatalln(err) | ||
| return | ||
| } | ||
| fv.SetUint(v) | ||
| case reflect.Float32, reflect.Float64: | ||
| var v float64 | ||
| if v, err = strconv.ParseFloat(f.Value.String(), 64); err != nil { | ||
| log.Fatalln(err) | ||
| return | ||
| } | ||
| fv.SetFloat(v) | ||
| case reflect.Bool: | ||
| var v bool | ||
| if v, err = strconv.ParseBool(f.Value.String()); err != nil { | ||
| log.Fatalln(err) | ||
| return | ||
| } | ||
| fv.SetBool(v) | ||
| case reflect.String: | ||
| fv.SetString(f.Value.String()) | ||
| case reflect.Slice, reflect.Array: | ||
| // TODO NOT support | ||
| // if err := unmarshalArray("name", f.Value.String(), &s); err != nil { | ||
| // log.Fatalln(err) | ||
| // return | ||
| // } | ||
| // fv.Set(reflect.ValueOf(s.Name)) | ||
| // log.Printf("get list =%#v\n", s) | ||
| default: | ||
| log.Printf("unknow type %s for set flag", fv.Type()) | ||
| } | ||
| }) | ||
| t.Travel(obj) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| package configo | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "reflect" | ||
|
|
||
| "github.com/shafreeck/toml" | ||
| ) | ||
|
|
||
| type TravelHandle func(path string, tag *toml.CfgTag, v reflect.Value) | ||
|
|
||
| type Travel struct { | ||
| handle TravelHandle | ||
| } | ||
|
|
||
| func NewTravel(h TravelHandle) *Travel { | ||
| return &Travel{handle: h} | ||
| } | ||
|
|
||
| func (t *Travel) Travel(obj interface{}) { | ||
| t.travel("", nil, reflect.ValueOf(obj)) | ||
| } | ||
|
|
||
| func (t *Travel) travel(path string, tag *toml.CfgTag, v reflect.Value) { | ||
| switch v.Kind() { | ||
| case reflect.Ptr: | ||
| vValue := v.Elem() | ||
| if !vValue.IsValid() { | ||
| return | ||
| } | ||
| t.travel(path, tag, vValue) | ||
| case reflect.Interface: | ||
| vValue := v.Elem() | ||
| if !vValue.IsValid() { | ||
| return | ||
| } | ||
| t.travel(path, tag, vValue) | ||
| case reflect.Struct: | ||
| for i := 0; i < v.NumField(); i += 1 { | ||
| if !v.Field(i).IsValid() { | ||
| continue | ||
| } | ||
| tag := extractTag(v.Type().Field(i).Tag.Get(fieldTagName)) | ||
| p := tag.Name | ||
| if len(path) > 0 { | ||
| p = path + "." + tag.Name | ||
| } | ||
| t.travel(p, tag, v.Field(i)) | ||
| } | ||
| case reflect.Slice, reflect.Array: | ||
| // handle slice & array as a whole | ||
| t.handle(path, tag, v) | ||
| for i := 0; i < v.Len(); i++ { | ||
| p := fmt.Sprintf("%d", i) | ||
| if len(path) > 0 { | ||
| p = path + "." + p | ||
| } | ||
| // handle every element | ||
| t.travel(p, tag, v.Index(i)) | ||
| } | ||
| case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
| fallthrough | ||
| case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||
| fallthrough | ||
| case reflect.Float32, reflect.Float64: | ||
| fallthrough | ||
| case reflect.Bool: | ||
| fallthrough | ||
| case reflect.String: | ||
| t.handle(path, tag, v) | ||
| default: | ||
| panic(fmt.Sprintf("config file use unsupport type. %v", v.Type())) | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.