Skip to content

Commit e7d4137

Browse files
committed
[new] the first version
0 parents  commit e7d4137

12 files changed

Lines changed: 367 additions & 0 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.idea

config.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Example:
2+
"@": "http://www.baidu.com"
3+
example: "http://example.com"

config/config.go

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package config
2+
3+
import (
4+
"gopkg.in/yaml.v2"
5+
"io/ioutil"
6+
"os"
7+
"reflect"
8+
"strings"
9+
)
10+
11+
type ModelType int
12+
13+
const (
14+
configName = "config.yaml"
15+
LoopBackKey = "@"
16+
17+
TypeUnknown ModelType = iota
18+
TypeVector
19+
TypeScalar
20+
)
21+
22+
type Nest struct {
23+
Data map[string]interface{}
24+
}
25+
26+
func GetConfigPath() string {
27+
defaultPath := "./" + configName
28+
wd, err := os.Getwd()
29+
if err != nil {
30+
return defaultPath
31+
}
32+
if strings.HasSuffix(wd, "goto") {
33+
return "./" + configName
34+
} else if strings.HasSuffix(wd, "handler") || strings.HasSuffix(wd, "config") {
35+
return "../" + configName
36+
}
37+
return defaultPath
38+
}
39+
40+
func NewNest(configPath string) (*Nest, error) {
41+
conf, err := loadYaml(configPath)
42+
if err != nil {
43+
return nil, err
44+
}
45+
return &Nest{Data: conf}, nil
46+
}
47+
48+
//载入配置
49+
func loadYaml(path string) (conf map[string]interface{}, err error) {
50+
f, err := ioutil.ReadFile(path)
51+
if err != nil {
52+
return nil, err
53+
}
54+
m := make(map[interface{}]interface{})
55+
err = yaml.Unmarshal(f, &m)
56+
//to lower to compare
57+
if err != nil {
58+
return
59+
}
60+
conf = toMapStringInterface(m)
61+
toLower(conf)
62+
return
63+
}
64+
65+
func writeYaml(path string, target interface{}) error {
66+
out, err := yaml.Marshal(target)
67+
if err != nil {
68+
return err
69+
}
70+
return ioutil.WriteFile(path, out, 0644)
71+
}
72+
73+
func (n *Nest) GetScalar(paths []string) (URL string, ok bool) {
74+
return getScalar(paths, n.Data)
75+
}
76+
77+
func (n *Nest) Flush() error {
78+
return writeYaml(GetConfigPath(), n.Data)
79+
}
80+
81+
func (n *Nest) AddScalar(paths []string, url string) {
82+
addScalar(n.Data, paths, url)
83+
}
84+
85+
func addScalar(m map[string]interface{}, paths []string, url string) map[string]interface{} {
86+
if len(paths) == 0 {
87+
return nil
88+
}
89+
curK := paths[0]
90+
curV := m[curK]
91+
//find scalar key
92+
if len(paths) == 1 {
93+
if curV != nil && typeOf(curV) == TypeVector {
94+
k := m[curK]
95+
k.(map[string]interface{})[LoopBackKey] = url
96+
} else {
97+
m[curK] = url
98+
}
99+
return m
100+
}
101+
102+
if curV == nil {
103+
m[curK] = addScalar(make(map[string]interface{}), paths[1:], url)
104+
return m
105+
}
106+
107+
if typeOf(curV) == TypeVector {
108+
m[curK] = addScalar(curV.(map[string]interface{}), paths[1:], url)
109+
}
110+
111+
if typeOf(curV) == TypeScalar {
112+
x := make(map[string]interface{})
113+
x[LoopBackKey] = curV
114+
m[curK] = addScalar(x, paths[1:], url)
115+
}
116+
return m
117+
}
118+
119+
func toMapStringInterface(m map[interface{}]interface{}) map[string]interface{} {
120+
nm := make(map[string]interface{})
121+
for k, v := range m {
122+
if reflect.TypeOf(v).Kind() == reflect.Map {
123+
v = toMapStringInterface(v.(map[interface{}]interface{}))
124+
}
125+
nm[k.(string)] = v
126+
}
127+
return nm
128+
}
129+
130+
func toLower(m map[string]interface{}) map[string]interface{} {
131+
for k, v := range m {
132+
delete(m, k)
133+
switch typeOf(v) {
134+
case TypeScalar:
135+
v = strings.ToLower(v.(string))
136+
case TypeVector:
137+
v = toLower(v.(map[string]interface{}))
138+
default:
139+
continue
140+
}
141+
k = strings.ToLower(k)
142+
m[k] = v
143+
}
144+
return m
145+
}
146+
147+
//get the specified URL
148+
func getScalar(paths []string, m map[string]interface{}) (scalar string, ok bool) {
149+
if len(paths) == 0 {
150+
return
151+
}
152+
value, got := m[paths[0]]
153+
if !got {
154+
return
155+
}
156+
switch typeOf(value) {
157+
case TypeScalar:
158+
return value.(string), true
159+
case TypeVector:
160+
if len(paths) == 1 {
161+
v, ok := value.(map[string]interface{})[LoopBackKey]
162+
if ok {
163+
return v.(string), true
164+
} else {
165+
return "", false
166+
}
167+
}
168+
return getScalar(paths[1:], value.(map[string]interface{}))
169+
default:
170+
return
171+
}
172+
}
173+
174+
func typeOf(i interface{}) ModelType {
175+
switch reflect.TypeOf(i).Kind() {
176+
case reflect.Map:
177+
return TypeVector
178+
case reflect.String:
179+
return TypeScalar
180+
default:
181+
return TypeUnknown
182+
}
183+
}

config/config_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package config
2+
3+
import (
4+
"github.com/stretchr/testify/require"
5+
"testing"
6+
)
7+
8+
func Test_typeOf(t *testing.T) {
9+
type args struct {
10+
i interface{}
11+
}
12+
tests := []struct {
13+
name string
14+
args args
15+
want ModelType
16+
}{
17+
{
18+
args: args{make(map[string]interface{})},
19+
want: TypeVector,
20+
}, {
21+
want: TypeUnknown,
22+
}, {
23+
args: args{""},
24+
want: TypeScalar,
25+
},
26+
}
27+
for _, tt := range tests {
28+
t.Run(tt.name, func(t *testing.T) {
29+
if got := typeOf(tt.args.i); got != tt.want {
30+
t.Errorf("typeOf() = %v, want %v", got, tt.want)
31+
}
32+
})
33+
}
34+
}
35+
36+
func TestNest_GetURL(t *testing.T) {
37+
nest, err := NewNest("../config.yaml")
38+
if err != nil {
39+
t.Fatalf(err.Error())
40+
}
41+
u, _ := nest.GetScalar([]string{"tce", "stream"})
42+
print(u)
43+
}
44+
45+
func Test_toLower(t *testing.T) {
46+
assert := require.New(t)
47+
m := map[string]interface{}{
48+
"A": "A",
49+
"b": "B",
50+
"C": "c",
51+
"D": map[string]interface{}{
52+
"E": "e",
53+
"f": "F",
54+
},
55+
}
56+
assert.NotPanics(func() {
57+
toLower(m)
58+
assert.Equal("a", m["a"])
59+
assert.Equal("f", m["d"].(map[string]interface{})["f"])
60+
})
61+
}
62+
63+
func TestNest_AddScalar(t *testing.T) {
64+
nest, err := NewNest("../config.yaml")
65+
if err != nil {
66+
t.Fatalf(err.Error())
67+
}
68+
nest.AddScalar([]string{"tce", "stream", "a"}, "http://www.baidu.com")
69+
nest.Flush()
70+
println(nest.Data)
71+
}

go.mod

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module github.com/Huweicai/goto
2+
3+
require (
4+
github.com/davecgh/go-spew v1.1.1 // indirect
5+
github.com/stretchr/objx v0.1.1 // indirect
6+
github.com/stretchr/testify v1.3.0
7+
gopkg.in/yaml.v2 v2.2.2
8+
)

go.sum

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
5+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
6+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
7+
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
8+
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
9+
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
10+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
11+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
12+
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
13+
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

handler/add.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package handler
2+
3+
import (
4+
"github.com/Huweicai/goto/config"
5+
"log"
6+
)
7+
8+
func Add(args []string) {
9+
nest, err := config.NewNest(config.GetConfigPath())
10+
if err != nil {
11+
log.Fatalf(err.Error())
12+
return
13+
}
14+
nest.AddScalar(args[:len(args)-1], args[len(args)-1])
15+
nest.Flush()
16+
}

handler/common.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package handler
2+
3+
const (
4+
add = "add"
5+
get = "get"
6+
)
7+
8+
var handlers = map[string]func(args []string){
9+
add: Add,
10+
get: Get,
11+
}
12+
13+
func GetHandler(name string) func(args []string) {
14+
return handlers[name]
15+
}

handler/common_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package handler
2+
3+
import (
4+
"os"
5+
"testing"
6+
)
7+
8+
func TestAdd(t *testing.T) {
9+
s, _ := os.Getwd()
10+
print(s)
11+
12+
}

handler/get.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package handler
2+
3+
import (
4+
"github.com/Huweicai/goto/config"
5+
"log"
6+
"os/exec"
7+
)
8+
9+
func Get(args []string) {
10+
nest, err := config.NewNest("./config.yaml")
11+
if err != nil {
12+
log.Fatalf("init nest failed err:%s", err.Error())
13+
return
14+
}
15+
url, ok := nest.GetScalar(args)
16+
if !ok {
17+
return
18+
}
19+
cmd := exec.Command("open", url)
20+
err = cmd.Run()
21+
if err != nil {
22+
log.Fatal(err.Error())
23+
24+
}
25+
}

0 commit comments

Comments
 (0)