mirror of
https://github.com/httprunner/httprunner.git
synced 2026-07-10 23:12:41 +08:00
fix: filter commented out functions when generating plugin file
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
## v4.1.4 (2022-06-14)
|
## v4.1.4 (2022-06-14)
|
||||||
|
|
||||||
- feat: config pypi index url by setting environment `PYPI_INDEX_URL`
|
- feat: config pypi index url by setting environment `PYPI_INDEX_URL`
|
||||||
|
- fix: filter commented out functions when generating plugin file
|
||||||
|
|
||||||
## v4.1.3 (2022-06-14)
|
## v4.1.3 (2022-06-14)
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,11 @@ import time
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
|
# commented out function will be filtered
|
||||||
|
# def get_headers():
|
||||||
|
# return {"User-Agent": "hrp"}
|
||||||
|
|
||||||
|
|
||||||
def get_user_agent():
|
def get_user_agent():
|
||||||
return "hrp/funppy"
|
return "hrp/funppy"
|
||||||
|
|
||||||
|
|||||||
142
hrp/build.go
142
hrp/build.go
@@ -26,36 +26,54 @@ var pyTemplate string
|
|||||||
var goTemplate string
|
var goTemplate string
|
||||||
|
|
||||||
// regex for finding all function names
|
// regex for finding all function names
|
||||||
var (
|
type regexFunctions struct {
|
||||||
regexPyFunctionName = regexp.MustCompile(`def ([a-zA-Z_]\w*)\(.*\)`)
|
*regexp.Regexp
|
||||||
regexGoFunctionName = regexp.MustCompile(`func ([A-Z][a-zA-Z_]\w*)\(.*\)`)
|
|
||||||
)
|
|
||||||
|
|
||||||
type pluginTemplateContent struct {
|
|
||||||
Version string // hrp version
|
|
||||||
FunctionNames []string // function names
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func findAllFunctionNames(t *regexp.Regexp, path string) (functionNames []string, err error) {
|
var (
|
||||||
log.Info().Str("path", path).Msg("find all function names from plugin file")
|
regexPyFunctionName = regexFunctions{regexp.MustCompile(`(?m)^def ([a-zA-Z_]\w*)\(.*\)`)}
|
||||||
|
regexGoFunctionName = regexFunctions{regexp.MustCompile(`(?m)^func ([a-zA-Z_]\w*)\(.*\)`)}
|
||||||
content, err := os.ReadFile(path)
|
)
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("failed to read file")
|
|
||||||
return nil, errors.Wrap(err, "read file failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
func (r *regexFunctions) findAllFunctionNames(content string) []string {
|
||||||
|
var functionNames []string
|
||||||
// find all function names
|
// find all function names
|
||||||
functionNameSlice := t.FindAllStringSubmatch(string(content), -1)
|
functionNameSlice := r.FindAllStringSubmatch(content, -1)
|
||||||
for _, elem := range functionNameSlice {
|
for _, elem := range functionNameSlice {
|
||||||
name := strings.Trim(elem[1], " ")
|
name := strings.Trim(elem[1], " ")
|
||||||
functionNames = append(functionNames, name)
|
functionNames = append(functionNames, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
var filteredFunctionNames []string
|
||||||
|
if r == ®exPyFunctionName {
|
||||||
|
// filter private functions
|
||||||
|
for _, name := range functionNames {
|
||||||
|
if strings.HasPrefix(name, "__") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
filteredFunctionNames = append(filteredFunctionNames, name)
|
||||||
|
}
|
||||||
|
} else if r == ®exGoFunctionName {
|
||||||
|
// filter main and init function
|
||||||
|
for _, name := range functionNames {
|
||||||
|
if name == "main" || name == "init" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
filteredFunctionNames = append(filteredFunctionNames, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info().Strs("functionNames", filteredFunctionNames).Msg("find all function names")
|
||||||
|
return filteredFunctionNames
|
||||||
}
|
}
|
||||||
|
|
||||||
func generate(data *pluginTemplateContent, tmpl, output string) error {
|
type pluginTemplate struct {
|
||||||
|
path string // file path
|
||||||
|
Version string // hrp version
|
||||||
|
FunctionNames []string // function names
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *pluginTemplate) generate(tmpl, output string) error {
|
||||||
file, err := os.Create(output)
|
file, err := os.Create(output)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("open output file failed")
|
log.Error().Err(err).Msg("open output file failed")
|
||||||
@@ -64,7 +82,7 @@ func generate(data *pluginTemplateContent, tmpl, output string) error {
|
|||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
writer := bufio.NewWriter(file)
|
writer := bufio.NewWriter(file)
|
||||||
err = template.Must(template.New("debugtalk").Parse(tmpl)).Execute(writer, data)
|
err = template.Must(template.New("debugtalk").Parse(tmpl)).Execute(writer, pt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("execute template parsing failed")
|
log.Error().Err(err).Msg("execute template parsing failed")
|
||||||
return err
|
return err
|
||||||
@@ -79,28 +97,28 @@ func generate(data *pluginTemplateContent, tmpl, output string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildGo builds debugtalk.go to debugtalk.bin
|
func (pt *pluginTemplate) generatePy(output string) error {
|
||||||
func buildGo(path string, output string) error {
|
// specify output file path
|
||||||
functionNames, err := findAllFunctionNames(regexGoFunctionName, path)
|
if output == "" {
|
||||||
|
dir, _ := os.Getwd()
|
||||||
|
output = filepath.Join(dir, PluginPySourceGenFile)
|
||||||
|
} else if builtin.IsFolderPathExists(output) {
|
||||||
|
output = filepath.Join(output, PluginPySourceGenFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate .debugtalk_gen.py
|
||||||
|
err := pt.generate(pyTemplate, output)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "find all function names failed")
|
return err
|
||||||
}
|
|
||||||
// filter main and init function
|
|
||||||
var filteredFunctionNames []string
|
|
||||||
for _, name := range functionNames {
|
|
||||||
if name == "main" || name == "init" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
filteredFunctionNames = append(filteredFunctionNames, name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
templateContent := &pluginTemplateContent{
|
log.Info().Str("output", output).Str("plugin", pt.path).Msg("build python plugin successfully")
|
||||||
Version: version.VERSION,
|
return nil
|
||||||
FunctionNames: filteredFunctionNames,
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pluginDir := filepath.Dir(path)
|
func (pt *pluginTemplate) generateGo(output string) error {
|
||||||
err = generate(templateContent, goTemplate, filepath.Join(pluginDir, PluginGoSourceGenFile))
|
pluginDir := filepath.Dir(pt.path)
|
||||||
|
err := pt.generate(goTemplate, filepath.Join(pluginDir, PluginGoSourceGenFile))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "generate hashicorp plugin failed")
|
return errors.Wrap(err, "generate hashicorp plugin failed")
|
||||||
}
|
}
|
||||||
@@ -139,14 +157,30 @@ func buildGo(path string, output string) error {
|
|||||||
outputPath, _ := filepath.Abs(output)
|
outputPath, _ := filepath.Abs(output)
|
||||||
|
|
||||||
// build go plugin to debugtalk.bin
|
// build go plugin to debugtalk.bin
|
||||||
cmd := exec.Command("go", "build", "-o", outputPath, PluginGoSourceGenFile, filepath.Base(path))
|
cmd := exec.Command("go", "build", "-o", outputPath, PluginGoSourceGenFile, filepath.Base(pt.path))
|
||||||
if err := builtin.ExecCommandInDir(cmd, pluginDir); err != nil {
|
if err := builtin.ExecCommandInDir(cmd, pluginDir); err != nil {
|
||||||
return errors.Wrap(err, "go build plugin failed")
|
return errors.Wrap(err, "go build plugin failed")
|
||||||
}
|
}
|
||||||
log.Info().Str("output", outputPath).Str("plugin", path).Msg("build go plugin successfully")
|
log.Info().Str("output", outputPath).Str("plugin", pt.path).Msg("build go plugin successfully")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// buildGo builds debugtalk.go to debugtalk.bin
|
||||||
|
func buildGo(path string, output string) error {
|
||||||
|
content, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("failed to read file")
|
||||||
|
return errors.Wrap(err, "read file failed")
|
||||||
|
}
|
||||||
|
functionNames := regexGoFunctionName.findAllFunctionNames(string(content))
|
||||||
|
|
||||||
|
templateContent := &pluginTemplate{
|
||||||
|
Version: version.VERSION,
|
||||||
|
FunctionNames: functionNames,
|
||||||
|
}
|
||||||
|
return templateContent.generateGo(output)
|
||||||
|
}
|
||||||
|
|
||||||
// buildPy completes funppy information in debugtalk.py
|
// buildPy completes funppy information in debugtalk.py
|
||||||
func buildPy(path string, output string) error {
|
func buildPy(path string, output string) error {
|
||||||
// check the syntax of debugtalk.py
|
// check the syntax of debugtalk.py
|
||||||
@@ -155,31 +189,19 @@ func buildPy(path string, output string) error {
|
|||||||
return errors.Wrap(err, "python plugin syntax invalid")
|
return errors.Wrap(err, "python plugin syntax invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
functionNames, err := findAllFunctionNames(regexPyFunctionName, path)
|
content, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
log.Error().Err(err).Msg("failed to read file")
|
||||||
|
return errors.Wrap(err, "read file failed")
|
||||||
}
|
}
|
||||||
templateContent := &pluginTemplateContent{
|
functionNames := regexPyFunctionName.findAllFunctionNames(string(content))
|
||||||
|
|
||||||
|
templateContent := &pluginTemplate{
|
||||||
|
path: path,
|
||||||
Version: version.VERSION,
|
Version: version.VERSION,
|
||||||
FunctionNames: functionNames,
|
FunctionNames: functionNames,
|
||||||
}
|
}
|
||||||
|
return templateContent.generatePy(output)
|
||||||
// specify output file path
|
|
||||||
if output == "" {
|
|
||||||
dir, _ := os.Getwd()
|
|
||||||
output = filepath.Join(dir, PluginPySourceGenFile)
|
|
||||||
} else if builtin.IsFolderPathExists(output) {
|
|
||||||
output = filepath.Join(output, PluginPySourceGenFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate .debugtalk_gen.py
|
|
||||||
err = generate(templateContent, pyTemplate, output)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info().Str("output", output).Str("plugin", path).Msg("build python plugin successfully")
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildPlugin(path string, output string) (err error) {
|
func BuildPlugin(path string, output string) (err error) {
|
||||||
|
|||||||
@@ -42,3 +42,87 @@ func TestRun(t *testing.T) {
|
|||||||
t.Fatal()
|
t.Fatal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFindAllPythonFunctionNames(t *testing.T) {
|
||||||
|
content := `
|
||||||
|
def test_1(): # exported function
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _test_2(): # exported function
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __test_3(): # private function
|
||||||
|
pass
|
||||||
|
|
||||||
|
# def test_4(): # commented out function
|
||||||
|
# pass
|
||||||
|
|
||||||
|
def Test5(): # exported function
|
||||||
|
pass
|
||||||
|
`
|
||||||
|
names := regexPyFunctionName.findAllFunctionNames(content)
|
||||||
|
if !assert.Contains(t, names, "test_1") {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if !assert.Contains(t, names, "Test5") {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if !assert.Contains(t, names, "_test_2") {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if !assert.NotContains(t, names, "__test_3") {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
// commented out function
|
||||||
|
if !assert.NotContains(t, names, "test_4") {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindAllGoFunctionNames(t *testing.T) {
|
||||||
|
content := `
|
||||||
|
func Test1() { // exported function
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFunc2() { // exported function
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() { // private function
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { // private function
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Test3() { // exported function
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// func Test4() { // commented out function
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
`
|
||||||
|
names := regexGoFunctionName.findAllFunctionNames(content)
|
||||||
|
if !assert.Contains(t, names, "Test1") {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if !assert.Contains(t, names, "testFunc2") {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if !assert.NotContains(t, names, "main") {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if !assert.NotContains(t, names, "init") {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if !assert.Contains(t, names, "_Test3") {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
// commented out function
|
||||||
|
if !assert.NotContains(t, names, "Test4") {
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,11 @@ import time
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
|
# commented out function will be filtered
|
||||||
|
# def get_headers():
|
||||||
|
# return {"User-Agent": "hrp"}
|
||||||
|
|
||||||
|
|
||||||
def get_user_agent():
|
def get_user_agent():
|
||||||
return "hrp/funppy"
|
return "hrp/funppy"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user