mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
cmd/gf: refactor gf gen service with AST (#3488)
This commit is contained in:
@ -57,12 +57,16 @@ func Test_Gen_Service_Default(t *testing.T) {
|
||||
t.AssertNil(err)
|
||||
t.Assert(files, []string{
|
||||
dstFolder + filepath.FromSlash("/article.go"),
|
||||
dstFolder + filepath.FromSlash("/delivery.go"),
|
||||
dstFolder + filepath.FromSlash("/user.go"),
|
||||
})
|
||||
|
||||
// contents
|
||||
testPath := gtest.DataPath("genservice", "service")
|
||||
expectFiles := []string{
|
||||
testPath + filepath.FromSlash("/article.go"),
|
||||
testPath + filepath.FromSlash("/delivery.go"),
|
||||
testPath + filepath.FromSlash("/user.go"),
|
||||
}
|
||||
for i := range files {
|
||||
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
|
||||
|
||||
@ -10,7 +10,11 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/container/gset"
|
||||
@ -21,9 +25,6 @@ import (
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -147,19 +148,22 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
|
||||
}
|
||||
|
||||
var (
|
||||
isDirty bool // Temp boolean.
|
||||
isDirty atomic.Value // Temp boolean.
|
||||
files []string // Temp file array.
|
||||
fileContent string // Temp file content for handling go file.
|
||||
initImportSrcPackages []string // Used for generating logic.go.
|
||||
inputPackages = in.Packages // Custom packages.
|
||||
dstPackageName = gstr.ToLower(gfile.Basename(in.DstFolder)) // Package name for generated go files.
|
||||
generatedDstFilePathSet = gset.NewStrSet() // All generated file path set.
|
||||
)
|
||||
isDirty.Store(false)
|
||||
|
||||
// The first level folders.
|
||||
srcFolderPaths, err := gfile.ScanDir(in.SrcFolder, "*", false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// it will use goroutine to generate service files for each package.
|
||||
var wg = sync.WaitGroup{}
|
||||
for _, srcFolderPath := range srcFolderPaths {
|
||||
if !gfile.IsDir(srcFolderPath) {
|
||||
continue
|
||||
@ -173,111 +177,30 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
|
||||
}
|
||||
// Parse single logic package folder.
|
||||
var (
|
||||
// StructName => FunctionDefinitions
|
||||
srcPkgInterfaceMap = gmap.NewListMap()
|
||||
srcImportedPackages = garray.NewSortedStrArray().SetUnique(true)
|
||||
importAliasToPathMap = gmap.NewStrStrMap() // for conflict imports check. alias => import path(with `"`)
|
||||
importPathToAliasMap = gmap.NewStrStrMap() // for conflict imports check. import path(with `"`) => alias
|
||||
srcPackageName = gfile.Basename(srcFolderPath)
|
||||
ok bool
|
||||
dstFilePath = gfile.Join(in.DstFolder,
|
||||
srcPackageName = gfile.Basename(srcFolderPath)
|
||||
srcImportedPackages = garray.NewSortedStrArray().SetUnique(true)
|
||||
srcStructFunctions = gmap.NewListMap()
|
||||
dstFilePath = gfile.Join(in.DstFolder,
|
||||
c.getDstFileNameCase(srcPackageName, in.DstFileNameCase)+".go",
|
||||
)
|
||||
srcCodeCommentedMap = make(map[string]string)
|
||||
)
|
||||
generatedDstFilePathSet.Add(dstFilePath)
|
||||
// if it were to use goroutine,
|
||||
// it would cause the order of the generated functions in the file to be disordered.
|
||||
for _, file := range files {
|
||||
var packageItems []packageItem
|
||||
fileContent = gfile.GetContents(file)
|
||||
// Calculate code comments in source Go files.
|
||||
err = c.calculateCodeCommented(in, fileContent, srcCodeCommentedMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// remove all comments.
|
||||
fileContent, err = gregex.ReplaceString(`(//.*)|((?s)/\*.*?\*/)`, "", fileContent)
|
||||
pkgItems, funcItems, err := c.parseItemsInSrc(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Calculate imported packages of source go files.
|
||||
packageItems, err = c.calculateImportedPackages(fileContent)
|
||||
// Calculate imported packages for service generating.
|
||||
err = c.calculateImportedItems(in, pkgItems, funcItems, srcImportedPackages)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// try finding the conflicts imports between files.
|
||||
for _, item := range packageItems {
|
||||
var alias = item.Alias
|
||||
if alias == "" {
|
||||
alias = gfile.Basename(gstr.Trim(item.Path, `"`))
|
||||
}
|
||||
|
||||
// ignore unused import paths, which do not exist in function definitions.
|
||||
if !gregex.IsMatchString(fmt.Sprintf(`func .+?([^\w])%s(\.\w+).+?{`, alias), fileContent) {
|
||||
mlog.Debugf(`ignore unused package: %s`, item.RawImport)
|
||||
continue
|
||||
}
|
||||
|
||||
// find the exist alias with the same import path.
|
||||
var existAlias = importPathToAliasMap.Get(item.Path)
|
||||
if existAlias != "" {
|
||||
fileContent, err = gregex.ReplaceStringFuncMatch(
|
||||
fmt.Sprintf(`([^\w])%s(\.\w+)`, alias), fileContent,
|
||||
func(match []string) string {
|
||||
return match[1] + existAlias + match[2]
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// resolve alias conflicts.
|
||||
var importPath = importAliasToPathMap.Get(alias)
|
||||
if importPath == "" {
|
||||
importAliasToPathMap.Set(alias, item.Path)
|
||||
importPathToAliasMap.Set(item.Path, alias)
|
||||
srcImportedPackages.Add(item.RawImport)
|
||||
continue
|
||||
}
|
||||
if importPath != item.Path {
|
||||
// update the conflicted alias for import path with suffix.
|
||||
// eg:
|
||||
// v1 -> v10
|
||||
// v11 -> v110
|
||||
for aliasIndex := 0; ; aliasIndex++ {
|
||||
item.Alias = fmt.Sprintf(`%s%d`, alias, aliasIndex)
|
||||
var existPathForAlias = importAliasToPathMap.Get(item.Alias)
|
||||
if existPathForAlias != "" {
|
||||
if existPathForAlias == item.Path {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
importPathToAliasMap.Set(item.Path, item.Alias)
|
||||
importAliasToPathMap.Set(item.Alias, item.Path)
|
||||
// reformat the import path with alias.
|
||||
item.RawImport = fmt.Sprintf(`%s %s`, item.Alias, item.Path)
|
||||
|
||||
// update the file content with new alias import.
|
||||
fileContent, err = gregex.ReplaceStringFuncMatch(
|
||||
fmt.Sprintf(`([^\w])%s(\.\w+)`, alias), fileContent,
|
||||
func(match []string) string {
|
||||
return match[1] + item.Alias + match[2]
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
srcImportedPackages.Add(item.RawImport)
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate functions and interfaces for service generating.
|
||||
err = c.calculateInterfaceFunctions(in, fileContent, srcPkgInterfaceMap)
|
||||
err = c.calculateFuncItems(in, funcItems, srcStructFunctions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -295,22 +218,28 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
// Generating service go file for single logic package.
|
||||
if ok, err = c.generateServiceFile(generateServiceFilesInput{
|
||||
wg.Add(1)
|
||||
go func(generateServiceFilesInput generateServiceFilesInput) {
|
||||
defer wg.Done()
|
||||
ok, err := c.generateServiceFile(generateServiceFilesInput)
|
||||
if err != nil {
|
||||
mlog.Printf(`error generating service file "%s": %v`, generateServiceFilesInput.DstFilePath, err)
|
||||
}
|
||||
if !isDirty.Load().(bool) && ok {
|
||||
isDirty.Store(true)
|
||||
}
|
||||
}(generateServiceFilesInput{
|
||||
CGenServiceInput: in,
|
||||
SrcStructFunctions: srcPkgInterfaceMap,
|
||||
SrcImportedPackages: srcImportedPackages.Slice(),
|
||||
SrcPackageName: srcPackageName,
|
||||
SrcImportedPackages: srcImportedPackages.Slice(),
|
||||
SrcStructFunctions: srcStructFunctions,
|
||||
DstPackageName: dstPackageName,
|
||||
DstFilePath: dstFilePath,
|
||||
SrcCodeCommentedMap: srcCodeCommentedMap,
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
if ok {
|
||||
isDirty = true
|
||||
}
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
if in.Clear {
|
||||
files, err = gfile.ScanDirFile(in.DstFolder, "*.go", false)
|
||||
@ -320,7 +249,9 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
|
||||
var relativeFilePath string
|
||||
for _, file := range files {
|
||||
relativeFilePath = gstr.SubStrFromR(file, in.DstFolder)
|
||||
if !generatedDstFilePathSet.Contains(relativeFilePath) && utils.IsFileDoNotEdit(relativeFilePath) {
|
||||
if !generatedDstFilePathSet.Contains(relativeFilePath) &&
|
||||
utils.IsFileDoNotEdit(relativeFilePath) {
|
||||
|
||||
mlog.Printf(`remove no longer used service file: %s`, relativeFilePath)
|
||||
if err = gfile.Remove(file); err != nil {
|
||||
return nil, err
|
||||
@ -329,7 +260,7 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
|
||||
}
|
||||
}
|
||||
|
||||
if isDirty {
|
||||
if isDirty.Load().(bool) {
|
||||
// Generate initialization go file.
|
||||
if len(initImportSrcPackages) > 0 {
|
||||
if err = c.generateInitializationFile(in, initImportSrcPackages); err != nil {
|
||||
|
||||
186
cmd/gf/internal/cmd/genservice/genservice_ast_parse.go
Normal file
186
cmd/gf/internal/cmd/genservice/genservice_ast_parse.go
Normal file
@ -0,0 +1,186 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package genservice
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
)
|
||||
|
||||
type pkgItem struct {
|
||||
Alias string `eg:"gdbas"`
|
||||
Path string `eg:"github.com/gogf/gf/v2/database/gdb"`
|
||||
RawImport string `eg:"gdbas github.com/gogf/gf/v2/database/gdb"`
|
||||
}
|
||||
|
||||
type funcItem struct {
|
||||
Receiver string `eg:"sUser"`
|
||||
MethodName string `eg:"GetList"`
|
||||
Params []map[string]string `eg:"ctx: context.Context, cond: *SearchInput"`
|
||||
Results []map[string]string `eg:"list: []*User, err: error"`
|
||||
Comment string `eg:"Get user list"`
|
||||
}
|
||||
|
||||
// parseItemsInSrc parses the pkgItem and funcItem from the specified file.
|
||||
// It can't skip the private methods.
|
||||
// It can't skip the imported packages of import alias equal to `_`.
|
||||
func (c CGenService) parseItemsInSrc(filePath string) (pkgItems []pkgItem, funcItems []funcItem, err error) {
|
||||
var (
|
||||
fileContent = gfile.GetContents(filePath)
|
||||
fileSet = token.NewFileSet()
|
||||
)
|
||||
|
||||
node, err := parser.ParseFile(fileSet, "", fileContent, parser.ParseComments)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ast.Inspect(node, func(n ast.Node) bool {
|
||||
switch x := n.(type) {
|
||||
case *ast.ImportSpec:
|
||||
// parse the imported packages.
|
||||
pkgItems = append(pkgItems, c.parseImportPackages(x))
|
||||
|
||||
case *ast.FuncDecl:
|
||||
// parse the function items.
|
||||
if x.Recv == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
var funcName = x.Name.Name
|
||||
funcItems = append(funcItems, funcItem{
|
||||
Receiver: c.parseFuncReceiverTypeName(x),
|
||||
MethodName: funcName,
|
||||
Params: c.parseFuncParams(x),
|
||||
Results: c.parseFuncResults(x),
|
||||
Comment: c.parseFuncComment(x),
|
||||
})
|
||||
}
|
||||
return true
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// parseImportPackages retrieves the imported packages from the specified ast.ImportSpec.
|
||||
func (c CGenService) parseImportPackages(node *ast.ImportSpec) (packages pkgItem) {
|
||||
if node.Path == nil {
|
||||
return
|
||||
}
|
||||
var (
|
||||
alias string
|
||||
path = node.Path.Value
|
||||
rawImport string
|
||||
)
|
||||
if node.Name != nil {
|
||||
alias = node.Name.Name
|
||||
rawImport = alias + " " + path
|
||||
} else {
|
||||
rawImport = path
|
||||
}
|
||||
return pkgItem{
|
||||
Alias: alias,
|
||||
Path: path,
|
||||
RawImport: rawImport,
|
||||
}
|
||||
}
|
||||
|
||||
// parseFuncReceiverTypeName retrieves the receiver type of the function.
|
||||
// For example:
|
||||
//
|
||||
// func(s *sArticle) -> *sArticle
|
||||
// func(s sArticle) -> sArticle
|
||||
func (c CGenService) parseFuncReceiverTypeName(node *ast.FuncDecl) (receiverType string) {
|
||||
if node.Recv == nil {
|
||||
return ""
|
||||
}
|
||||
receiverType, err := c.astExprToString(node.Recv.List[0].Type)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// parseFuncParams retrieves the input parameters of the function.
|
||||
// It returns the name and type of the input parameters.
|
||||
// For example:
|
||||
//
|
||||
// []map[string]string{paramName:ctx paramType:context.Context, paramName:info paramType:struct{}}
|
||||
func (c CGenService) parseFuncParams(node *ast.FuncDecl) (params []map[string]string) {
|
||||
if node.Type.Params == nil {
|
||||
return
|
||||
}
|
||||
for _, param := range node.Type.Params.List {
|
||||
if param.Names == nil {
|
||||
// No name for the return value.
|
||||
resultType, err := c.astExprToString(param.Type)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
params = append(params, map[string]string{
|
||||
"paramName": "",
|
||||
"paramType": resultType,
|
||||
})
|
||||
continue
|
||||
}
|
||||
for _, name := range param.Names {
|
||||
paramType, err := c.astExprToString(param.Type)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
params = append(params, map[string]string{
|
||||
"paramName": name.Name,
|
||||
"paramType": paramType,
|
||||
})
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// parseFuncResults retrieves the output parameters of the function.
|
||||
// It returns the name and type of the output parameters.
|
||||
// For example:
|
||||
//
|
||||
// []map[string]string{resultName:list resultType:[]*User, resultName:err resultType:error}
|
||||
// []map[string]string{resultName: "", resultType: error}
|
||||
func (c CGenService) parseFuncResults(node *ast.FuncDecl) (results []map[string]string) {
|
||||
if node.Type.Results == nil {
|
||||
return
|
||||
}
|
||||
for _, result := range node.Type.Results.List {
|
||||
if result.Names == nil {
|
||||
// No name for the return value.
|
||||
resultType, err := c.astExprToString(result.Type)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
results = append(results, map[string]string{
|
||||
"resultName": "",
|
||||
"resultType": resultType,
|
||||
})
|
||||
continue
|
||||
}
|
||||
for _, name := range result.Names {
|
||||
resultType, err := c.astExprToString(result.Type)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
results = append(results, map[string]string{
|
||||
"resultName": name.Name,
|
||||
"resultType": resultType,
|
||||
})
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// parseFuncComment retrieves the comment of the function.
|
||||
func (c CGenService) parseFuncComment(node *ast.FuncDecl) string {
|
||||
return c.astCommentToString(node.Doc)
|
||||
}
|
||||
48
cmd/gf/internal/cmd/genservice/genservice_ast_utils.go
Normal file
48
cmd/gf/internal/cmd/genservice/genservice_ast_utils.go
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package genservice
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"go/ast"
|
||||
"go/format"
|
||||
"go/token"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// exprToString converts ast.Expr to string.
|
||||
// For example:
|
||||
//
|
||||
// ast.Expr -> "context.Context"
|
||||
// ast.Expr -> "*v1.XxxReq"
|
||||
// ast.Expr -> "error"
|
||||
// ast.Expr -> "int"
|
||||
func (c CGenService) astExprToString(expr ast.Expr) (string, error) {
|
||||
var (
|
||||
buf bytes.Buffer
|
||||
err error
|
||||
)
|
||||
err = format.Node(&buf, token.NewFileSet(), expr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
// astCommentToString returns the raw (original) text of the comment.
|
||||
// It includes the comment markers (//, /*, and */).
|
||||
// It adds a newline at the end of the comment.
|
||||
func (c CGenService) astCommentToString(node *ast.CommentGroup) string {
|
||||
if node == nil {
|
||||
return ""
|
||||
}
|
||||
var b strings.Builder
|
||||
for _, c := range node.List {
|
||||
b.WriteString(c.Text + "\n")
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
@ -8,168 +8,145 @@ package genservice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
type packageItem struct {
|
||||
Alias string
|
||||
Path string
|
||||
RawImport string
|
||||
}
|
||||
|
||||
func (c CGenService) calculateImportedPackages(fileContent string) (packages []packageItem, err error) {
|
||||
f, err := parser.ParseFile(token.NewFileSet(), "", fileContent, parser.ImportsOnly)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
packages = make([]packageItem, 0)
|
||||
for _, s := range f.Imports {
|
||||
if s.Path != nil {
|
||||
if s.Name != nil {
|
||||
// If it has alias, and it is not `_`.
|
||||
if pkgAlias := s.Name.String(); pkgAlias != "_" {
|
||||
packages = append(packages, packageItem{
|
||||
Alias: pkgAlias,
|
||||
Path: s.Path.Value,
|
||||
RawImport: pkgAlias + " " + s.Path.Value,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// no alias
|
||||
packages = append(packages, packageItem{
|
||||
Alias: "",
|
||||
Path: s.Path.Value,
|
||||
RawImport: s.Path.Value,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return packages, nil
|
||||
}
|
||||
|
||||
func (c CGenService) calculateCodeCommented(in CGenServiceInput, fileContent string, srcCodeCommentedMap map[string]string) error {
|
||||
matches, err := gregex.MatchAllString(`((((//.*)|(/\*[\s\S]*?\*/))\s)+)func \((.+?)\) ([\s\S]+?) {`, fileContent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, match := range matches {
|
||||
var (
|
||||
structName string
|
||||
structMatch []string
|
||||
funcReceiver = gstr.Trim(match[1+5])
|
||||
receiverArray = gstr.SplitAndTrim(funcReceiver, " ")
|
||||
functionHead = gstr.Trim(gstr.Replace(match[2+5], "\n", ""))
|
||||
commentedInfo = ""
|
||||
)
|
||||
if len(receiverArray) > 1 {
|
||||
structName = receiverArray[1]
|
||||
} else if len(receiverArray) == 1 {
|
||||
structName = receiverArray[0]
|
||||
}
|
||||
structName = gstr.Trim(structName, "*")
|
||||
|
||||
// Case of:
|
||||
// Xxx(\n ctx context.Context, req *v1.XxxReq,\n) -> Xxx(ctx context.Context, req *v1.XxxReq)
|
||||
functionHead = gstr.Replace(functionHead, `,)`, `)`)
|
||||
functionHead, _ = gregex.ReplaceString(`\(\s+`, `(`, functionHead)
|
||||
functionHead, _ = gregex.ReplaceString(`\s{2,}`, ` `, functionHead)
|
||||
if !gstr.IsLetterUpper(functionHead[0]) {
|
||||
continue
|
||||
}
|
||||
// Match and pick the struct name from receiver.
|
||||
if structMatch, err = gregex.MatchString(in.StPattern, structName); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(structMatch) < 1 {
|
||||
continue
|
||||
}
|
||||
structName = gstr.CaseCamel(structMatch[1])
|
||||
|
||||
commentedInfo = match[1]
|
||||
if len(commentedInfo) > 0 {
|
||||
srcCodeCommentedMap[fmt.Sprintf("%s-%s", structName, functionHead)] = commentedInfo
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c CGenService) calculateInterfaceFunctions(
|
||||
in CGenServiceInput, fileContent string, srcPkgInterfaceMap *gmap.ListMap,
|
||||
func (c CGenService) calculateImportedItems(
|
||||
in CGenServiceInput,
|
||||
pkgItems []pkgItem, funcItems []funcItem,
|
||||
srcImportedPackages *garray.SortedStrArray,
|
||||
) (err error) {
|
||||
var (
|
||||
matches [][]string
|
||||
srcPkgInterfaceFuncArray *garray.StrArray
|
||||
)
|
||||
// calculate struct name and its functions according function definitions.
|
||||
matches, err = gregex.MatchAllString(`func \((.+?)\) ([\s\S]+?) {`, fileContent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, match := range matches {
|
||||
var (
|
||||
structName string
|
||||
structMatch []string
|
||||
funcReceiver = gstr.Trim(match[1])
|
||||
receiverArray = gstr.SplitAndTrim(funcReceiver, " ")
|
||||
functionHead = gstr.Trim(gstr.Replace(match[2], "\n", ""))
|
||||
)
|
||||
if len(receiverArray) > 1 {
|
||||
structName = receiverArray[1]
|
||||
} else if len(receiverArray) == 1 {
|
||||
structName = receiverArray[0]
|
||||
}
|
||||
structName = gstr.Trim(structName, "*")
|
||||
// allFuncParamType saves all the param and result types of the functions.
|
||||
var allFuncParamType strings.Builder
|
||||
|
||||
// Case of:
|
||||
// Xxx(\n ctx context.Context, req *v1.XxxReq,\n) -> Xxx(ctx context.Context, req *v1.XxxReq)
|
||||
functionHead = gstr.Replace(functionHead, `,)`, `)`)
|
||||
functionHead, _ = gregex.ReplaceString(`\(\s+`, `(`, functionHead)
|
||||
functionHead, _ = gregex.ReplaceString(`\s{2,}`, ` `, functionHead)
|
||||
if !gstr.IsLetterUpper(functionHead[0]) {
|
||||
continue
|
||||
for _, item := range funcItems {
|
||||
for _, param := range item.Params {
|
||||
allFuncParamType.WriteString(param["paramType"] + ",")
|
||||
}
|
||||
// Match and pick the struct name from receiver.
|
||||
if structMatch, err = gregex.MatchString(in.StPattern, structName); err != nil {
|
||||
return err
|
||||
for _, result := range item.Results {
|
||||
allFuncParamType.WriteString(result["resultType"] + ",")
|
||||
}
|
||||
if len(structMatch) < 1 {
|
||||
continue
|
||||
}
|
||||
structName = gstr.CaseCamel(structMatch[1])
|
||||
if !srcPkgInterfaceMap.Contains(structName) {
|
||||
srcPkgInterfaceFuncArray = garray.NewStrArray()
|
||||
srcPkgInterfaceMap.Set(structName, srcPkgInterfaceFuncArray)
|
||||
} else {
|
||||
srcPkgInterfaceFuncArray = srcPkgInterfaceMap.Get(structName).(*garray.StrArray)
|
||||
}
|
||||
srcPkgInterfaceFuncArray.Append(functionHead)
|
||||
}
|
||||
// calculate struct name according type definitions.
|
||||
matches, err = gregex.MatchAllString(`type (.+) struct\s*{`, fileContent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, match := range matches {
|
||||
var (
|
||||
structName string
|
||||
structMatch []string
|
||||
)
|
||||
if structMatch, err = gregex.MatchString(in.StPattern, match[1]); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(structMatch) < 1 {
|
||||
|
||||
for _, item := range pkgItems {
|
||||
alias := item.Alias
|
||||
|
||||
// If the alias is _, it means that the package is not generated.
|
||||
if alias == "_" {
|
||||
mlog.Debugf(`ignore anonymous package: %s`, item.RawImport)
|
||||
continue
|
||||
}
|
||||
structName = gstr.CaseCamel(structMatch[1])
|
||||
if !srcPkgInterfaceMap.Contains(structName) {
|
||||
srcPkgInterfaceMap.Set(structName, garray.NewStrArray())
|
||||
// If the alias is empty, it will use the package name as the alias.
|
||||
if alias == "" {
|
||||
alias = gfile.Basename(gstr.Trim(item.Path, `"`))
|
||||
}
|
||||
if !gstr.Contains(allFuncParamType.String(), alias) {
|
||||
mlog.Debugf(`ignore unused package: %s`, item.RawImport)
|
||||
continue
|
||||
}
|
||||
srcImportedPackages.Add(item.RawImport)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c CGenService) calculateFuncItems(
|
||||
in CGenServiceInput,
|
||||
funcItems []funcItem,
|
||||
srcPkgInterfaceMap *gmap.ListMap,
|
||||
) (err error) {
|
||||
var srcPkgInterfaceFunc []map[string]string
|
||||
|
||||
for _, item := range funcItems {
|
||||
var (
|
||||
// eg: "sArticle"
|
||||
receiverName string
|
||||
receiverMatch []string
|
||||
|
||||
// eg: "GetList(ctx context.Context, req *v1.ArticleListReq) (list []*v1.Article, err error)"
|
||||
funcHead string
|
||||
)
|
||||
|
||||
// handle the receiver name.
|
||||
if item.Receiver == "" {
|
||||
continue
|
||||
}
|
||||
receiverName = item.Receiver
|
||||
receiverName = gstr.Trim(receiverName, "*")
|
||||
// Match and pick the struct name from receiver.
|
||||
if receiverMatch, err = gregex.MatchString(in.StPattern, receiverName); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(receiverMatch) < 1 {
|
||||
continue
|
||||
}
|
||||
receiverName = gstr.CaseCamel(receiverMatch[1])
|
||||
|
||||
// check if the func name is public.
|
||||
if !gstr.IsLetterUpper(item.MethodName[0]) {
|
||||
continue
|
||||
}
|
||||
|
||||
if !srcPkgInterfaceMap.Contains(receiverName) {
|
||||
srcPkgInterfaceFunc = make([]map[string]string, 0)
|
||||
srcPkgInterfaceMap.Set(receiverName, srcPkgInterfaceFunc)
|
||||
} else {
|
||||
srcPkgInterfaceFunc = srcPkgInterfaceMap.Get(receiverName).([]map[string]string)
|
||||
}
|
||||
|
||||
// make the func head.
|
||||
paramsStr := c.tidyParam(item.Params)
|
||||
resultsStr := c.tidyResult(item.Results)
|
||||
funcHead = fmt.Sprintf("%s(%s) (%s)", item.MethodName, paramsStr, resultsStr)
|
||||
|
||||
srcPkgInterfaceFunc = append(srcPkgInterfaceFunc, map[string]string{
|
||||
"funcHead": funcHead,
|
||||
"funcComment": item.Comment,
|
||||
})
|
||||
srcPkgInterfaceMap.Set(receiverName, srcPkgInterfaceFunc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// tidyParam tidies the input parameters.
|
||||
// For example:
|
||||
//
|
||||
// []map[string]string{paramName:ctx paramType:context.Context, paramName:info paramType:struct{}}
|
||||
// -> ctx context.Context, info struct{}
|
||||
func (c CGenService) tidyParam(paramSlice []map[string]string) (paramStr string) {
|
||||
for i, param := range paramSlice {
|
||||
if i > 0 {
|
||||
paramStr += ", "
|
||||
}
|
||||
paramStr += fmt.Sprintf("%s %s", param["paramName"], param["paramType"])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// tidyResult tidies the output parameters.
|
||||
// For example:
|
||||
//
|
||||
// []map[string]string{resultName:list resultType:[]*User, resultName:err resultType:error}
|
||||
// -> list []*User, err error
|
||||
//
|
||||
// []map[string]string{resultName: "", resultType: error}
|
||||
// -> error
|
||||
func (c CGenService) tidyResult(resultSlice []map[string]string) (resultStr string) {
|
||||
for i, result := range resultSlice {
|
||||
if i > 0 {
|
||||
resultStr += ", "
|
||||
}
|
||||
if result["resultName"] != "" {
|
||||
resultStr += fmt.Sprintf("%s %s", result["resultName"], result["resultType"])
|
||||
} else {
|
||||
resultStr += result["resultType"]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -7,112 +7,34 @@
|
||||
package genservice
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
type generateServiceFilesInput struct {
|
||||
CGenServiceInput
|
||||
DstFilePath string // Absolute file path for generated service go file.
|
||||
SrcStructFunctions *gmap.ListMap
|
||||
SrcImportedPackages []string
|
||||
SrcPackageName string
|
||||
SrcImportedPackages []string
|
||||
SrcStructFunctions *gmap.ListMap
|
||||
DstPackageName string
|
||||
SrcCodeCommentedMap map[string]string
|
||||
DstFilePath string // Absolute file path for generated service go file.
|
||||
}
|
||||
|
||||
func (c CGenService) generateServiceFile(in generateServiceFilesInput) (ok bool, err error) {
|
||||
var (
|
||||
generatedContent string
|
||||
allFuncArray = garray.NewStrArray() // Used for check whether interface dirty, going to change file content.
|
||||
importedPackagesContent = fmt.Sprintf(
|
||||
"import (\n%s\n)", gstr.Join(in.SrcImportedPackages, "\n"),
|
||||
)
|
||||
)
|
||||
generatedContent += gstr.ReplaceByMap(consts.TemplateGenServiceContentHead, g.MapStrStr{
|
||||
"{Imports}": importedPackagesContent,
|
||||
"{PackageName}": in.DstPackageName,
|
||||
})
|
||||
var generatedContent bytes.Buffer
|
||||
|
||||
// Type definitions.
|
||||
generatedContent += "type("
|
||||
generatedContent += "\n"
|
||||
in.SrcStructFunctions.Iterator(func(key, value interface{}) bool {
|
||||
structName, funcArray := key.(string), value.(*garray.StrArray)
|
||||
allFuncArray.Append(funcArray.Slice()...)
|
||||
// Add comments to a method.
|
||||
for index, funcName := range funcArray.Slice() {
|
||||
if commentedInfo, exist := in.SrcCodeCommentedMap[fmt.Sprintf("%s-%s", structName, funcName)]; exist {
|
||||
funcName = commentedInfo + funcName
|
||||
_ = funcArray.Set(index, funcName)
|
||||
}
|
||||
}
|
||||
generatedContent += gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentInterface, g.MapStrStr{
|
||||
"{InterfaceName}": "I" + structName,
|
||||
"{FuncDefinition}": funcArray.Join("\n\t"),
|
||||
}))
|
||||
generatedContent += "\n"
|
||||
return true
|
||||
})
|
||||
generatedContent += ")"
|
||||
generatedContent += "\n"
|
||||
|
||||
// Generating variable and register definitions.
|
||||
var (
|
||||
variableContent string
|
||||
generatingInterfaceCheck string
|
||||
)
|
||||
// Variable definitions.
|
||||
in.SrcStructFunctions.Iterator(func(key, value interface{}) bool {
|
||||
structName := key.(string)
|
||||
generatingInterfaceCheck = fmt.Sprintf(`[^\w\d]+%s.I%s[^\w\d]`, in.DstPackageName, structName)
|
||||
if gregex.IsMatchString(generatingInterfaceCheck, generatedContent) {
|
||||
return true
|
||||
}
|
||||
variableContent += gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentVariable, g.MapStrStr{
|
||||
"{StructName}": structName,
|
||||
"{InterfaceName}": "I" + structName,
|
||||
}))
|
||||
variableContent += "\n"
|
||||
return true
|
||||
})
|
||||
if variableContent != "" {
|
||||
generatedContent += "var("
|
||||
generatedContent += "\n"
|
||||
generatedContent += variableContent
|
||||
generatedContent += ")"
|
||||
generatedContent += "\n"
|
||||
}
|
||||
// Variable register function definitions.
|
||||
in.SrcStructFunctions.Iterator(func(key, value interface{}) bool {
|
||||
structName := key.(string)
|
||||
generatingInterfaceCheck = fmt.Sprintf(`[^\w\d]+%s.I%s[^\w\d]`, in.DstPackageName, structName)
|
||||
if gregex.IsMatchString(generatingInterfaceCheck, generatedContent) {
|
||||
return true
|
||||
}
|
||||
generatedContent += gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentRegister, g.MapStrStr{
|
||||
"{StructName}": structName,
|
||||
"{InterfaceName}": "I" + structName,
|
||||
}))
|
||||
generatedContent += "\n\n"
|
||||
return true
|
||||
})
|
||||
|
||||
// Replace empty braces that have new line.
|
||||
generatedContent, _ = gregex.ReplaceString(`{[\s\t]+}`, `{}`, generatedContent)
|
||||
|
||||
// Remove package name calls of `dstPackageName` in produced codes.
|
||||
generatedContent, _ = gregex.ReplaceString(fmt.Sprintf(`\*{0,1}%s\.`, in.DstPackageName), ``, generatedContent)
|
||||
c.generatePackageImports(&generatedContent, in.DstPackageName, in.SrcImportedPackages)
|
||||
c.generateType(&generatedContent, in.SrcStructFunctions, in.DstPackageName)
|
||||
c.generateVar(&generatedContent, in.SrcStructFunctions)
|
||||
c.generateFunc(&generatedContent, in.SrcStructFunctions)
|
||||
|
||||
// Write file content to disk.
|
||||
if gfile.Exists(in.DstFilePath) {
|
||||
@ -120,59 +42,14 @@ func (c CGenService) generateServiceFile(in generateServiceFilesInput) (ok bool,
|
||||
mlog.Printf(`ignore file as it is manually maintained: %s`, in.DstFilePath)
|
||||
return false, nil
|
||||
}
|
||||
if !c.isToGenerateServiceGoFile(in.DstPackageName, in.DstFilePath, allFuncArray) {
|
||||
mlog.Printf(`not dirty, ignore generating service go file: %s`, in.DstFilePath)
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
mlog.Printf(`generating service go file: %s`, in.DstFilePath)
|
||||
if err = gfile.PutContents(in.DstFilePath, generatedContent); err != nil {
|
||||
if err = gfile.PutBytes(in.DstFilePath, generatedContent.Bytes()); err != nil {
|
||||
return true, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// isToGenerateServiceGoFile checks and returns whether the service content dirty.
|
||||
func (c CGenService) isToGenerateServiceGoFile(dstPackageName, filePath string, funcArray *garray.StrArray) bool {
|
||||
var (
|
||||
err error
|
||||
fileContent = gfile.GetContents(filePath)
|
||||
generatedFuncArray = garray.NewSortedStrArrayFrom(funcArray.Slice())
|
||||
contentFuncArray = garray.NewSortedStrArray()
|
||||
)
|
||||
if fileContent == "" {
|
||||
return true
|
||||
}
|
||||
// remove all comments.
|
||||
fileContent, err = gregex.ReplaceString(`(//.*)|((?s)/\*.*?\*/)`, "", fileContent)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return false
|
||||
}
|
||||
matches, _ := gregex.MatchAllString(`\s+interface\s+{([\s\S]+?)}`, fileContent)
|
||||
for _, match := range matches {
|
||||
contentFuncArray.Append(gstr.SplitAndTrim(match[1], "\n")...)
|
||||
}
|
||||
if generatedFuncArray.Len() != contentFuncArray.Len() {
|
||||
mlog.Debugf(
|
||||
`dirty, generatedFuncArray.Len()[%d] != contentFuncArray.Len()[%d]`,
|
||||
generatedFuncArray.Len(), contentFuncArray.Len(),
|
||||
)
|
||||
return true
|
||||
}
|
||||
var funcDefinition string
|
||||
for i := 0; i < generatedFuncArray.Len(); i++ {
|
||||
funcDefinition, _ = gregex.ReplaceString(
|
||||
fmt.Sprintf(`\*{0,1}%s\.`, dstPackageName), ``, generatedFuncArray.At(i),
|
||||
)
|
||||
if funcDefinition != contentFuncArray.At(i) {
|
||||
mlog.Debugf(`dirty, %s != %s`, funcDefinition, contentFuncArray.At(i))
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// generateInitializationFile generates `logic.go`.
|
||||
func (c CGenService) generateInitializationFile(in CGenServiceInput, importSrcPackages []string) (err error) {
|
||||
var (
|
||||
|
||||
104
cmd/gf/internal/cmd/genservice/genservice_generate_template.go
Normal file
104
cmd/gf/internal/cmd/genservice/genservice_generate_template.go
Normal file
@ -0,0 +1,104 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package genservice
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
func (c CGenService) generatePackageImports(generatedContent *bytes.Buffer, packageName string, imports []string) {
|
||||
generatedContent.WriteString(gstr.ReplaceByMap(consts.TemplateGenServiceContentHead, g.MapStrStr{
|
||||
"{PackageName}": packageName,
|
||||
"{Imports}": fmt.Sprintf(
|
||||
"import (\n%s\n)", gstr.Join(imports, "\n"),
|
||||
),
|
||||
}))
|
||||
}
|
||||
|
||||
// generateType type definitions.
|
||||
// See: const.TemplateGenServiceContentInterface
|
||||
func (c CGenService) generateType(generatedContent *bytes.Buffer, srcStructFunctions *gmap.ListMap, dstPackageName string) {
|
||||
generatedContent.WriteString("type(")
|
||||
generatedContent.WriteString("\n")
|
||||
|
||||
srcStructFunctions.Iterator(func(key, value interface{}) bool {
|
||||
var (
|
||||
funcContents = make([]string, 0)
|
||||
funcContent string
|
||||
)
|
||||
structName, funcSlice := key.(string), value.([]map[string]string)
|
||||
// Generating interface content.
|
||||
for _, funcInfo := range funcSlice {
|
||||
// Remove package name calls of `dstPackageName` in produced codes.
|
||||
funcHead, _ := gregex.ReplaceString(
|
||||
fmt.Sprintf(`\*{0,1}%s\.`, dstPackageName),
|
||||
``, funcInfo["funcHead"],
|
||||
)
|
||||
funcContent = funcInfo["funcComment"] + funcHead
|
||||
funcContents = append(funcContents, funcContent)
|
||||
}
|
||||
|
||||
// funcContents to string.
|
||||
generatedContent.WriteString(
|
||||
gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentInterface, g.MapStrStr{
|
||||
"{InterfaceName}": "I" + structName,
|
||||
"{FuncDefinition}": gstr.Join(funcContents, "\n\t"),
|
||||
})),
|
||||
)
|
||||
generatedContent.WriteString("\n")
|
||||
return true
|
||||
})
|
||||
|
||||
generatedContent.WriteString(")")
|
||||
generatedContent.WriteString("\n")
|
||||
}
|
||||
|
||||
// generateVar variable definitions.
|
||||
// See: const.TemplateGenServiceContentVariable
|
||||
func (c CGenService) generateVar(generatedContent *bytes.Buffer, srcStructFunctions *gmap.ListMap) {
|
||||
// Generating variable and register definitions.
|
||||
var variableContent string
|
||||
|
||||
srcStructFunctions.Iterator(func(key, value interface{}) bool {
|
||||
structName := key.(string)
|
||||
variableContent += gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentVariable, g.MapStrStr{
|
||||
"{StructName}": structName,
|
||||
"{InterfaceName}": "I" + structName,
|
||||
}))
|
||||
variableContent += "\n"
|
||||
return true
|
||||
})
|
||||
if variableContent != "" {
|
||||
generatedContent.WriteString("var(")
|
||||
generatedContent.WriteString("\n")
|
||||
generatedContent.WriteString(variableContent)
|
||||
generatedContent.WriteString(")")
|
||||
generatedContent.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
// generateFunc function definitions.
|
||||
// See: const.TemplateGenServiceContentRegister
|
||||
func (c CGenService) generateFunc(generatedContent *bytes.Buffer, srcStructFunctions *gmap.ListMap) {
|
||||
// Variable register function definitions.
|
||||
srcStructFunctions.Iterator(func(key, value interface{}) bool {
|
||||
structName := key.(string)
|
||||
generatedContent.WriteString(gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentRegister, g.MapStrStr{
|
||||
"{StructName}": structName,
|
||||
"{InterfaceName}": "I" + structName,
|
||||
})))
|
||||
generatedContent.WriteString("\n\n")
|
||||
return true
|
||||
})
|
||||
}
|
||||
@ -8,8 +8,11 @@ package article
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go/ast"
|
||||
t "time"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/service"
|
||||
gdbalias "github.com/gogf/gf/v2/database/gdb"
|
||||
)
|
||||
|
||||
type sArticle struct {
|
||||
@ -30,5 +33,15 @@ func (s *sArticle) Get(ctx context.Context, id uint) (info struct{}, err error)
|
||||
* @author oldme
|
||||
*/
|
||||
func (s *sArticle) Create(ctx context.Context, info struct{}) (id uint, err error) {
|
||||
// Use time package to test alias import.
|
||||
t.Now()
|
||||
return id, err
|
||||
}
|
||||
|
||||
func (s *sArticle) A1o2(ctx context.Context, str string, a, b *ast.GoStmt) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sArticle) B_2(ctx context.Context, db gdbalias.Raw) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
75
cmd/gf/internal/cmd/testdata/genservice/logic/article/article_extra.go
vendored
Normal file
75
cmd/gf/internal/cmd/testdata/genservice/logic/article/article_extra.go
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package article
|
||||
|
||||
// import (
|
||||
// "context"
|
||||
//
|
||||
// "github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/service"
|
||||
// )
|
||||
import (
|
||||
"context"
|
||||
|
||||
// This is a random comment
|
||||
gdbas "github.com/gogf/gf/v2/database/gdb"
|
||||
/**
|
||||
*
|
||||
*/
|
||||
_ "github.com/gogf/gf/v2/os/gfile"
|
||||
)
|
||||
|
||||
// T1 random comment
|
||||
func (s sArticle) T1(ctx context.Context, id, id2 uint) (gdb gdbas.Model, err error) {
|
||||
g := gdbas.Model{}
|
||||
return g, err
|
||||
}
|
||||
|
||||
// I'm a random comment
|
||||
|
||||
// t2 random comment
|
||||
func (s *sArticle) t2(ctx context.Context) (err error) {
|
||||
/**
|
||||
* random comment
|
||||
* i (1). func (s *sArticle) t2(ctx context.Context) (err error) { /** 1883
|
||||
*
|
||||
*/
|
||||
_ = func(ctx2 context.Context) {}
|
||||
return nil
|
||||
}
|
||||
|
||||
// T3
|
||||
/**
|
||||
* random comment @*4213hHY1&%##%><<Y
|
||||
* @param b
|
||||
* @return c, d
|
||||
* @return err
|
||||
* @author oldme
|
||||
*/
|
||||
func (s *sArticle) T3(ctx context.Context, b *gdbas.Model) (c, d *gdbas.Model, err error) {
|
||||
/* import (
|
||||
* "context"
|
||||
*
|
||||
* "github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/service"
|
||||
*/
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
/**
|
||||
* random comment
|
||||
*/
|
||||
|
||||
// func (s *sArticle) T4(i interface{}) interface{}
|
||||
// # $ % ^ & * ( ) _ + - = { } | [ ] \ : " ; ' < > ? , . /
|
||||
func (s *sArticle) T4(i interface{}) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
/**
|
||||
* func (s *sArticle) T4(i interface{}) interface{} {
|
||||
* return nil
|
||||
* }
|
||||
*/
|
||||
38
cmd/gf/internal/cmd/testdata/genservice/logic/delivery/delivery_app.go
vendored
Normal file
38
cmd/gf/internal/cmd/testdata/genservice/logic/delivery/delivery_app.go
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package delivery
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/service"
|
||||
)
|
||||
|
||||
type sDeliveryApp struct{}
|
||||
|
||||
func NewDeliveryApp() *sDeliveryApp {
|
||||
return &sDeliveryApp{}
|
||||
}
|
||||
|
||||
func (s *sDeliveryApp) Create(ctx context.Context) (i service.IDeliveryCluster, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (s *sDeliveryApp) GetList(ctx context.Context, i service.IDeliveryCluster) (err error) {
|
||||
service.Article().Get(ctx, 1)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *sDeliveryApp) GetOne(ctx context.Context) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (s *sDeliveryApp) Delete(ctx context.Context) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (s *sDeliveryApp) AA(ctx context.Context) (err error) { return }
|
||||
32
cmd/gf/internal/cmd/testdata/genservice/logic/delivery/delivery_cluster.go
vendored
Normal file
32
cmd/gf/internal/cmd/testdata/genservice/logic/delivery/delivery_cluster.go
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package delivery
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
gdbas "github.com/gogf/gf/v2/database/gdb"
|
||||
)
|
||||
|
||||
type sDeliveryCluster struct{}
|
||||
|
||||
func NewDeliveryCluster() *sDeliveryCluster {
|
||||
return &sDeliveryCluster{}
|
||||
}
|
||||
|
||||
// Create 自动创建Cluster及Project.
|
||||
func (s *sDeliveryCluster) Create(ctx context.Context) (err error, gdb gdbas.Model) {
|
||||
return
|
||||
}
|
||||
|
||||
func (s *sDeliveryCluster) Delete(ctx context.Context) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (s *sDeliveryCluster) GetList(ctx context.Context) (err error) {
|
||||
return
|
||||
}
|
||||
@ -6,4 +6,6 @@ package logic
|
||||
|
||||
import (
|
||||
_ "github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/logic/article"
|
||||
_ "github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/logic/delivery"
|
||||
_ "github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/logic/user"
|
||||
)
|
||||
|
||||
49
cmd/gf/internal/cmd/testdata/genservice/logic/user/user.go
vendored
Normal file
49
cmd/gf/internal/cmd/testdata/genservice/logic/user/user.go
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/testdata/genservice/service"
|
||||
)
|
||||
|
||||
func init() {
|
||||
service.RegisterUser(New())
|
||||
}
|
||||
|
||||
type sUser struct {
|
||||
}
|
||||
|
||||
func New() *sUser {
|
||||
return &sUser{}
|
||||
}
|
||||
|
||||
// Create creates a new user.
|
||||
func (s *sUser) Create(ctx context.Context, name string) (id int, err error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// GetOne retrieves user by id.
|
||||
func (s *sUser) GetOne(ctx context.Context, id int) (name string, err error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// GetList retrieves user list.
|
||||
func (s *sUser) GetList(ctx context.Context) (names []string, err error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Update updates user by id.
|
||||
func (s *sUser) Update(ctx context.Context, id int) (name string, err error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Delete deletes user by id.
|
||||
func (s *sUser) Delete(ctx context.Context, id int) (err error) {
|
||||
return nil
|
||||
}
|
||||
@ -7,6 +7,10 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go/ast"
|
||||
|
||||
gdbalias "github.com/gogf/gf/v2/database/gdb"
|
||||
gdbas "github.com/gogf/gf/v2/database/gdb"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -19,6 +23,22 @@ type (
|
||||
* @author oldme
|
||||
*/
|
||||
Create(ctx context.Context, info struct{}) (id uint, err error)
|
||||
A1o2(ctx context.Context, str string, a *ast.GoStmt, b *ast.GoStmt) error
|
||||
B_2(ctx context.Context, db gdbalias.Raw) (err error)
|
||||
// T1 random comment
|
||||
T1(ctx context.Context, id uint, id2 uint) (gdb gdbas.Model, err error)
|
||||
// T3
|
||||
/**
|
||||
* random comment @*4213hHY1&%##%><<Y
|
||||
* @param b
|
||||
* @return c, d
|
||||
* @return err
|
||||
* @author oldme
|
||||
*/
|
||||
T3(ctx context.Context, b *gdbas.Model) (c *gdbas.Model, d *gdbas.Model, err error)
|
||||
// func (s *sArticle) T4(i interface{}) interface{}
|
||||
// # $ % ^ & * ( ) _ + - = { } | [ ] \ : " ; ' < > ? , . /
|
||||
T4(i interface{}) interface{}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
55
cmd/gf/internal/cmd/testdata/genservice/service/delivery.go
vendored
Normal file
55
cmd/gf/internal/cmd/testdata/genservice/service/delivery.go
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
// ================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// You can delete these comments if you wish manually maintain this interface file.
|
||||
// ================================================================================
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
gdbas "github.com/gogf/gf/v2/database/gdb"
|
||||
)
|
||||
|
||||
type (
|
||||
IDeliveryApp interface {
|
||||
Create(ctx context.Context) (i IDeliveryCluster, err error)
|
||||
GetList(ctx context.Context, i IDeliveryCluster) (err error)
|
||||
GetOne(ctx context.Context) (err error)
|
||||
Delete(ctx context.Context) (err error)
|
||||
AA(ctx context.Context) (err error)
|
||||
}
|
||||
IDeliveryCluster interface {
|
||||
// Create 自动创建Cluster及Project.
|
||||
Create(ctx context.Context) (err error, gdb gdbas.Model)
|
||||
Delete(ctx context.Context) (err error)
|
||||
GetList(ctx context.Context) (err error)
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
localDeliveryApp IDeliveryApp
|
||||
localDeliveryCluster IDeliveryCluster
|
||||
)
|
||||
|
||||
func DeliveryApp() IDeliveryApp {
|
||||
if localDeliveryApp == nil {
|
||||
panic("implement not found for interface IDeliveryApp, forgot register?")
|
||||
}
|
||||
return localDeliveryApp
|
||||
}
|
||||
|
||||
func RegisterDeliveryApp(i IDeliveryApp) {
|
||||
localDeliveryApp = i
|
||||
}
|
||||
|
||||
func DeliveryCluster() IDeliveryCluster {
|
||||
if localDeliveryCluster == nil {
|
||||
panic("implement not found for interface IDeliveryCluster, forgot register?")
|
||||
}
|
||||
return localDeliveryCluster
|
||||
}
|
||||
|
||||
func RegisterDeliveryCluster(i IDeliveryCluster) {
|
||||
localDeliveryCluster = i
|
||||
}
|
||||
40
cmd/gf/internal/cmd/testdata/genservice/service/user.go
vendored
Normal file
40
cmd/gf/internal/cmd/testdata/genservice/service/user.go
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
// ================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// You can delete these comments if you wish manually maintain this interface file.
|
||||
// ================================================================================
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type (
|
||||
IUser interface {
|
||||
// Create creates a new user.
|
||||
Create(ctx context.Context, name string) (id int, err error)
|
||||
// GetOne retrieves user by id.
|
||||
GetOne(ctx context.Context, id int) (name string, err error)
|
||||
// GetList retrieves user list.
|
||||
GetList(ctx context.Context) (names []string, err error)
|
||||
// Update updates user by id.
|
||||
Update(ctx context.Context, id int) (name string, err error)
|
||||
// Delete deletes user by id.
|
||||
Delete(ctx context.Context, id int) (err error)
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
localUser IUser
|
||||
)
|
||||
|
||||
func User() IUser {
|
||||
if localUser == nil {
|
||||
panic("implement not found for interface IUser, forgot register?")
|
||||
}
|
||||
return localUser
|
||||
}
|
||||
|
||||
func RegisterUser(i IUser) {
|
||||
localUser = i
|
||||
}
|
||||
Reference in New Issue
Block a user