/
plugin.go
132 lines (110 loc) · 3.03 KB
/
plugin.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
131
132
package hrp
import (
"fmt"
"os"
"os/signal"
"path/filepath"
"syscall"
"github.com/httprunner/funplugin"
"github.com/rs/zerolog/log"
"github.com/httprunner/httprunner/hrp/internal/sdk"
)
const (
goPluginFile = "debugtalk.so" // built from go plugin
hashicorpGoPluginFile = "debugtalk.bin" // built from hashicorp go plugin
hashicorpPyPluginFile = "debugtalk.py" // used for hashicorp python plugin
)
func initPlugin(path string, logOn bool) (plugin funplugin.IPlugin, pluginDir string, err error) {
// plugin file not found
if path == "" {
return nil, "", nil
}
pluginPath, err := locatePlugin(path)
if err != nil {
return nil, "", nil
}
// TODO: move pluginDir to funplugin
pluginDir = filepath.Dir(pluginPath)
// found plugin file
plugin, err = funplugin.Init(pluginPath, funplugin.WithLogOn(logOn))
if err != nil {
log.Error().Err(err).Msgf("init plugin failed: %s", pluginPath)
return
}
// catch Interrupt and SIGTERM signals to ensure plugin quitted
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
plugin.Quit()
}()
// report event for initializing plugin
event := sdk.EventTracking{
Category: "InitPlugin",
Action: fmt.Sprintf("Init %s plugin", plugin.Type()),
Value: 0, // success
}
if err != nil {
event.Value = 1 // failed
}
go sdk.SendEvent(event)
return
}
func locatePlugin(path string) (pluginPath string, err error) {
// priority: hashicorp plugin (debugtalk.bin > debugtalk.py) > go plugin (debugtalk.so)
pluginPath, err = locateFile(path, hashicorpGoPluginFile)
if err == nil {
return
}
pluginPath, err = locateFile(path, hashicorpPyPluginFile)
if err == nil {
return
}
pluginPath, err = locateFile(path, goPluginFile)
if err == nil {
return
}
return "", fmt.Errorf("plugin file not found")
}
// locateFile searches destFile upward recursively until current
// working directory or system root dir.
func locateFile(startPath string, destFile string) (string, error) {
stat, err := os.Stat(startPath)
if os.IsNotExist(err) {
return "", err
}
var startDir string
if stat.IsDir() {
startDir = startPath
} else {
startDir = filepath.Dir(startPath)
}
startDir, _ = filepath.Abs(startDir)
// convention over configuration
pluginPath := filepath.Join(startDir, destFile)
if _, err := os.Stat(pluginPath); err == nil {
return pluginPath, nil
}
// current working directory
cwd, _ := os.Getwd()
if startDir == cwd {
return "", fmt.Errorf("searched to CWD, plugin file not found")
}
// system root dir
parentDir, _ := filepath.Abs(filepath.Dir(startDir))
if parentDir == startDir {
return "", fmt.Errorf("searched to system root dir, plugin file not found")
}
return locateFile(parentDir, destFile)
}
func getProjectRootDirPath(path string) (rootDir string, err error) {
pluginPath, err := locatePlugin(path)
if err == nil {
rootDir = filepath.Dir(pluginPath)
return
}
// failed to locate project root dir
// maybe project plugin debugtalk.xx is not exist
// use current dir instead
return os.Getwd()
}