forked from go-gorm/gen
/
export.go
130 lines (111 loc) · 2.96 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
123
124
125
126
127
128
129
130
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{}) (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" {
var skip int
var file string
for {
_, file, _, _ = runtime.Caller(skip)
if !(strings.Contains(file, "gorm/gen/generator.go") || strings.Contains(file, "gorm/gen/internal")) || file == "" {
break
}
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()
}