-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 232951f
Showing
226 changed files
with
40,557 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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,40 @@ | ||
package config | ||
|
||
import ( | ||
"strings" | ||
|
||
"github.com/projecteru2/yavirt/errors" | ||
) | ||
|
||
// Batch . | ||
type Batch struct { | ||
Bins []string `toml:"bins"` | ||
FlagFile string `toml:"flag_file"` | ||
ForceOK bool `toml:"force_ok"` | ||
Timeout Duration `toml:"timeout"` | ||
Retry bool `toml:"retry"` | ||
Interval Duration `toml:"interval"` | ||
} | ||
|
||
// IsRunOnce . | ||
func (b Batch) IsRunOnce() bool { | ||
return len(b.FlagFile) > 0 | ||
} | ||
|
||
// GetCommands . | ||
func (b Batch) GetCommands() (map[string][]string, error) { | ||
var cmds = map[string][]string{} | ||
|
||
for _, bin := range b.Bins { | ||
switch parts := strings.Split(bin, " "); len(parts) { | ||
case 0: | ||
return nil, errors.Annotatef(errors.ErrInvalidValue, "invalid command: %s", bin) | ||
case 1: | ||
cmds[parts[0]] = nil | ||
default: | ||
cmds[parts[0]] = parts[1:] | ||
} | ||
} | ||
|
||
return cmds, nil | ||
} |
This file contains 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,149 @@ | ||
package config | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/projecteru2/yavirt/errors" | ||
) | ||
|
||
type checker struct { //nolint | ||
conf interface{} | ||
field string | ||
fieldObj reflect.StructField | ||
val interface{} | ||
} | ||
|
||
func newChecker(conf interface{}, field string) *checker { //nolint | ||
return &checker{ | ||
conf: conf, | ||
field: field, | ||
} | ||
} | ||
|
||
func (c *checker) check() (err error) { //nolint | ||
if c.conf == nil { | ||
return errors.Errorf("nil *Config") | ||
} | ||
|
||
if c.fieldObj, c.val, err = c.getFieldValue(reflect.ValueOf(c.conf), c.field); err != nil { | ||
return errors.Trace(err) | ||
} | ||
|
||
if err := c.checkEnum(); err != nil { | ||
return errors.Trace(err) | ||
} | ||
|
||
if err := c.checkRange(); err != nil { | ||
return errors.Trace(err) | ||
} | ||
|
||
return | ||
} | ||
|
||
func (c *checker) checkRange() error { //nolint | ||
var rang, found = c.fieldObj.Tag.Lookup("range") | ||
if !found || len(rang) < 1 { | ||
return nil | ||
} | ||
|
||
var part = strings.Split(rang, "-") | ||
if len(part) != 2 { //nolint | ||
return errors.Errorf("invalid range: %s", rang) | ||
} | ||
|
||
var atoi = func(s []string) ([]int, error) { | ||
var ar = make([]int, len(s)) | ||
var err error | ||
for i := 0; i < len(s); i++ { | ||
ar[i], err = strconv.Atoi(s[i]) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
return ar, nil | ||
} | ||
|
||
var ar, err = atoi(part) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
var min, max = ar[0], ar[1] | ||
var leng int | ||
var kind = c.fieldObj.Type.Kind() | ||
|
||
switch kind { | ||
case reflect.Int: | ||
leng = c.val.(int) | ||
case reflect.String: | ||
leng = len(c.val.(string)) | ||
default: | ||
return errors.Errorf("invalid type: %d", kind) | ||
} | ||
|
||
if leng < min || leng > max { | ||
return errors.Errorf("invalid length: %d, it should be [%d, %d]", leng, min, max) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (c *checker) checkEnum() error { //nolint | ||
var enum, found = c.fieldObj.Tag.Lookup("enum") | ||
if !found || len(enum) < 1 { | ||
return nil | ||
} | ||
|
||
for _, part := range strings.Split(enum, ",") { | ||
if fmt.Sprintf("%v", c.val) == strings.TrimSpace(part) { | ||
return nil | ||
} | ||
} | ||
|
||
return errors.Errorf("invalid value: %v", c.val) | ||
} | ||
|
||
func (c *checker) getFieldValue(valObj reflect.Value, field string) ( //nolint | ||
reflect.StructField, interface{}, error) { | ||
|
||
var fieldObj reflect.StructField | ||
|
||
if valObj.Kind() != reflect.Ptr { | ||
return fieldObj, nil, errors.Errorf("require a ptr") | ||
} | ||
|
||
var elem = valObj.Elem() | ||
if !elem.IsValid() { | ||
return fieldObj, nil, errors.Errorf("invalid value") | ||
} | ||
|
||
for i := 0; i < elem.NumField(); i++ { | ||
var name, rest = c.split(field) | ||
|
||
fieldObj = elem.Type().Field(i) | ||
if !strings.EqualFold(fieldObj.Name, name) { | ||
continue | ||
} | ||
|
||
var val = elem.Field(i).Interface() | ||
|
||
if len(rest) < 1 { | ||
return fieldObj, val, nil | ||
} | ||
|
||
return c.getFieldValue(reflect.ValueOf(val), rest) | ||
} | ||
|
||
return fieldObj, nil, errors.Errorf("no such field: %s", field) | ||
} | ||
|
||
func (c *checker) split(field string) (string, string) { //nolint | ||
var i = strings.Index(field, ".") | ||
if i < 0 { | ||
return field, "" | ||
} | ||
return field[:i], field[i+1:] | ||
} |
This file contains 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,79 @@ | ||
package config | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/projecteru2/yavirt/test/assert" | ||
) | ||
|
||
type config struct { | ||
Debug string | ||
Env string `enum:"dev,test,uat,live"` | ||
ProfHTTPPort int `toml:"prof_http_port" enum:"9999,8888"` | ||
Mysql *mysql | ||
} | ||
|
||
type mysql struct { | ||
User string `range:"2-8"` | ||
Port int `range:"6000-9999" json:"port"` | ||
Host string `json:"host"` | ||
} | ||
|
||
var newconf = func() *config { | ||
return &config{ | ||
Mysql: &mysql{}, | ||
} | ||
} | ||
|
||
func TestCheckNotFound(t *testing.T) { | ||
var conf = newconf() | ||
assert.NotNil(t, newChecker(conf, "NotFound").check()) | ||
assert.NotNil(t, newChecker(conf, "Mysql.NotFound").check()) | ||
} | ||
|
||
func TestCheckStrEnum(t *testing.T) { | ||
var conf = newconf() | ||
|
||
conf.Env = "" | ||
assert.NotNil(t, newChecker(conf, "Env").check()) | ||
|
||
conf.Env = "unknown" | ||
assert.NotNil(t, newChecker(conf, "Env").check()) | ||
|
||
conf.Env = "dev" | ||
assert.Nil(t, newChecker(conf, "Env").check()) | ||
} | ||
|
||
func TestCheckStrRange(t *testing.T) { | ||
var conf = newconf() | ||
|
||
conf.Mysql.User = "a" | ||
assert.NotNil(t, newChecker(conf, "Mysql.User").check()) | ||
|
||
conf.Mysql.User = string(make([]byte, 256)) | ||
assert.NotNil(t, newChecker(conf, "Mysql.User").check()) | ||
} | ||
|
||
func TestCheckIntEnum(t *testing.T) { | ||
var conf = newconf() | ||
conf.ProfHTTPPort = 80 | ||
assert.NotNil(t, newChecker(conf, "ProfHTTPPort").check()) | ||
|
||
conf.ProfHTTPPort = 8888 | ||
assert.Nil(t, newChecker(conf, "ProfHTTPPort").check()) | ||
} | ||
|
||
func TestCheckIntRange(t *testing.T) { | ||
var conf = newconf() | ||
conf.Mysql.Port = 3306 | ||
assert.NotNil(t, newChecker(conf, "Mysql.Port").check()) | ||
|
||
conf.Mysql.Port = 6606 | ||
assert.Nil(t, newChecker(conf, "Mysql.Port").check()) | ||
} | ||
|
||
func TestCheckNone(t *testing.T) { | ||
var conf = newconf() | ||
assert.Nil(t, newChecker(conf, "Debug").check()) | ||
assert.Nil(t, newChecker(conf, "Mysql.Host").check()) | ||
} |
This file contains 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,39 @@ | ||
package config | ||
|
||
import ( | ||
"bytes" | ||
|
||
"github.com/BurntSushi/toml" | ||
|
||
"github.com/projecteru2/yavirt/errors" | ||
) | ||
|
||
// Decode . | ||
func Decode(raw string, conf *Config) error { | ||
if _, err := toml.Decode(raw, conf); err != nil { | ||
return errors.Trace(err) | ||
} | ||
return nil | ||
} | ||
|
||
// Encode . | ||
func Encode(conf *Config, noIndents ...bool) (string, error) { | ||
var buf bytes.Buffer | ||
var enc = toml.NewEncoder(&buf) | ||
|
||
if len(noIndents) < 1 || !noIndents[0] { | ||
enc.Indent = " " | ||
} | ||
|
||
if err := enc.Encode(conf); err != nil { | ||
return "", errors.Trace(err) | ||
} | ||
|
||
return buf.String(), nil | ||
} | ||
|
||
// DecodeFile . | ||
func DecodeFile(file string, conf *Config) (err error) { | ||
_, err = toml.DecodeFile(file, conf) | ||
return | ||
} |
Oops, something went wrong.