feat: add --output command in hrp build

This commit is contained in:
xucong053
2022-05-26 21:26:48 +08:00
parent 67c0cb8640
commit 2bee7ba3c7
6 changed files with 79 additions and 91 deletions

View File

@@ -12,15 +12,19 @@ var buildCmd = &cobra.Command{
Long: `build python/go plugin for testing`,
Example: ` $ hrp build plugin/debugtalk.go
$ hrp build plugin/debugtalk.py`,
Args: cobra.MinimumNArgs(1),
Args: cobra.ExactArgs(1),
PreRun: func(cmd *cobra.Command, args []string) {
setLogLevel(logLevel)
},
RunE: func(cmd *cobra.Command, args []string) error {
return build.Run(args)
return build.Run(args[0], output)
},
}
var output string
func init() {
rootCmd.AddCommand(buildCmd)
buildCmd.Flags().StringVarP(&output, "output", "o", "", "funplugin product output path, default: cwd")
}

View File

@@ -4,6 +4,8 @@ import (
"fmt"
)
import "os"
func SumTwoInt(a, b int) int {
return a + b
}
@@ -38,3 +40,7 @@ func SetupHookExample(args string) string {
func TeardownHookExample(args string) string {
return fmt.Sprintf("step name: %v, teardown...", args)
}
func init() {
_, _ = os.Getwd()
}

View File

@@ -23,8 +23,9 @@ const (
funppy = `import funppy`
fungo = `"github.com/httprunner/funplugin/fungo"`
regexPythonFunctionName = `def ([a-zA-Z_]\w*)\(.*\)`
regexGoImport = `import\s*\(\n([\s\S]*)\n\)`
regexGoFunctionName = `func ([a-zA-Z_]\w*)\(.*\)`
regexGoImports = `import\s*\(\n([\s\S]*)\n\)`
regexGoImport = `import\s*(\"[\s\S]*\")\n`
regexGoFunctionName = `func ([A-Z][a-zA-Z_]\w*)\(.*\)`
regexGoFunctionContent = `func [\s\S]*?\n}\n`
)
@@ -35,17 +36,17 @@ var pyTemplate string
var goTemplate string
type TemplateContent struct {
Fun string // funplugin package
Regexps *Regexps // match import/function
Imports []string // python/go import
FromImports []string // python from...import...
Functions []string // python/go function
FunctionNames []string // function name set by user
FunctionSnakeNames []string // function snake name converts by function name for registering plugin
Fun string // funplugin package
Regexps *Regexps // match import/function
Imports []string // python/go import
FromImports []string // python from...import...
Functions []string // python/go function
FunctionNames []string // function name set by user
}
type Regexps struct {
Import *regexp.Regexp
Imports *regexp.Regexp
FunctionName *regexp.Regexp
FunctionContent *regexp.Regexp // including function define and body
}
@@ -65,11 +66,14 @@ func (t *TemplateContent) parseGoContent(path string) error {
if len(importSlice) != 0 {
imports := strings.Replace(importSlice[0][1], "\t", "", -1)
for _, elem := range strings.Split(imports, "\n") {
t.Imports = append(t.Imports, elem)
t.Imports = append(t.Imports, strings.TrimSpace(elem))
}
} else {
if strings.Contains(originalContent, "\nimport ") {
return errors.New(`import style error, expected import ( ... )`)
}
// parse import
importSlice = t.Regexps.Imports.FindAllStringSubmatch(originalContent, -1)
if len(importSlice) != 0 {
for _, elem := range importSlice {
t.Imports = append(t.Imports, strings.TrimSpace(elem[1]))
}
}
// import fungo package
@@ -85,7 +89,6 @@ func (t *TemplateContent) parseGoContent(path string) error {
continue
}
t.FunctionNames = append(t.FunctionNames, name)
t.FunctionSnakeNames = append(t.FunctionSnakeNames, convertSnakeName(name))
}
// parse function content
@@ -135,7 +138,6 @@ func (t *TemplateContent) parsePyContent(path string) error {
continue
}
t.FunctionNames = append(t.FunctionNames, functionNameSlice[0][1])
t.FunctionSnakeNames = append(t.FunctionSnakeNames, convertSnakeName(functionNameSlice[0][1]))
}
content += line + "\n"
}
@@ -174,16 +176,16 @@ func (t *TemplateContent) genDebugTalk(path string, templ string) error {
}
// buildGo builds debugtalk.go to debugtalk.bin
func buildGo(path string) error {
func buildGo(path string, output string) error {
templateContent := &TemplateContent{
Fun: fungo,
Regexps: &Regexps{
Import: regexp.MustCompile(regexGoImport),
Imports: regexp.MustCompile(regexGoImports),
FunctionName: regexp.MustCompile(regexGoFunctionName),
FunctionContent: regexp.MustCompile(regexGoFunctionContent),
},
}
dir, _ := filepath.Split(path)
// create temp dir for building
tempDir, err := ioutil.TempDir("", "hrp_build")
@@ -224,7 +226,13 @@ func buildGo(path string) error {
return err
}
outputPath, err := filepath.Abs(filepath.Join(dir, "../debugtalk.bin"))
if output == "" {
dir, _ := os.Getwd()
output = filepath.Join(dir, "debugtalk.bin")
} else if builtin.IsFolderPathExists(output) {
output = filepath.Join(output, "debugtalk.bin")
}
outputPath, err := filepath.Abs(output)
if err != nil {
return err
}
@@ -238,7 +246,7 @@ func buildGo(path string) error {
}
// buildPy completes funppy information in debugtalk.py
func buildPy(path string) error {
func buildPy(path string, output string) error {
templateContent := &TemplateContent{
Fun: funppy,
Regexps: &Regexps{
@@ -251,8 +259,13 @@ func buildPy(path string) error {
}
// generate debugtalk.py
dir, _ := filepath.Split(path)
err = templateContent.genDebugTalk(filepath.Join(dir, "../debugtalk.py"), pyTemplate)
if output == "" {
dir, _ := os.Getwd()
output = filepath.Join(dir, "debugtalk.py")
} else if builtin.IsFolderPathExists(output) {
output = filepath.Join(output, "debugtalk.py")
}
err = templateContent.genDebugTalk(output, pyTemplate)
if err != nil {
return err
}
@@ -266,39 +279,19 @@ func buildPy(path string) error {
return nil
}
func Run(args []string) (err error) {
for _, arg := range args {
ext := filepath.Ext(arg)
switch ext {
case ".py":
err = buildPy(arg)
case ".go":
err = buildGo(arg)
default:
return errors.New("type error, expected .py or .go")
}
if err != nil {
log.Error().Err(err).Msg(fmt.Sprintf("failed to build %s", arg))
os.Exit(1)
}
func Run(arg string, output string) (err error) {
ext := filepath.Ext(arg)
switch ext {
case ".py":
err = buildPy(arg, output)
case ".go":
err = buildGo(arg, output)
default:
return errors.New("type error, expected .py or .go")
}
if err != nil {
log.Error().Err(err).Msg(fmt.Sprintf("failed to build %s", arg))
os.Exit(1)
}
return nil
}
// convertSnakeName converts name to snake name
func convertSnakeName(originalName string) string {
snakeName := make([]byte, 0, len(originalName)*2)
flag := false
num := len(originalName)
for i := 0; i < num; i++ {
ch := originalName[i]
if i > 0 && ch >= 'A' && ch <= 'Z' && flag {
snakeName = append(snakeName, '_')
}
if ch != '_' {
flag = true
}
snakeName = append(snakeName, ch)
}
return strings.ToLower(string(snakeName))
}

View File

@@ -7,38 +7,23 @@ import (
)
func TestRun(t *testing.T) {
err := Run([]string{"examples/debugtalk_no_funppy.py", "examples/debugtalk_no_fungo.go"})
err := Run("examples/debugtalk_no_funppy.py", "")
if !assert.Nil(t, err) {
t.Fatal()
}
err = Run("examples/debugtalk_no_fungo.go", "")
if !assert.Nil(t, err) {
t.Fatal()
}
err = Run("examples/debugtalk_no_funppy.py", "./debugtalk_gen.py")
if !assert.Nil(t, err) {
t.Fatal()
}
err = Run("examples/debugtalk_no_fungo.go", "./debugtalk_gen.bin")
if !assert.Nil(t, err) {
t.Fatal()
}
}
func TestConvertSnakeName(t *testing.T) {
testData := []struct {
expectedValue string
originalValue string
}{
{
expectedValue: "test_name",
originalValue: "testName",
},
{
expectedValue: "test",
originalValue: "test",
},
{
expectedValue: "test_name",
originalValue: "TestName",
},
{
expectedValue: "test_name",
originalValue: "test_name",
},
}
for _, data := range testData {
name := convertSnakeName(data.originalValue)
if !assert.Equal(t, data.expectedValue, name) {
t.Fatal()
}
}
}

View File

@@ -10,8 +10,8 @@ import (
{{ $function }}
{{ end }}
func main() {
{{- range $idx, $name := .FunctionNames }}
fungo.Register("{{ index $.FunctionSnakeNames $idx }}", {{ $name }})
{{- range $idx, $functionName := .FunctionNames }}
fungo.Register("{{ $functionName }}", {{ $functionName }})
{{- end }}
fungo.Serve()
}

View File

@@ -9,7 +9,7 @@
{{ end }}
if __name__ == "__main__":
{{- range $mainRegSnake := .FunctionSnakeNames }}
funppy.register("{{ $mainRegSnake }}", {{ $mainRegSnake }})
{{- range $functionName := .FunctionNames }}
funppy.register("{{ $functionName }}", {{ $functionName }})
{{- end }}
funppy.serve()