/
export.go
122 lines (103 loc) · 2.79 KB
/
export.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package parser
import (
"fmt"
"go/build"
"os"
"path/filepath"
"reflect"
"runtime"
"strings"
)
// InterfacePath interface path
type InterfacePath struct {
Name string
FullName string
Files []string
Package string
}
// GetInterfacePath get interface's directory path and all files it contains
func GetInterfacePath(v interface{}) (paths []*InterfacePath, err error) {
value := reflect.ValueOf(v)
if value.Kind() != reflect.Func {
err = fmt.Errorf("model param is not function:%s", value.String())
return
}
for i := 0; i < value.Type().NumIn(); i++ {
var path InterfacePath
arg := value.Type().In(i)
path.FullName = arg.String()
// keep the last model
for _, n := range strings.Split(arg.String(), ".") {
path.Name = n
}
ctx := build.Default
var p *build.Package
if strings.Split(arg.String(), ".")[0] == "main" {
_, file, _, _ := runtime.Caller(3)
p, err = ctx.ImportDir(filepath.Dir(file), build.ImportComment)
} else {
p, err = ctx.Import(arg.PkgPath(), "", build.ImportComment)
}
if err != nil {
return
}
for _, file := range p.GoFiles {
goFile := fmt.Sprintf("%s/%s", p.Dir, file)
if fileExists(goFile) {
path.Files = append(path.Files, goFile)
}
}
if len(path.Files) == 0 {
err = fmt.Errorf("interface file not found:%s", value.String())
return
}
paths = append(paths, &path)
}
return
}
func fileExists(path string) bool {
_, err := os.Stat(path)
return err == nil
}
// GetModelMethod get diy methods
func GetModelMethod(v interface{}, skip int) (method *DIYMethods, err error) {
method = new(DIYMethods)
// get diy method info by input value, must input a function or a struct
value := reflect.ValueOf(v)
switch value.Kind() {
case reflect.Func:
fullPath := runtime.FuncForPC(value.Pointer()).Name()
err = method.parserPath(fullPath)
if err != nil {
return nil, err
}
case reflect.Struct:
method.pkgPath = value.Type().PkgPath()
method.BaseStructType = value.Type().Name()
default:
return nil, fmt.Errorf("method param must be a function or struct")
}
var p *build.Package
// if struct in main file
ctx := build.Default
if method.pkgPath == "main" {
_, file, _, _ := runtime.Caller(skip)
p, err = ctx.ImportDir(filepath.Dir(file), build.ImportComment)
} else {
p, err = ctx.Import(method.pkgPath, "", build.ImportComment)
}
if err != nil {
return nil, fmt.Errorf("diy method dir not found:%s.%s %w", method.pkgPath, method.MethodName, err)
}
for _, file := range p.GoFiles {
goFile := p.Dir + "/" + file
if fileExists(goFile) {
method.pkgFiles = append(method.pkgFiles, goFile)
}
}
if len(method.pkgFiles) == 0 {
return nil, fmt.Errorf("diy method file not found:%s.%s", method.pkgPath, method.MethodName)
}
// read files got methods
return method, method.LoadMethods()
}