Skip to content

Commit 232951f

Browse files
committed
init
0 parents  commit 232951f

File tree

226 files changed

+40557
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

226 files changed

+40557
-0
lines changed

config/batch.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package config
2+
3+
import (
4+
"strings"
5+
6+
"github.com/projecteru2/yavirt/errors"
7+
)
8+
9+
// Batch .
10+
type Batch struct {
11+
Bins []string `toml:"bins"`
12+
FlagFile string `toml:"flag_file"`
13+
ForceOK bool `toml:"force_ok"`
14+
Timeout Duration `toml:"timeout"`
15+
Retry bool `toml:"retry"`
16+
Interval Duration `toml:"interval"`
17+
}
18+
19+
// IsRunOnce .
20+
func (b Batch) IsRunOnce() bool {
21+
return len(b.FlagFile) > 0
22+
}
23+
24+
// GetCommands .
25+
func (b Batch) GetCommands() (map[string][]string, error) {
26+
var cmds = map[string][]string{}
27+
28+
for _, bin := range b.Bins {
29+
switch parts := strings.Split(bin, " "); len(parts) {
30+
case 0:
31+
return nil, errors.Annotatef(errors.ErrInvalidValue, "invalid command: %s", bin)
32+
case 1:
33+
cmds[parts[0]] = nil
34+
default:
35+
cmds[parts[0]] = parts[1:]
36+
}
37+
}
38+
39+
return cmds, nil
40+
}

config/check.go

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package config
2+
3+
import (
4+
"fmt"
5+
"reflect"
6+
"strconv"
7+
"strings"
8+
9+
"github.com/projecteru2/yavirt/errors"
10+
)
11+
12+
type checker struct { //nolint
13+
conf interface{}
14+
field string
15+
fieldObj reflect.StructField
16+
val interface{}
17+
}
18+
19+
func newChecker(conf interface{}, field string) *checker { //nolint
20+
return &checker{
21+
conf: conf,
22+
field: field,
23+
}
24+
}
25+
26+
func (c *checker) check() (err error) { //nolint
27+
if c.conf == nil {
28+
return errors.Errorf("nil *Config")
29+
}
30+
31+
if c.fieldObj, c.val, err = c.getFieldValue(reflect.ValueOf(c.conf), c.field); err != nil {
32+
return errors.Trace(err)
33+
}
34+
35+
if err := c.checkEnum(); err != nil {
36+
return errors.Trace(err)
37+
}
38+
39+
if err := c.checkRange(); err != nil {
40+
return errors.Trace(err)
41+
}
42+
43+
return
44+
}
45+
46+
func (c *checker) checkRange() error { //nolint
47+
var rang, found = c.fieldObj.Tag.Lookup("range")
48+
if !found || len(rang) < 1 {
49+
return nil
50+
}
51+
52+
var part = strings.Split(rang, "-")
53+
if len(part) != 2 { //nolint
54+
return errors.Errorf("invalid range: %s", rang)
55+
}
56+
57+
var atoi = func(s []string) ([]int, error) {
58+
var ar = make([]int, len(s))
59+
var err error
60+
for i := 0; i < len(s); i++ {
61+
ar[i], err = strconv.Atoi(s[i])
62+
if err != nil {
63+
return nil, err
64+
}
65+
}
66+
return ar, nil
67+
}
68+
69+
var ar, err = atoi(part)
70+
if err != nil {
71+
return err
72+
}
73+
74+
var min, max = ar[0], ar[1]
75+
var leng int
76+
var kind = c.fieldObj.Type.Kind()
77+
78+
switch kind {
79+
case reflect.Int:
80+
leng = c.val.(int)
81+
case reflect.String:
82+
leng = len(c.val.(string))
83+
default:
84+
return errors.Errorf("invalid type: %d", kind)
85+
}
86+
87+
if leng < min || leng > max {
88+
return errors.Errorf("invalid length: %d, it should be [%d, %d]", leng, min, max)
89+
}
90+
91+
return nil
92+
}
93+
94+
func (c *checker) checkEnum() error { //nolint
95+
var enum, found = c.fieldObj.Tag.Lookup("enum")
96+
if !found || len(enum) < 1 {
97+
return nil
98+
}
99+
100+
for _, part := range strings.Split(enum, ",") {
101+
if fmt.Sprintf("%v", c.val) == strings.TrimSpace(part) {
102+
return nil
103+
}
104+
}
105+
106+
return errors.Errorf("invalid value: %v", c.val)
107+
}
108+
109+
func (c *checker) getFieldValue(valObj reflect.Value, field string) ( //nolint
110+
reflect.StructField, interface{}, error) {
111+
112+
var fieldObj reflect.StructField
113+
114+
if valObj.Kind() != reflect.Ptr {
115+
return fieldObj, nil, errors.Errorf("require a ptr")
116+
}
117+
118+
var elem = valObj.Elem()
119+
if !elem.IsValid() {
120+
return fieldObj, nil, errors.Errorf("invalid value")
121+
}
122+
123+
for i := 0; i < elem.NumField(); i++ {
124+
var name, rest = c.split(field)
125+
126+
fieldObj = elem.Type().Field(i)
127+
if !strings.EqualFold(fieldObj.Name, name) {
128+
continue
129+
}
130+
131+
var val = elem.Field(i).Interface()
132+
133+
if len(rest) < 1 {
134+
return fieldObj, val, nil
135+
}
136+
137+
return c.getFieldValue(reflect.ValueOf(val), rest)
138+
}
139+
140+
return fieldObj, nil, errors.Errorf("no such field: %s", field)
141+
}
142+
143+
func (c *checker) split(field string) (string, string) { //nolint
144+
var i = strings.Index(field, ".")
145+
if i < 0 {
146+
return field, ""
147+
}
148+
return field[:i], field[i+1:]
149+
}

config/check_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package config
2+
3+
import (
4+
"testing"
5+
6+
"github.com/projecteru2/yavirt/test/assert"
7+
)
8+
9+
type config struct {
10+
Debug string
11+
Env string `enum:"dev,test,uat,live"`
12+
ProfHTTPPort int `toml:"prof_http_port" enum:"9999,8888"`
13+
Mysql *mysql
14+
}
15+
16+
type mysql struct {
17+
User string `range:"2-8"`
18+
Port int `range:"6000-9999" json:"port"`
19+
Host string `json:"host"`
20+
}
21+
22+
var newconf = func() *config {
23+
return &config{
24+
Mysql: &mysql{},
25+
}
26+
}
27+
28+
func TestCheckNotFound(t *testing.T) {
29+
var conf = newconf()
30+
assert.NotNil(t, newChecker(conf, "NotFound").check())
31+
assert.NotNil(t, newChecker(conf, "Mysql.NotFound").check())
32+
}
33+
34+
func TestCheckStrEnum(t *testing.T) {
35+
var conf = newconf()
36+
37+
conf.Env = ""
38+
assert.NotNil(t, newChecker(conf, "Env").check())
39+
40+
conf.Env = "unknown"
41+
assert.NotNil(t, newChecker(conf, "Env").check())
42+
43+
conf.Env = "dev"
44+
assert.Nil(t, newChecker(conf, "Env").check())
45+
}
46+
47+
func TestCheckStrRange(t *testing.T) {
48+
var conf = newconf()
49+
50+
conf.Mysql.User = "a"
51+
assert.NotNil(t, newChecker(conf, "Mysql.User").check())
52+
53+
conf.Mysql.User = string(make([]byte, 256))
54+
assert.NotNil(t, newChecker(conf, "Mysql.User").check())
55+
}
56+
57+
func TestCheckIntEnum(t *testing.T) {
58+
var conf = newconf()
59+
conf.ProfHTTPPort = 80
60+
assert.NotNil(t, newChecker(conf, "ProfHTTPPort").check())
61+
62+
conf.ProfHTTPPort = 8888
63+
assert.Nil(t, newChecker(conf, "ProfHTTPPort").check())
64+
}
65+
66+
func TestCheckIntRange(t *testing.T) {
67+
var conf = newconf()
68+
conf.Mysql.Port = 3306
69+
assert.NotNil(t, newChecker(conf, "Mysql.Port").check())
70+
71+
conf.Mysql.Port = 6606
72+
assert.Nil(t, newChecker(conf, "Mysql.Port").check())
73+
}
74+
75+
func TestCheckNone(t *testing.T) {
76+
var conf = newconf()
77+
assert.Nil(t, newChecker(conf, "Debug").check())
78+
assert.Nil(t, newChecker(conf, "Mysql.Host").check())
79+
}

config/codec.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package config
2+
3+
import (
4+
"bytes"
5+
6+
"github.com/BurntSushi/toml"
7+
8+
"github.com/projecteru2/yavirt/errors"
9+
)
10+
11+
// Decode .
12+
func Decode(raw string, conf *Config) error {
13+
if _, err := toml.Decode(raw, conf); err != nil {
14+
return errors.Trace(err)
15+
}
16+
return nil
17+
}
18+
19+
// Encode .
20+
func Encode(conf *Config, noIndents ...bool) (string, error) {
21+
var buf bytes.Buffer
22+
var enc = toml.NewEncoder(&buf)
23+
24+
if len(noIndents) < 1 || !noIndents[0] {
25+
enc.Indent = " "
26+
}
27+
28+
if err := enc.Encode(conf); err != nil {
29+
return "", errors.Trace(err)
30+
}
31+
32+
return buf.String(), nil
33+
}
34+
35+
// DecodeFile .
36+
func DecodeFile(file string, conf *Config) (err error) {
37+
_, err = toml.DecodeFile(file, conf)
38+
return
39+
}

0 commit comments

Comments
 (0)