Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
Rabbbit committed Jan 5, 2021
1 parent bca97b6 commit f5c2669
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 66 deletions.
82 changes: 81 additions & 1 deletion cli/actions/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"github.com/fatih/color"
"github.com/gozelus/zelus_rest/cli/codegen"
"github.com/iancoleman/strcase"
"github.com/urfave/cli"
"io"
"os"
Expand Down Expand Up @@ -54,8 +55,87 @@ func GenApis(ctx *cli.Context) error {
return err
}

if err := codegen.NewControllerGenner(apiFileMergeCopy, dir, "api").GenCode(); err != nil {
// 先解析 apiFile 以此生成 controllers
controllerGen := codegen.NewControllerGenner()
groupControllers, err := controllerGen.ParseApiFile(apiFileMergeCopy, "api")
if err != nil {
return err
}
// 生成 service 代码,用于服务于 controllers
for groupName, controllersMap := range groupControllers {
path := filepath.Join(dir, "services", groupName)
// 因为 service 层可能会有些业务代码,所以这个地方不再强制生成
if _, err := mkdirIfNotExist(path); err != nil {
return err
}
// 遍历 controller 准备生成对应的 service 文件
for _, c := range controllersMap {
filename := filepath.Join(path, strcase.ToSnake(c.Name+"_service.go"))
createFile, err := createIfNotExist(filename)
if err != nil {
return err
}
if createFile == nil {
fmt.Println(color.HiRedString("%s exist, will ignore ...", filename))
continue
}

fmt.Println(color.HiGreenString("%s created", filename))
// 交给 genner
if err := codegen.NewServiceGener(c).GenCode(createFile); err != nil {
return err
}
if err := logFinishAndFmt(createFile.Name()); err != nil {
return err
}
}
}

// 生成 controllers 的代码,用于服务 routes
for groupName, controllersMap := range groupControllers {
// 查看是否存在 dir/controllers/$groupName 这个文件夹
// 如果存在,则强制删除,然后创建新的文件夹
path := filepath.Join(dir, "controllers", groupName)
if err := forceCreateDir(path); err != nil {
return err
}

// 遍历 controller 准备生成对应的 controller 文件
for _, c := range controllersMap {
filename := filepath.Join(path, strcase.ToSnake(c.Name+"_controller.go"))
w, err := os.Create(filename)
if err != nil {
return err
}
fmt.Println(color.HiGreenString("%s created", filename))
// 交给 genner
if err := controllerGen.GenCode(w, c); err != nil {
return err
}
if err := logFinishAndFmt(w.Name()); err != nil {
return err
}
}
}
return nil
}

func forceCreateDir(path string) error {
_, err := os.Stat(path)
if err == nil {
fmt.Println(color.HiRedString("%s exist, will remove and recreate", path))
if err := os.RemoveAll(path); err != nil {
return err
}
if err := os.MkdirAll(path, os.ModePerm); err != nil {
return err
}
}
if os.IsNotExist(err) {
fmt.Println(color.HiGreenString("%s not exist, will recreate", path))
if err := os.MkdirAll(path, os.ModePerm); err != nil {
return err
}
}
return nil
}
5 changes: 4 additions & 1 deletion cli/actions/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ import (
"fmt"
"github.com/fatih/color"
"os/exec"
"time"
)

func logFinishAndFmt(dirPath string) error {
now := time.Now()
fmt.Println(color.HiGreenString("the file : %s will be fmt ...", dirPath))
if err := exec.Command("goimports", "-w", dirPath).Run(); err != nil {
return err
}
fmt.Println(color.HiGreenString("the file : %s done \n", dirPath))
fmt.Println(color.HiGreenString("the file : %s fmt done ---> %dms", dirPath, time.Now().Sub(now).Milliseconds()))
return nil
}
14 changes: 13 additions & 1 deletion cli/actions/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,25 @@ import (
"path/filepath"
)

func createIfNotExist(path string) (*os.File, error) {
var file *os.File
var err error
if _, err = os.Stat(path); os.IsNotExist(err) {
if file, err = os.Create(path); err != nil {
return nil, err
}
return file, nil
}
return nil, nil
}

func mkdirIfNotExist(dir string) (string, error) {
dirAbs, err := filepath.Abs(dir)
if err != nil {
return "", err
}
if _, err := os.Stat(dirAbs); os.IsNotExist(err) {
if err := os.Mkdir(dirAbs, os.ModePerm); err != nil {
if err := os.MkdirAll(dirAbs, os.ModePerm); err != nil {
return "", err
}
}
Expand Down
99 changes: 42 additions & 57 deletions cli/codegen/controller_gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ import (
"github.com/iancoleman/strcase"
"html/template"
"io"
"os"
"path/filepath"
"strings"
)

type controller struct {
Name string
Handlers []*handler
PkgName string
Name string
Handlers []*handler
PkgName string
// 依赖的类型包名
TypesPkgName string
// 依赖的服务包名
ServicesPkgName string
}
type handler struct {
Method string
Expand All @@ -29,70 +30,52 @@ type handler struct {
Comments []string
}
type ControllerGenner struct {
readerFiler io.Reader
reader io.Reader
writer io.Writer
genPath string
typesPkgName string

// reader api 文件的读取入口抽象
reader io.Reader
// 依赖的类型包名
TypesPkgName string
// 依赖的服务包名
ServicesPkgName string

// key1 一级path -> 文件夹名
// key2 二级path -> 文件名
// 如 /v1/user/create -> { "v1" : { "user" : $controller } }
// controller 下的函数名,将会被 @handler 后的字符串映射
Group map[string]map[string]*controller
}

func NewControllerGenner(file io.Reader, genPath, typesPkgName string) *ControllerGenner {
return &ControllerGenner{typesPkgName: typesPkgName, genPath: genPath, reader: file, Group: map[string]map[string]*controller{}}
func NewControllerGenner() *ControllerGenner {
return &ControllerGenner{Group: map[string]map[string]*controller{}}
}

func (c *ControllerGenner) GenCode() error {
if err := c.initHandlers(); err != nil {
return err
}
if err := c.initDir(); err != nil {
// 将 controller 结构体转为代码写入文件
func (c ControllerGenner) GenCode(w io.Writer, controller *controller) error {
if err := c.execTemplate(w, controller); err != nil {
return err
}
return nil
}

func (c *ControllerGenner) initDir() error {
for group, controllerMap := range c.Group {
path := filepath.Join(c.genPath, group)
_, err := os.Stat(path)
if err == nil {
fmt.Println(color.GreenString("%s exist, will remove and recreate", path))
if err := os.RemoveAll(path); err != nil {
return err
}
if err := os.MkdirAll(path, os.ModePerm); err != nil {
return err
}
}
if os.IsNotExist(err) {
fmt.Println(color.GreenString("%s not exist, will recreate", path))
if err := os.MkdirAll(path, os.ModePerm); err != nil {
return err
}
}
for _, controller := range controllerMap {
filename := filepath.Join(path, strcase.ToSnake(controller.Name+"_controller.go"))
w, err := os.Create(filename)
if err != nil {
return err
}
fmt.Println(color.GreenString("%s created", filename))
if err := c.execTemplate(w, controller, group); err != nil {
return err
}
}
// 通过 api 文件生成 controller 定义的结构体
func (c *ControllerGenner) ParseApiFile(file io.Reader, typesPkgName string) (map[string]map[string]*controller, error) {
c.reader = file
c.TypesPkgName = typesPkgName
if err := c.initHandlers(); err != nil {
return nil, err
}
return nil
return c.Group, nil
}
func (c *ControllerGenner) execTemplate(w io.Writer, controller *controller, groupName string) error {

func (c *ControllerGenner) execTemplate(w io.Writer, controller *controller) error {
var t *template.Template
var err error
if t, err = template.New("controller new").Parse(tpls.ControllerTpl); err != nil {
return err
}
return t.Execute(w, controller)
}

func (c *ControllerGenner) initHandlers() error {
reader := bufio.NewReader(c.reader)
var lineNum int
Expand Down Expand Up @@ -178,19 +161,21 @@ func (c *ControllerGenner) handleHandlerLine(lines []string) error {
excontroller.Handlers = append(excontroller.Handlers, h)
} else {
c.Group[group][controllerName] = &controller{
Name: strcase.ToCamel(controllerName),
Handlers: []*handler{h},
PkgName: group,
TypesPkgName: c.typesPkgName,
Name: strcase.ToCamel(controllerName),
Handlers: []*handler{h},
PkgName: group + "_controllers",
TypesPkgName: c.TypesPkgName,
ServicesPkgName: group + "_services",
}
}
} else {
c.Group[group] = map[string]*controller{
controllerName: {
Name: strcase.ToCamel(controllerName),
Handlers: []*handler{h},
PkgName: group,
TypesPkgName: c.typesPkgName,
Name: strcase.ToCamel(controllerName),
Handlers: []*handler{h},
PkgName: group + "_controllers",
TypesPkgName: c.TypesPkgName,
ServicesPkgName: group + "_services",
},
}
}
Expand Down
51 changes: 51 additions & 0 deletions cli/codegen/service_gen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package codegen

import (
"github.com/gozelus/zelus_rest/cli/tpls"
"html/template"
"io"
"strings"
)

type serviceInfo struct {
Name string
Handlers []*handler
PkgName string
TypesPkgName string
}

type ServiceGenner struct {
controller *controller
serviceInfo *serviceInfo
}

func NewServiceGener(c *controller) *ServiceGenner {
s := &ServiceGenner{
controller: c,
serviceInfo: initServiceInfo(c),
}
return s
}

// file 要写入的文件
// controller 要服务的 controller
func (s *ServiceGenner) GenCode(file io.Writer) error {
var t *template.Template
var err error
if t, err = template.New("service new").Parse(tpls.ServiceTpl); err != nil {
return err
}
if err := t.Execute(file, s.serviceInfo); err != nil {
return err
}
return nil
}

func initServiceInfo(controller *controller) *serviceInfo {
return &serviceInfo{
Name: controller.Name,
Handlers: controller.Handlers,
PkgName: strings.Split(controller.PkgName, "_")[0] + "_services",
TypesPkgName: controller.TypesPkgName,
}
}
10 changes: 4 additions & 6 deletions cli/tpls/controller.tpl.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
package tpls

var ControllerTpl = `package {{ .PkgName }}
var ControllerTpl = `// Code generated by ZelusCtl. DO NOT EDIT.
package {{ .PkgName }}
import (
"github.com/gozelus/zelus_rest"
)
type {{ .Name }}Service interface { {{ range .Handlers }}
{{ .Name }}(ctx rest.Context, req *{{ $.TypesPkgName }}.{{ .RequestType }}) (*{{ $.TypesPkgName }}.{{ .ResponseType }}, error) {{ end }}
}
type {{ .Name }}Controller struct {
service {{ .Name }}Service
service *{{ $.ServicesPkgName }}.{{ .Name }}Service
}
func New{{ .Name }}Controller(service {{ .Name }}Service) *{{ .Name }}Controller {
func New{{ .Name }}Controller(service *{{ $.ServicesPkgName }}.{{ .Name }}Service) *{{ .Name }}Controller {
return &{{ .Name }}Controller{service : service}
}
Expand Down
15 changes: 15 additions & 0 deletions cli/tpls/service.tpl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package tpls

var ServiceTpl = `package {{ .PkgName }}
type {{ .Name }}Service struct {
// 以后放入要依赖度的对象
}
func New{{ .Name }}Service() *{{ .Name }}Service {
return &{{ .Name }}Service{}
}
{{ range .Handlers }}
func (s *{{ $.Name }}Service) {{ .Name }}(ctx rest.Context, request *{{ $.TypesPkgName }}.{{ .RequestType }}) (*{{ $.TypesPkgName }}.{{ .ResponseType }}, error) {
return nil, errors.New("no imp")
}
{{ end }}
`

0 comments on commit f5c2669

Please sign in to comment.