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

View File

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

View File

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

View File

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