Skip to content

Commit

Permalink
improve command gen ctrl and gen service (#2711)
Browse files Browse the repository at this point in the history
  • Loading branch information
gqcn authored Jun 19, 2023
1 parent d6433de commit c5c2938
Show file tree
Hide file tree
Showing 34 changed files with 321 additions and 138 deletions.
14 changes: 7 additions & 7 deletions cmd/gf/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ module github.com/gogf/gf/cmd/gf/v2
go 1.18

require (
github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.4.3
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.4.3
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.4.3
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.4.3
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.4.3
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.4.3
github.com/gogf/gf/v2 v2.4.3
github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.4.4
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.4.4
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.4.4
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.4.4
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.4.4
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.4.4
github.com/gogf/gf/v2 v2.4.4
github.com/minio/selfupdate v0.6.0
github.com/olekukonko/tablewriter v0.0.5
golang.org/x/tools v0.7.0
Expand Down
66 changes: 51 additions & 15 deletions cmd/gf/internal/cmd/genctrl/genctrl.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ gf gen ctrl
CGenCtrlBriefSdkPath = `also generate SDK go files for api definitions to specified directory`
CGenCtrlBriefSdkStdVersion = `use standard version prefix for generated sdk request path`
CGenCtrlBriefSdkNoV1 = `do not add version suffix for interface module name if version is v1`
CGenCtrlBriefClear = `auto delete generated and unimplemented controller go files if api definitions are missing`
)

const (
Expand All @@ -56,6 +57,7 @@ func init() {
`CGenCtrlBriefSdkPath`: CGenCtrlBriefSdkPath,
`CGenCtrlBriefSdkStdVersion`: CGenCtrlBriefSdkStdVersion,
`CGenCtrlBriefSdkNoV1`: CGenCtrlBriefSdkNoV1,
`CGenCtrlBriefClear`: CGenCtrlBriefClear,
})
}

Expand All @@ -69,13 +71,17 @@ type (
SdkPath string `short:"k" name:"sdkPath" brief:"{CGenCtrlBriefSdkPath}"`
SdkStdVersion bool `short:"v" name:"sdkStdVersion" brief:"{CGenCtrlBriefSdkStdVersion}" orphan:"true"`
SdkNoV1 bool `short:"n" name:"sdkNoV1" brief:"{CGenCtrlBriefSdkNoV1}" orphan:"true"`
Clear bool `short:"c" name:"clear" brief:"{CGenCtrlBriefClear}" orphan:"true"`
}
CGenCtrlOutput struct{}
)

func (c CGenCtrl) Ctrl(ctx context.Context, in CGenCtrlInput) (out *CGenCtrlOutput, err error) {
if in.WatchFile != "" {
err = c.generateByWatchFile(in.WatchFile, in.SdkPath, in.SdkStdVersion, in.SdkNoV1)
err = c.generateByWatchFile(
in.WatchFile, in.SdkPath, in.SdkStdVersion, in.SdkNoV1, in.Clear,
)
mlog.Print(`done!`)
return
}

Expand All @@ -96,7 +102,10 @@ func (c CGenCtrl) Ctrl(ctx context.Context, in CGenCtrlInput) (out *CGenCtrlOutp
module = gfile.Basename(apiModuleFolderPath)
dstModuleFolderPath = gfile.Join(in.DstFolder, module)
)
err = c.generateByModule(apiModuleFolderPath, dstModuleFolderPath, in.SdkPath, in.SdkStdVersion, in.SdkNoV1)
err = c.generateByModule(
apiModuleFolderPath, dstModuleFolderPath, in.SdkPath,
in.SdkStdVersion, in.SdkNoV1, in.Clear,
)
if err != nil {
return nil, err
}
Expand All @@ -106,7 +115,7 @@ func (c CGenCtrl) Ctrl(ctx context.Context, in CGenCtrlInput) (out *CGenCtrlOutp
return
}

func (c CGenCtrl) generateByWatchFile(watchFile, sdkPath string, sdkStdVersion, sdkNoV1 bool) (err error) {
func (c CGenCtrl) generateByWatchFile(watchFile, sdkPath string, sdkStdVersion, sdkNoV1, clear bool) (err error) {
// File lock to avoid multiple processes.
var (
flockFilePath = gfile.Temp("gf.cli.gen.service.lock")
Expand All @@ -133,20 +142,26 @@ func (c CGenCtrl) generateByWatchFile(watchFile, sdkPath string, sdkStdVersion,
return nil
}
// watch file should have api definitions.
if !gregex.IsMatchString(PatternApiDefinition, gfile.GetContents(watchFile)) {
return nil
if gfile.Exists(watchFile) {
if !gregex.IsMatchString(PatternApiDefinition, gfile.GetContents(watchFile)) {
return nil
}
}

var (
projectRootPath = gfile.Dir(gfile.Dir(apiModuleFolderPath))
module = gfile.Basename(apiModuleFolderPath)
dstModuleFolderPath = gfile.Join(projectRootPath, "internal", "controller", module)
)
return c.generateByModule(apiModuleFolderPath, dstModuleFolderPath, sdkPath, sdkStdVersion, sdkNoV1)
return c.generateByModule(
apiModuleFolderPath, dstModuleFolderPath, sdkPath, sdkStdVersion, sdkNoV1, clear,
)
}

// parseApiModule parses certain api and generate associated go files by certain module, not all api modules.
func (c CGenCtrl) generateByModule(
apiModuleFolderPath, dstModuleFolderPath, sdkPath string, sdkStdVersion, sdkNoV1 bool,
apiModuleFolderPath, dstModuleFolderPath, sdkPath string,
sdkStdVersion, sdkNoV1, clear bool,
) (err error) {
// parse src and dst folder go files.
apiItemsInSrc, err := c.getApiItemsInSrc(apiModuleFolderPath)
Expand All @@ -158,6 +173,12 @@ func (c CGenCtrl) generateByModule(
return err
}

// generate api interface go files.
if err = newApiInterfaceGenerator().Generate(apiModuleFolderPath, apiItemsInSrc); err != nil {
return
}

// generate controller go files.
// api filtering for already implemented api controllers.
var (
alreadyImplementedCtrlSet = gset.NewStrSet()
Expand All @@ -172,26 +193,41 @@ func (c CGenCtrl) generateByModule(
}
toBeImplementedApiItems = append(toBeImplementedApiItems, item)
}

// generate api interface go files.
if err = newApiInterfaceGenerator().Generate(apiModuleFolderPath, apiItemsInSrc); err != nil {
return
}

// generate controller go files.
if len(toBeImplementedApiItems) > 0 {
err = newControllerGenerator().Generate(dstModuleFolderPath, toBeImplementedApiItems)
if err != nil {
return
}
}

// delete unimplemented controllers if api definitions are missing.
if clear {
var (
apiDefinitionSet = gset.NewStrSet()
extraApiItemsInCtrl = make([]apiItem, 0)
)
for _, item := range apiItemsInSrc {
apiDefinitionSet.Add(item.String())
}
for _, item := range apiItemsInDst {
if apiDefinitionSet.Contains(item.String()) {
continue
}
extraApiItemsInCtrl = append(extraApiItemsInCtrl, item)
}
if len(extraApiItemsInCtrl) > 0 {
err = newControllerClearer().Clear(dstModuleFolderPath, extraApiItemsInCtrl)
if err != nil {
return
}
}
}

// generate sdk go files.
if sdkPath != "" {
if err = newApiSdkGenerator().Generate(apiItemsInSrc, sdkPath, sdkStdVersion, sdkNoV1); err != nil {
return
}
}

return
}
57 changes: 57 additions & 0 deletions cmd/gf/internal/cmd/genctrl/genctrl_generate_ctrl_clear.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// 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 genctrl

import (
"fmt"

"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
)

type controllerClearer struct{}

func newControllerClearer() *controllerClearer {
return &controllerClearer{}
}

func (c *controllerClearer) Clear(dstModuleFolderPath string, extraApiItemsInCtrl []apiItem) (err error) {
for _, item := range extraApiItemsInCtrl {
if err = c.doClear(dstModuleFolderPath, item); err != nil {
return err
}
}
return
}

func (c *controllerClearer) doClear(dstModuleFolderPath string, item apiItem) (err error) {
var (
methodNameSnake = gstr.CaseSnake(item.MethodName)
methodFilePath = gfile.Join(dstModuleFolderPath, fmt.Sprintf(
`%s_%s_%s.go`, item.Module, item.Version, methodNameSnake,
))
fileContent = gstr.Trim(gfile.GetContents(methodFilePath))
)
match, err := gregex.MatchString(`.+?Req.+?Res.+?{([\s\S]+?)}`, fileContent)
if err != nil {
return err
}
if len(match) > 1 {
implements := gstr.Trim(match[1])
// One line.
if !gstr.Contains(implements, "\n") && gstr.Contains(implements, `CodeNotImplemented`) {
mlog.Printf(
`remove unimplemented and of no api definitions controller file: %s`,
methodFilePath,
)
err = gfile.Remove(methodFilePath)
}
}
return
}
25 changes: 2 additions & 23 deletions cmd/gf/internal/cmd/gendao/gendao.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gtag"

Expand Down Expand Up @@ -180,7 +179,6 @@ type (
DB gdb.DB
TableNames []string
NewTableNames []string
ModName string // Module name of current golang project, which is used for import purpose.
}
)

Expand All @@ -204,9 +202,8 @@ func (c CGenDao) Dao(ctx context.Context, in CGenDaoInput) (out *CGenDaoOutput,
// doGenDaoForArray implements the "gen dao" command for configuration array.
func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
var (
err error
db gdb.DB
modName string // Go module name, eg: github.com/gogf/gf.
err error
db gdb.DB
)
if index >= 0 {
err = g.Cfg().MustGet(
Expand All @@ -221,21 +218,6 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
mlog.Fatalf(`path "%s" does not exist`, in.Path)
}
removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
if in.ImportPrefix == "" {
mlog.Debug(`import prefix is empty, trying calculating the import package path using go.mod`)
if !gfile.Exists("go.mod") {
mlog.Fatal("go.mod does not exist in current working directory")
}
var (
goModContent = gfile.GetContents("go.mod")
match, _ = gregex.MatchString(`^module\s+(.+)\s*`, goModContent)
)
if len(match) > 1 {
modName = gstr.Trim(match[1])
} else {
mlog.Fatal("module name does not found in go.mod")
}
}

// It uses user passed database configuration.
if in.Link != "" {
Expand Down Expand Up @@ -287,23 +269,20 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
DB: db,
TableNames: tableNames,
NewTableNames: newTableNames,
ModName: modName,
})
// Do.
generateDo(ctx, CGenDaoInternalInput{
CGenDaoInput: in,
DB: db,
TableNames: tableNames,
NewTableNames: newTableNames,
ModName: modName,
})
// Entity.
generateEntity(ctx, CGenDaoInternalInput{
CGenDaoInput: in,
DB: db,
TableNames: tableNames,
NewTableNames: newTableNames,
ModName: modName,
})
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/gf/internal/cmd/gendao/gendao_dao.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func generateDaoSingle(ctx context.Context, in generateDaoSingleInput) {
importPrefix = in.ImportPrefix
)
if importPrefix == "" {
importPrefix = utils.GetImportPath(in.DaoPath)
importPrefix = utils.GetImportPath(gfile.Join(in.Path, in.DaoPath))
} else {
importPrefix = gstr.Join(g.SliceStr{importPrefix, in.DaoPath}, "/")
}
Expand Down
Loading

0 comments on commit c5c2938

Please sign in to comment.