reactor rpc (#179)
* reactor rpc generation * update flag * update command * update command * update unit test * delete test file * optimize code * update doc * update gen pb * rename target dir * update mysql data type convert rule * add done flag * optimize req/reply parameter * optimize req/reply parameter * remove waste code * remove duplicate parameter * format code * format code * optimize naming * reactor rpcv2 to rpc * remove new line * format code * rename underline to snake * reactor getParentPackage * remove debug log * reactor background
This commit is contained in:
75
tools/goctl/rpc/generator/base/common.pb.go
Normal file
75
tools/goctl/rpc/generator/base/common.pb.go
Normal file
@@ -0,0 +1,75 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: common.proto
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type User struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *User) Reset() { *m = User{} }
|
||||
func (m *User) String() string { return proto.CompactTextString(m) }
|
||||
func (*User) ProtoMessage() {}
|
||||
func (*User) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_555bd8c177793206, []int{0}
|
||||
}
|
||||
|
||||
func (m *User) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_User.Unmarshal(m, b)
|
||||
}
|
||||
func (m *User) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_User.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *User) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_User.Merge(m, src)
|
||||
}
|
||||
func (m *User) XXX_Size() int {
|
||||
return xxx_messageInfo_User.Size(m)
|
||||
}
|
||||
func (m *User) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_User.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_User proto.InternalMessageInfo
|
||||
|
||||
func (m *User) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*User)(nil), "common.User")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("common.proto", fileDescriptor_555bd8c177793206) }
|
||||
|
||||
var fileDescriptor_555bd8c177793206 = []byte{
|
||||
// 72 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x49, 0xce, 0xcf, 0xcd,
|
||||
0xcd, 0xcf, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x83, 0xf0, 0x94, 0xa4, 0xb8, 0x58,
|
||||
0x42, 0x8b, 0x53, 0x8b, 0x84, 0x84, 0xb8, 0x58, 0xf2, 0x12, 0x73, 0x53, 0x25, 0x18, 0x15, 0x18,
|
||||
0x35, 0x38, 0x83, 0xc0, 0xec, 0x24, 0x36, 0xb0, 0x52, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0x2c, 0x6d, 0x58, 0x59, 0x3a, 0x00, 0x00, 0x00,
|
||||
}
|
||||
7
tools/goctl/rpc/generator/base/common.proto
Normal file
7
tools/goctl/rpc/generator/base/common.proto
Normal file
@@ -0,0 +1,7 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package common;
|
||||
|
||||
message User {
|
||||
string name = 1;
|
||||
}
|
||||
33
tools/goctl/rpc/generator/defaultgenerator.go
Normal file
33
tools/goctl/rpc/generator/defaultgenerator.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/console"
|
||||
)
|
||||
|
||||
type defaultGenerator struct {
|
||||
log console.Console
|
||||
}
|
||||
|
||||
func NewDefaultGenerator() *defaultGenerator {
|
||||
log := console.NewColorConsole()
|
||||
return &defaultGenerator{
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *defaultGenerator) Prepare() error {
|
||||
_, err := exec.LookPath("go")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = exec.LookPath("protoc")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = exec.LookPath("protoc-gen-go")
|
||||
return err
|
||||
}
|
||||
11
tools/goctl/rpc/generator/filename.go
Normal file
11
tools/goctl/rpc/generator/filename.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
func formatFilename(filename string) string {
|
||||
return strings.ToLower(stringx.From(filename).ToCamel())
|
||||
}
|
||||
98
tools/goctl/rpc/generator/gen.go
Normal file
98
tools/goctl/rpc/generator/gen.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/console"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/ctx"
|
||||
)
|
||||
|
||||
type RpcGenerator struct {
|
||||
g Generator
|
||||
}
|
||||
|
||||
func NewDefaultRpcGenerator() *RpcGenerator {
|
||||
return NewRpcGenerator(NewDefaultGenerator())
|
||||
}
|
||||
|
||||
func NewRpcGenerator(g Generator) *RpcGenerator {
|
||||
return &RpcGenerator{
|
||||
g: g,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *RpcGenerator) Generate(src, target string, protoImportPath []string) error {
|
||||
abs, err := filepath.Abs(target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = util.MkdirIfNotExist(abs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = g.g.Prepare()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
projectCtx, err := ctx.Prepare(abs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p := parser.NewDefaultProtoParser()
|
||||
proto, err := p.Parse(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dirCtx, err := mkdir(projectCtx, proto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = g.g.GenEtc(dirCtx, proto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = g.g.GenPb(dirCtx, protoImportPath, proto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = g.g.GenConfig(dirCtx, proto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = g.g.GenSvc(dirCtx, proto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = g.g.GenLogic(dirCtx, proto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = g.g.GenServer(dirCtx, proto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = g.g.GenMain(dirCtx, proto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = g.g.GenCall(dirCtx, proto)
|
||||
|
||||
console.NewColorConsole().MarkDone()
|
||||
|
||||
return err
|
||||
}
|
||||
104
tools/goctl/rpc/generator/gen_test.go
Normal file
104
tools/goctl/rpc/generator/gen_test.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/execx"
|
||||
)
|
||||
|
||||
func TestRpcGenerateCaseNilImport(t *testing.T) {
|
||||
dispatcher := NewDefaultGenerator()
|
||||
if err := dispatcher.Prepare(); err == nil {
|
||||
g := NewRpcGenerator(dispatcher)
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = g.Generate("./test_stream.proto", abs, nil)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = execx.Run("go test "+abs, abs)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRpcGenerateCaseOption(t *testing.T) {
|
||||
dispatcher := NewDefaultGenerator()
|
||||
if err := dispatcher.Prepare(); err == nil {
|
||||
g := NewRpcGenerator(dispatcher)
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = g.Generate("./test_option.proto", abs, nil)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = execx.Run("go test "+abs, abs)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRpcGenerateCaseWordOption(t *testing.T) {
|
||||
dispatcher := NewDefaultGenerator()
|
||||
if err := dispatcher.Prepare(); err == nil {
|
||||
g := NewRpcGenerator(dispatcher)
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = g.Generate("./test_word_option.proto", abs, nil)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = execx.Run("go test "+abs, abs)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
// test keyword go
|
||||
func TestRpcGenerateCaseGoOption(t *testing.T) {
|
||||
dispatcher := NewDefaultGenerator()
|
||||
if err := dispatcher.Prepare(); err == nil {
|
||||
g := NewRpcGenerator(dispatcher)
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = g.Generate("./test_go_option.proto", abs, nil)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = execx.Run("go test "+abs, abs)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRpcGenerateCaseImport(t *testing.T) {
|
||||
dispatcher := NewDefaultGenerator()
|
||||
if err := dispatcher.Prepare(); err == nil {
|
||||
g := NewRpcGenerator(dispatcher)
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = g.Generate("./test_import.proto", abs, []string{"./base"})
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
assert.Nil(t, err)
|
||||
|
||||
_, err = execx.Run("go test "+abs, abs)
|
||||
assert.True(t, func() bool {
|
||||
return strings.Contains(err.Error(), "package base is not in GOROOT")
|
||||
}())
|
||||
}
|
||||
}
|
||||
154
tools/goctl/rpc/generator/gencall.go
Normal file
154
tools/goctl/rpc/generator/gencall.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
const (
|
||||
callTemplateText = `{{.head}}
|
||||
|
||||
//go:generate mockgen -destination ./{{.name}}_mock.go -package {{.filePackage}} -source $GOFILE
|
||||
|
||||
package {{.filePackage}}
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
{{.package}}
|
||||
|
||||
"github.com/tal-tech/go-zero/zrpc"
|
||||
)
|
||||
|
||||
type (
|
||||
{{.alias}}
|
||||
|
||||
{{.serviceName}} interface {
|
||||
{{.interface}}
|
||||
}
|
||||
|
||||
default{{.serviceName}} struct {
|
||||
cli zrpc.Client
|
||||
}
|
||||
)
|
||||
|
||||
func New{{.serviceName}}(cli zrpc.Client) {{.serviceName}} {
|
||||
return &default{{.serviceName}}{
|
||||
cli: cli,
|
||||
}
|
||||
}
|
||||
|
||||
{{.functions}}
|
||||
`
|
||||
|
||||
callInterfaceFunctionTemplate = `{{if .hasComment}}{{.comment}}
|
||||
{{end}}{{.method}}(ctx context.Context,in *{{.pbRequest}}) (*{{.pbResponse}},error)`
|
||||
|
||||
callFunctionTemplate = `
|
||||
{{if .hasComment}}{{.comment}}{{end}}
|
||||
func (m *default{{.rpcServiceName}}) {{.method}}(ctx context.Context,in *{{.pbRequest}}) (*{{.pbResponse}}, error) {
|
||||
client := {{.package}}.New{{.rpcServiceName}}Client(m.cli.Conn())
|
||||
return client.{{.method}}(ctx, in)
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
func (g *defaultGenerator) GenCall(ctx DirContext, proto parser.Proto) error {
|
||||
dir := ctx.GetCall()
|
||||
service := proto.Service
|
||||
head := util.GetHead(proto.Name)
|
||||
|
||||
filename := filepath.Join(dir.Filename, fmt.Sprintf("%s.go", formatFilename(service.Name)))
|
||||
functions, err := g.genFunction(proto.PbPackage, service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
iFunctions, err := g.getInterfaceFuncs(service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
text, err := util.LoadTemplate(category, callTemplateFile, callTemplateText)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var alias []string
|
||||
for _, item := range service.RPC {
|
||||
alias = append(alias, fmt.Sprintf("%s = %s", parser.CamelCase(item.RequestType), fmt.Sprintf("%s.%s", proto.PbPackage, parser.CamelCase(item.RequestType))))
|
||||
alias = append(alias, fmt.Sprintf("%s = %s", parser.CamelCase(item.ReturnsType), fmt.Sprintf("%s.%s", proto.PbPackage, parser.CamelCase(item.ReturnsType))))
|
||||
}
|
||||
|
||||
err = util.With("shared").GoFmt(true).Parse(text).SaveTo(map[string]interface{}{
|
||||
"name": formatFilename(service.Name),
|
||||
"alias": strings.Join(alias, util.NL),
|
||||
"head": head,
|
||||
"filePackage": formatFilename(service.Name),
|
||||
"package": fmt.Sprintf(`"%s"`, ctx.GetPb().Package),
|
||||
"serviceName": parser.CamelCase(service.Name),
|
||||
"functions": strings.Join(functions, util.NL),
|
||||
"interface": strings.Join(iFunctions, util.NL),
|
||||
}, filename, true)
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *defaultGenerator) genFunction(goPackage string, service parser.Service) ([]string, error) {
|
||||
functions := make([]string, 0)
|
||||
for _, rpc := range service.RPC {
|
||||
text, err := util.LoadTemplate(category, callFunctionTemplateFile, callFunctionTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
comment := parser.GetComment(rpc.Doc())
|
||||
buffer, err := util.With("sharedFn").Parse(text).Execute(map[string]interface{}{
|
||||
"rpcServiceName": stringx.From(service.Name).Title(),
|
||||
"method": stringx.From(rpc.Name).Title(),
|
||||
"package": goPackage,
|
||||
"pbRequest": parser.CamelCase(rpc.RequestType),
|
||||
"pbResponse": parser.CamelCase(rpc.ReturnsType),
|
||||
"hasComment": len(comment) > 0,
|
||||
"comment": comment,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
functions = append(functions, buffer.String())
|
||||
}
|
||||
return functions, nil
|
||||
}
|
||||
|
||||
func (g *defaultGenerator) getInterfaceFuncs(service parser.Service) ([]string, error) {
|
||||
functions := make([]string, 0)
|
||||
|
||||
for _, rpc := range service.RPC {
|
||||
text, err := util.LoadTemplate(category, callInterfaceFunctionTemplateFile, callInterfaceFunctionTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
comment := parser.GetComment(rpc.Doc())
|
||||
buffer, err := util.With("interfaceFn").Parse(text).Execute(
|
||||
map[string]interface{}{
|
||||
"hasComment": len(comment) > 0,
|
||||
"comment": comment,
|
||||
"method": stringx.From(rpc.Name).Title(),
|
||||
"pbRequest": parser.CamelCase(rpc.RequestType),
|
||||
"pbResponse": parser.CamelCase(rpc.ReturnsType),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
functions = append(functions, buffer.String())
|
||||
}
|
||||
|
||||
return functions, nil
|
||||
}
|
||||
44
tools/goctl/rpc/generator/gencall_test.go
Normal file
44
tools/goctl/rpc/generator/gencall_test.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/ctx"
|
||||
)
|
||||
|
||||
func TestGenerateCall(t *testing.T) {
|
||||
_ = Clean()
|
||||
project := "stream"
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir := filepath.Join(abs, project)
|
||||
err = util.MkdirIfNotExist(dir)
|
||||
assert.Nil(t, err)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
|
||||
projectCtx, err := ctx.Prepare(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
p := parser.NewDefaultProtoParser()
|
||||
proto, err := p.Parse("./test_stream.proto")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dirCtx, err := mkdir(projectCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
g := NewDefaultGenerator()
|
||||
err = g.Prepare()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = g.GenCall(dirCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
34
tools/goctl/rpc/generator/genconfig.go
Normal file
34
tools/goctl/rpc/generator/genconfig.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
)
|
||||
|
||||
const configTemplate = `package config
|
||||
|
||||
import "github.com/tal-tech/go-zero/zrpc"
|
||||
|
||||
type Config struct {
|
||||
zrpc.RpcServerConf
|
||||
}
|
||||
`
|
||||
|
||||
func (g *defaultGenerator) GenConfig(ctx DirContext, _ parser.Proto) error {
|
||||
dir := ctx.GetConfig()
|
||||
fileName := filepath.Join(dir.Filename, formatFilename("config")+".go")
|
||||
if util.FileExists(fileName) {
|
||||
return nil
|
||||
}
|
||||
|
||||
text, err := util.LoadTemplate(category, configTemplateFileFile, configTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(fileName, []byte(text), os.ModePerm)
|
||||
}
|
||||
48
tools/goctl/rpc/generator/genconfig_test.go
Normal file
48
tools/goctl/rpc/generator/genconfig_test.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/ctx"
|
||||
)
|
||||
|
||||
func TestGenerateConfig(t *testing.T) {
|
||||
_ = Clean()
|
||||
project := "stream"
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir := filepath.Join(abs, project)
|
||||
err = util.MkdirIfNotExist(dir)
|
||||
assert.Nil(t, err)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
|
||||
projectCtx, err := ctx.Prepare(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
p := parser.NewDefaultProtoParser()
|
||||
proto, err := p.Parse("./test_stream.proto")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dirCtx, err := mkdir(projectCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
g := NewDefaultGenerator()
|
||||
err = g.Prepare()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = g.GenConfig(dirCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
// test file exists
|
||||
err = g.GenConfig(dirCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
15
tools/goctl/rpc/generator/generator.go
Normal file
15
tools/goctl/rpc/generator/generator.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package generator
|
||||
|
||||
import "github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
|
||||
type Generator interface {
|
||||
Prepare() error
|
||||
GenMain(ctx DirContext, proto parser.Proto) error
|
||||
GenCall(ctx DirContext, proto parser.Proto) error
|
||||
GenEtc(ctx DirContext, proto parser.Proto) error
|
||||
GenConfig(ctx DirContext, proto parser.Proto) error
|
||||
GenLogic(ctx DirContext, proto parser.Proto) error
|
||||
GenServer(ctx DirContext, proto parser.Proto) error
|
||||
GenSvc(ctx DirContext, proto parser.Proto) error
|
||||
GenPb(ctx DirContext, protoImportPath []string, proto parser.Proto) error
|
||||
}
|
||||
32
tools/goctl/rpc/generator/genetc.go
Normal file
32
tools/goctl/rpc/generator/genetc.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
)
|
||||
|
||||
const etcTemplate = `Name: {{.serviceName}}.rpc
|
||||
ListenOn: 127.0.0.1:8080
|
||||
Etcd:
|
||||
Hosts:
|
||||
- 127.0.0.1:2379
|
||||
Key: {{.serviceName}}.rpc
|
||||
`
|
||||
|
||||
func (g *defaultGenerator) GenEtc(ctx DirContext, _ parser.Proto) error {
|
||||
dir := ctx.GetEtc()
|
||||
serviceNameLower := formatFilename(ctx.GetMain().Base)
|
||||
fileName := filepath.Join(dir.Filename, fmt.Sprintf("%v.yaml", serviceNameLower))
|
||||
|
||||
text, err := util.LoadTemplate(category, etcTemplateFileFile, etcTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return util.With("etc").Parse(text).SaveTo(map[string]interface{}{
|
||||
"serviceName": serviceNameLower,
|
||||
}, fileName, false)
|
||||
}
|
||||
45
tools/goctl/rpc/generator/genetc_test.go
Normal file
45
tools/goctl/rpc/generator/genetc_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/ctx"
|
||||
)
|
||||
|
||||
func TestGenerateEtc(t *testing.T) {
|
||||
_ = Clean()
|
||||
project := "stream"
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir := filepath.Join(abs, project)
|
||||
err = util.MkdirIfNotExist(dir)
|
||||
assert.Nil(t, err)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
|
||||
projectCtx, err := ctx.Prepare(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
p := parser.NewDefaultProtoParser()
|
||||
proto, err := p.Parse("./test_stream.proto")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dirCtx, err := mkdir(projectCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
g := NewDefaultGenerator()
|
||||
err = g.Prepare()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = g.GenEtc(dirCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
101
tools/goctl/rpc/generator/genlogic.go
Normal file
101
tools/goctl/rpc/generator/genlogic.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/core/collection"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
const (
|
||||
logicTemplate = `package logic
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
{{.imports}}
|
||||
|
||||
"github.com/tal-tech/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type {{.logicName}} struct {
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
logx.Logger
|
||||
}
|
||||
|
||||
func New{{.logicName}}(ctx context.Context,svcCtx *svc.ServiceContext) *{{.logicName}} {
|
||||
return &{{.logicName}}{
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
Logger: logx.WithContext(ctx),
|
||||
}
|
||||
}
|
||||
{{.functions}}
|
||||
`
|
||||
logicFunctionTemplate = `{{if .hasComment}}{{.comment}}{{end}}
|
||||
func (l *{{.logicName}}) {{.method}} (in {{.request}}) ({{.response}}, error) {
|
||||
// todo: add your logic here and delete this line
|
||||
|
||||
return &{{.responseType}}{}, nil
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
func (g *defaultGenerator) GenLogic(ctx DirContext, proto parser.Proto) error {
|
||||
dir := ctx.GetLogic()
|
||||
for _, rpc := range proto.Service.RPC {
|
||||
filename := filepath.Join(dir.Filename, formatFilename(rpc.Name+"_logic")+".go")
|
||||
functions, err := g.genLogicFunction(proto.PbPackage, rpc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
imports := collection.NewSet()
|
||||
imports.AddStr(fmt.Sprintf(`"%v"`, ctx.GetSvc().Package))
|
||||
imports.AddStr(fmt.Sprintf(`"%v"`, ctx.GetPb().Package))
|
||||
text, err := util.LoadTemplate(category, logicTemplateFileFile, logicTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = util.With("logic").GoFmt(true).Parse(text).SaveTo(map[string]interface{}{
|
||||
"logicName": fmt.Sprintf("%sLogic", stringx.From(rpc.Name).Title()),
|
||||
"functions": functions,
|
||||
"imports": strings.Join(imports.KeysStr(), util.NL),
|
||||
}, filename, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *defaultGenerator) genLogicFunction(goPackage string, rpc *parser.RPC) (string, error) {
|
||||
var functions = make([]string, 0)
|
||||
text, err := util.LoadTemplate(category, logicFuncTemplateFileFile, logicFunctionTemplate)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
logicName := stringx.From(rpc.Name + "_logic").ToCamel()
|
||||
comment := parser.GetComment(rpc.Doc())
|
||||
buffer, err := util.With("fun").Parse(text).Execute(map[string]interface{}{
|
||||
"logicName": logicName,
|
||||
"method": parser.CamelCase(rpc.Name),
|
||||
"request": fmt.Sprintf("*%s.%s", goPackage, parser.CamelCase(rpc.RequestType)),
|
||||
"response": fmt.Sprintf("*%s.%s", goPackage, parser.CamelCase(rpc.ReturnsType)),
|
||||
"responseType": fmt.Sprintf("%s.%s", goPackage, parser.CamelCase(rpc.ReturnsType)),
|
||||
"hasComment": len(comment) > 0,
|
||||
"comment": comment,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
functions = append(functions, buffer.String())
|
||||
return strings.Join(functions, util.NL), nil
|
||||
}
|
||||
44
tools/goctl/rpc/generator/genlogic_test.go
Normal file
44
tools/goctl/rpc/generator/genlogic_test.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/ctx"
|
||||
)
|
||||
|
||||
func TestGenerateLogic(t *testing.T) {
|
||||
project := "stream"
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir := filepath.Join(abs, project)
|
||||
err = util.MkdirIfNotExist(dir)
|
||||
assert.Nil(t, err)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
|
||||
projectCtx, err := ctx.Prepare(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
p := parser.NewDefaultProtoParser()
|
||||
proto, err := p.Parse("./test_stream.proto")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dirCtx, err := mkdir(projectCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
g := NewDefaultGenerator()
|
||||
err = g.Prepare()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = g.GenLogic(dirCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
70
tools/goctl/rpc/generator/genmain.go
Normal file
70
tools/goctl/rpc/generator/genmain.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
)
|
||||
|
||||
const mainTemplate = `{{.head}}
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
{{.imports}}
|
||||
|
||||
"github.com/tal-tech/go-zero/core/conf"
|
||||
"github.com/tal-tech/go-zero/zrpc"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var configFile = flag.String("f", "etc/{{.serviceName}}.yaml", "the config file")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
var c config.Config
|
||||
conf.MustLoad(*configFile, &c)
|
||||
ctx := svc.NewServiceContext(c)
|
||||
srv := server.New{{.service}}Server(ctx)
|
||||
|
||||
s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
|
||||
{{.pkg}}.Register{{.service}}Server(grpcServer, srv)
|
||||
})
|
||||
defer s.Stop()
|
||||
|
||||
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
|
||||
s.Start()
|
||||
}
|
||||
`
|
||||
|
||||
func (g *defaultGenerator) GenMain(ctx DirContext, proto parser.Proto) error {
|
||||
dir := ctx.GetMain()
|
||||
serviceNameLower := formatFilename(ctx.GetMain().Base)
|
||||
fileName := filepath.Join(dir.Filename, fmt.Sprintf("%v.go", serviceNameLower))
|
||||
imports := make([]string, 0)
|
||||
pbImport := fmt.Sprintf(`"%v"`, ctx.GetPb().Package)
|
||||
svcImport := fmt.Sprintf(`"%v"`, ctx.GetSvc().Package)
|
||||
remoteImport := fmt.Sprintf(`"%v"`, ctx.GetServer().Package)
|
||||
configImport := fmt.Sprintf(`"%v"`, ctx.GetConfig().Package)
|
||||
imports = append(imports, configImport, pbImport, remoteImport, svcImport)
|
||||
head := util.GetHead(proto.Name)
|
||||
text, err := util.LoadTemplate(category, mainTemplateFile, mainTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return util.With("main").GoFmt(true).Parse(text).SaveTo(map[string]interface{}{
|
||||
"head": head,
|
||||
"serviceName": serviceNameLower,
|
||||
"imports": strings.Join(imports, util.NL),
|
||||
"pkg": proto.PbPackage,
|
||||
"service": parser.CamelCase(proto.Service.Name),
|
||||
}, fileName, false)
|
||||
}
|
||||
45
tools/goctl/rpc/generator/genmain_test.go
Normal file
45
tools/goctl/rpc/generator/genmain_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/ctx"
|
||||
)
|
||||
|
||||
func TestGenerateMain(t *testing.T) {
|
||||
_ = Clean()
|
||||
project := "stream"
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir := filepath.Join(abs, project)
|
||||
err = util.MkdirIfNotExist(dir)
|
||||
assert.Nil(t, err)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
|
||||
projectCtx, err := ctx.Prepare(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
p := parser.NewDefaultProtoParser()
|
||||
proto, err := p.Parse("./test_stream.proto")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dirCtx, err := mkdir(projectCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
g := NewDefaultGenerator()
|
||||
err = g.Prepare()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = g.GenMain(dirCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
31
tools/goctl/rpc/generator/genpb.go
Normal file
31
tools/goctl/rpc/generator/genpb.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/execx"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
)
|
||||
|
||||
func (g *defaultGenerator) GenPb(ctx DirContext, protoImportPath []string, proto parser.Proto) error {
|
||||
dir := ctx.GetPb()
|
||||
cw := new(bytes.Buffer)
|
||||
base := filepath.Dir(proto.Src)
|
||||
cw.WriteString("protoc ")
|
||||
for _, ip := range protoImportPath {
|
||||
cw.WriteString(" -I=" + ip)
|
||||
}
|
||||
cw.WriteString(" -I=" + base)
|
||||
cw.WriteString(" " + proto.Name)
|
||||
if strings.Contains(proto.GoPackage, "/") {
|
||||
cw.WriteString(" --go_out=plugins=grpc:" + ctx.GetInternal().Filename)
|
||||
} else {
|
||||
cw.WriteString(" --go_out=plugins=grpc:" + dir.Filename)
|
||||
}
|
||||
command := cw.String()
|
||||
g.log.Debug(command)
|
||||
_, err := execx.Run(command, "")
|
||||
return err
|
||||
}
|
||||
184
tools/goctl/rpc/generator/genpb_test.go
Normal file
184
tools/goctl/rpc/generator/genpb_test.go
Normal file
@@ -0,0 +1,184 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/ctx"
|
||||
)
|
||||
|
||||
func TestGenerateCaseNilImport(t *testing.T) {
|
||||
project := "stream"
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir := filepath.Join(abs, project)
|
||||
err = util.MkdirIfNotExist(dir)
|
||||
assert.Nil(t, err)
|
||||
defer func() {
|
||||
//_ = os.RemoveAll(abs)
|
||||
}()
|
||||
|
||||
projectCtx, err := ctx.Prepare(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
p := parser.NewDefaultProtoParser()
|
||||
proto, err := p.Parse("./test_stream.proto")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dirCtx, err := mkdir(projectCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
g := NewDefaultGenerator()
|
||||
if err := g.Prepare(); err == nil {
|
||||
targetPb := filepath.Join(dirCtx.GetPb().Filename, "test_stream.pb.go")
|
||||
err = g.GenPb(dirCtx, nil, proto)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, func() bool {
|
||||
return util.FileExists(targetPb)
|
||||
}())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateCaseImport(t *testing.T) {
|
||||
project := "stream"
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir := filepath.Join(abs, project)
|
||||
err = util.MkdirIfNotExist(dir)
|
||||
assert.Nil(t, err)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
|
||||
projectCtx, err := ctx.Prepare(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
p := parser.NewDefaultProtoParser()
|
||||
proto, err := p.Parse("./test_stream.proto")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dirCtx, err := mkdir(projectCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
g := NewDefaultGenerator()
|
||||
if err := g.Prepare(); err == nil {
|
||||
err = g.GenPb(dirCtx, nil, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
targetPb := filepath.Join(dirCtx.GetPb().Filename, "test_stream.pb.go")
|
||||
assert.True(t, func() bool {
|
||||
return util.FileExists(targetPb)
|
||||
}())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateCasePathOption(t *testing.T) {
|
||||
project := "stream"
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir := filepath.Join(abs, project)
|
||||
err = util.MkdirIfNotExist(dir)
|
||||
assert.Nil(t, err)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
|
||||
projectCtx, err := ctx.Prepare(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
p := parser.NewDefaultProtoParser()
|
||||
proto, err := p.Parse("./test_option.proto")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dirCtx, err := mkdir(projectCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
g := NewDefaultGenerator()
|
||||
if err := g.Prepare(); err == nil {
|
||||
err = g.GenPb(dirCtx, nil, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
targetPb := filepath.Join(dirCtx.GetPb().Filename, "test_option.pb.go")
|
||||
assert.True(t, func() bool {
|
||||
return util.FileExists(targetPb)
|
||||
}())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateCaseWordOption(t *testing.T) {
|
||||
project := "stream"
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir := filepath.Join(abs, project)
|
||||
err = util.MkdirIfNotExist(dir)
|
||||
assert.Nil(t, err)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
|
||||
projectCtx, err := ctx.Prepare(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
p := parser.NewDefaultProtoParser()
|
||||
proto, err := p.Parse("./test_word_option.proto")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dirCtx, err := mkdir(projectCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
g := NewDefaultGenerator()
|
||||
if err := g.Prepare(); err == nil {
|
||||
|
||||
err = g.GenPb(dirCtx, nil, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
targetPb := filepath.Join(dirCtx.GetPb().Filename, "test_word_option.pb.go")
|
||||
assert.True(t, func() bool {
|
||||
return util.FileExists(targetPb)
|
||||
}())
|
||||
}
|
||||
}
|
||||
|
||||
// test keyword go
|
||||
func TestGenerateCaseGoOption(t *testing.T) {
|
||||
project := "stream"
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir := filepath.Join(abs, project)
|
||||
err = util.MkdirIfNotExist(dir)
|
||||
assert.Nil(t, err)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
|
||||
projectCtx, err := ctx.Prepare(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
p := parser.NewDefaultProtoParser()
|
||||
proto, err := p.Parse("./test_go_option.proto")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dirCtx, err := mkdir(projectCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
g := NewDefaultGenerator()
|
||||
if err := g.Prepare(); err == nil {
|
||||
|
||||
err = g.GenPb(dirCtx, nil, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
targetPb := filepath.Join(dirCtx.GetPb().Filename, "test_go_option.pb.go")
|
||||
assert.True(t, func() bool {
|
||||
return util.FileExists(targetPb)
|
||||
}())
|
||||
}
|
||||
}
|
||||
102
tools/goctl/rpc/generator/genserver.go
Normal file
102
tools/goctl/rpc/generator/genserver.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/core/collection"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
const (
|
||||
serverTemplate = `{{.head}}
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
{{.imports}}
|
||||
)
|
||||
|
||||
type {{.server}}Server struct {
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func New{{.server}}Server(svcCtx *svc.ServiceContext) *{{.server}}Server {
|
||||
return &{{.server}}Server{
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
{{.funcs}}
|
||||
`
|
||||
functionTemplate = `
|
||||
{{if .hasComment}}{{.comment}}{{end}}
|
||||
func (s *{{.server}}Server) {{.method}} (ctx context.Context, in {{.request}}) ({{.response}}, error) {
|
||||
l := logic.New{{.logicName}}(ctx,s.svcCtx)
|
||||
return l.{{.method}}(in)
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
func (g *defaultGenerator) GenServer(ctx DirContext, proto parser.Proto) error {
|
||||
dir := ctx.GetServer()
|
||||
logicImport := fmt.Sprintf(`"%v"`, ctx.GetLogic().Package)
|
||||
svcImport := fmt.Sprintf(`"%v"`, ctx.GetSvc().Package)
|
||||
pbImport := fmt.Sprintf(`"%v"`, ctx.GetPb().Package)
|
||||
|
||||
imports := collection.NewSet()
|
||||
imports.AddStr(logicImport, svcImport, pbImport)
|
||||
|
||||
head := util.GetHead(proto.Name)
|
||||
service := proto.Service
|
||||
serverFile := filepath.Join(dir.Filename, formatFilename(service.Name+"_server")+".go")
|
||||
funcList, err := g.genFunctions(proto.PbPackage, service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
text, err := util.LoadTemplate(category, serverTemplateFile, serverTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = util.With("server").GoFmt(true).Parse(text).SaveTo(map[string]interface{}{
|
||||
"head": head,
|
||||
"server": stringx.From(service.Name).Title(),
|
||||
"imports": strings.Join(imports.KeysStr(), util.NL),
|
||||
"funcs": strings.Join(funcList, util.NL),
|
||||
}, serverFile, true)
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *defaultGenerator) genFunctions(goPackage string, service parser.Service) ([]string, error) {
|
||||
var functionList []string
|
||||
for _, rpc := range service.RPC {
|
||||
text, err := util.LoadTemplate(category, serverFuncTemplateFile, functionTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
comment := parser.GetComment(rpc.Doc())
|
||||
buffer, err := util.With("func").Parse(text).Execute(map[string]interface{}{
|
||||
"server": stringx.From(service.Name).Title(),
|
||||
"logicName": fmt.Sprintf("%sLogic", stringx.From(rpc.Name).Title()),
|
||||
"method": parser.CamelCase(rpc.Name),
|
||||
"request": fmt.Sprintf("*%s.%s", goPackage, parser.CamelCase(rpc.RequestType)),
|
||||
"response": fmt.Sprintf("*%s.%s", goPackage, parser.CamelCase(rpc.ReturnsType)),
|
||||
"hasComment": len(comment) > 0,
|
||||
"comment": comment,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
functionList = append(functionList, buffer.String())
|
||||
}
|
||||
return functionList, nil
|
||||
}
|
||||
45
tools/goctl/rpc/generator/genserver_test.go
Normal file
45
tools/goctl/rpc/generator/genserver_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/ctx"
|
||||
)
|
||||
|
||||
func TestGenerateServer(t *testing.T) {
|
||||
_ = Clean()
|
||||
project := "stream"
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir := filepath.Join(abs, project)
|
||||
err = util.MkdirIfNotExist(dir)
|
||||
assert.Nil(t, err)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
|
||||
projectCtx, err := ctx.Prepare(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
p := parser.NewDefaultProtoParser()
|
||||
proto, err := p.Parse("./test_stream.proto")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dirCtx, err := mkdir(projectCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
g := NewDefaultGenerator()
|
||||
err = g.Prepare()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = g.GenServer(dirCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
37
tools/goctl/rpc/generator/gensvc.go
Normal file
37
tools/goctl/rpc/generator/gensvc.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
)
|
||||
|
||||
const svcTemplate = `package svc
|
||||
|
||||
import {{.imports}}
|
||||
|
||||
type ServiceContext struct {
|
||||
c config.Config
|
||||
}
|
||||
|
||||
func NewServiceContext(c config.Config) *ServiceContext {
|
||||
return &ServiceContext{
|
||||
c:c,
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
func (g *defaultGenerator) GenSvc(ctx DirContext, _ parser.Proto) error {
|
||||
dir := ctx.GetSvc()
|
||||
fileName := filepath.Join(dir.Filename, formatFilename("service_context")+".go")
|
||||
text, err := util.LoadTemplate(category, svcTemplateFile, svcTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return util.With("svc").GoFmt(true).Parse(text).SaveTo(map[string]interface{}{
|
||||
"imports": fmt.Sprintf(`"%v"`, ctx.GetConfig().Package),
|
||||
}, fileName, false)
|
||||
}
|
||||
40
tools/goctl/rpc/generator/gensvc_test.go
Normal file
40
tools/goctl/rpc/generator/gensvc_test.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/ctx"
|
||||
)
|
||||
|
||||
func TestGenerateSvc(t *testing.T) {
|
||||
_ = Clean()
|
||||
project := "stream"
|
||||
abs, err := filepath.Abs("./test")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir := filepath.Join(abs, project)
|
||||
err = util.MkdirIfNotExist(dir)
|
||||
assert.Nil(t, err)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(abs)
|
||||
}()
|
||||
|
||||
projectCtx, err := ctx.Prepare(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
p := parser.NewDefaultProtoParser()
|
||||
proto, err := p.Parse("./test_stream.proto")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dirCtx, err := mkdir(projectCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
|
||||
g := NewDefaultGenerator()
|
||||
err = g.GenSvc(dirCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
152
tools/goctl/rpc/generator/mkdir.go
Normal file
152
tools/goctl/rpc/generator/mkdir.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/ctx"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
const (
|
||||
wd = "wd"
|
||||
etc = "etc"
|
||||
internal = "internal"
|
||||
config = "config"
|
||||
logic = "logic"
|
||||
server = "server"
|
||||
svc = "svc"
|
||||
pb = "pb"
|
||||
call = "call"
|
||||
)
|
||||
|
||||
type (
|
||||
DirContext interface {
|
||||
GetCall() Dir
|
||||
GetEtc() Dir
|
||||
GetInternal() Dir
|
||||
GetConfig() Dir
|
||||
GetLogic() Dir
|
||||
GetServer() Dir
|
||||
GetSvc() Dir
|
||||
GetPb() Dir
|
||||
GetMain() Dir
|
||||
}
|
||||
|
||||
Dir struct {
|
||||
Base string
|
||||
Filename string
|
||||
Package string
|
||||
}
|
||||
defaultDirContext struct {
|
||||
inner map[string]Dir
|
||||
}
|
||||
)
|
||||
|
||||
func mkdir(ctx *ctx.ProjectContext, proto parser.Proto) (DirContext, error) {
|
||||
inner := make(map[string]Dir)
|
||||
etcDir := filepath.Join(ctx.WorkDir, "etc")
|
||||
internalDir := filepath.Join(ctx.WorkDir, "internal")
|
||||
configDir := filepath.Join(internalDir, "config")
|
||||
logicDir := filepath.Join(internalDir, "logic")
|
||||
serverDir := filepath.Join(internalDir, "server")
|
||||
svcDir := filepath.Join(internalDir, "svc")
|
||||
pbDir := filepath.Join(internalDir, proto.GoPackage)
|
||||
callDir := filepath.Join(ctx.WorkDir, strings.ToLower(stringx.From(proto.Service.Name).ToCamel()))
|
||||
inner[wd] = Dir{
|
||||
Filename: ctx.WorkDir,
|
||||
Package: filepath.ToSlash(filepath.Join(ctx.Path, strings.TrimPrefix(ctx.WorkDir, ctx.Dir))),
|
||||
Base: filepath.Base(ctx.WorkDir),
|
||||
}
|
||||
inner[etc] = Dir{
|
||||
Filename: etcDir,
|
||||
Package: filepath.ToSlash(filepath.Join(ctx.Path, strings.TrimPrefix(etcDir, ctx.Dir))),
|
||||
Base: filepath.Base(etcDir),
|
||||
}
|
||||
inner[internal] = Dir{
|
||||
Filename: internalDir,
|
||||
Package: filepath.ToSlash(filepath.Join(ctx.Path, strings.TrimPrefix(internalDir, ctx.Dir))),
|
||||
Base: filepath.Base(internalDir),
|
||||
}
|
||||
inner[config] = Dir{
|
||||
Filename: configDir,
|
||||
Package: filepath.ToSlash(filepath.Join(ctx.Path, strings.TrimPrefix(configDir, ctx.Dir))),
|
||||
Base: filepath.Base(configDir),
|
||||
}
|
||||
inner[logic] = Dir{
|
||||
Filename: logicDir,
|
||||
Package: filepath.ToSlash(filepath.Join(ctx.Path, strings.TrimPrefix(logicDir, ctx.Dir))),
|
||||
Base: filepath.Base(logicDir),
|
||||
}
|
||||
inner[server] = Dir{
|
||||
Filename: serverDir,
|
||||
Package: filepath.ToSlash(filepath.Join(ctx.Path, strings.TrimPrefix(serverDir, ctx.Dir))),
|
||||
Base: filepath.Base(serverDir),
|
||||
}
|
||||
inner[svc] = Dir{
|
||||
Filename: svcDir,
|
||||
Package: filepath.ToSlash(filepath.Join(ctx.Path, strings.TrimPrefix(svcDir, ctx.Dir))),
|
||||
Base: filepath.Base(svcDir),
|
||||
}
|
||||
inner[pb] = Dir{
|
||||
Filename: pbDir,
|
||||
Package: filepath.ToSlash(filepath.Join(ctx.Path, strings.TrimPrefix(pbDir, ctx.Dir))),
|
||||
Base: filepath.Base(pbDir),
|
||||
}
|
||||
inner[call] = Dir{
|
||||
Filename: callDir,
|
||||
Package: filepath.ToSlash(filepath.Join(ctx.Path, strings.TrimPrefix(callDir, ctx.Dir))),
|
||||
Base: filepath.Base(callDir),
|
||||
}
|
||||
for _, v := range inner {
|
||||
err := util.MkdirIfNotExist(v.Filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &defaultDirContext{
|
||||
inner: inner,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *defaultDirContext) GetCall() Dir {
|
||||
return d.inner[call]
|
||||
}
|
||||
|
||||
func (d *defaultDirContext) GetEtc() Dir {
|
||||
return d.inner[etc]
|
||||
}
|
||||
|
||||
func (d *defaultDirContext) GetInternal() Dir {
|
||||
return d.inner[internal]
|
||||
}
|
||||
|
||||
func (d *defaultDirContext) GetConfig() Dir {
|
||||
return d.inner[config]
|
||||
}
|
||||
|
||||
func (d *defaultDirContext) GetLogic() Dir {
|
||||
return d.inner[logic]
|
||||
}
|
||||
|
||||
func (d *defaultDirContext) GetServer() Dir {
|
||||
return d.inner[server]
|
||||
}
|
||||
|
||||
func (d *defaultDirContext) GetSvc() Dir {
|
||||
return d.inner[svc]
|
||||
}
|
||||
|
||||
func (d *defaultDirContext) GetPb() Dir {
|
||||
return d.inner[pb]
|
||||
}
|
||||
|
||||
func (d *defaultDirContext) GetMain() Dir {
|
||||
return d.inner[wd]
|
||||
}
|
||||
|
||||
func (d *Dir) Valid() bool {
|
||||
return len(d.Filename) > 0 && len(d.Package) > 0
|
||||
}
|
||||
130
tools/goctl/rpc/generator/mkdir_test.go
Normal file
130
tools/goctl/rpc/generator/mkdir_test.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"go/build"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/core/stringx"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/execx"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/ctx"
|
||||
)
|
||||
|
||||
func TestMkDirInGoPath(t *testing.T) {
|
||||
dft := build.Default
|
||||
gp := dft.GOPATH
|
||||
if len(gp) == 0 {
|
||||
return
|
||||
}
|
||||
projectName := stringx.Rand()
|
||||
dir := filepath.Join(gp, "src", projectName)
|
||||
err := util.MkdirIfNotExist(dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = os.RemoveAll(dir)
|
||||
}()
|
||||
|
||||
projectCtx, err := ctx.Prepare(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
p := parser.NewDefaultProtoParser()
|
||||
proto, err := p.Parse("./test.proto")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dirCtx, err := mkdir(projectCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
internal := filepath.Join(dir, "internal")
|
||||
assert.True(t, true, func() bool {
|
||||
return filepath.Join(dir, strings.ToLower(projectName)) == dirCtx.GetCall().Filename && projectName == dirCtx.GetCall().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return filepath.Join(dir, "etc") == dirCtx.GetEtc().Filename && filepath.Join(projectName, "etc") == dirCtx.GetEtc().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return internal == dirCtx.GetInternal().Filename && filepath.Join(projectName, "internal") == dirCtx.GetInternal().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return filepath.Join(internal, "config") == dirCtx.GetConfig().Filename && filepath.Join(projectName, "internal", "config") == dirCtx.GetConfig().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return filepath.Join(internal, "logic") == dirCtx.GetLogic().Filename && filepath.Join(projectName, "internal", "logic") == dirCtx.GetLogic().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return filepath.Join(internal, "server") == dirCtx.GetServer().Filename && filepath.Join(projectName, "internal", "server") == dirCtx.GetServer().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return filepath.Join(internal, "svc") == dirCtx.GetSvc().Filename && filepath.Join(projectName, "internal", "svc") == dirCtx.GetSvc().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return filepath.Join(internal, strings.ToLower(proto.Service.Name)) == dirCtx.GetPb().Filename && filepath.Join(projectName, "internal", strings.ToLower(proto.Service.Name)) == dirCtx.GetPb().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return dir == dirCtx.GetMain().Filename && projectName == dirCtx.GetMain().Package
|
||||
}())
|
||||
}
|
||||
|
||||
func TestMkDirInGoMod(t *testing.T) {
|
||||
dft := build.Default
|
||||
gp := dft.GOPATH
|
||||
if len(gp) == 0 {
|
||||
return
|
||||
}
|
||||
projectName := stringx.Rand()
|
||||
dir := filepath.Join(gp, "src", projectName)
|
||||
err := util.MkdirIfNotExist(dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = execx.Run("go mod init "+projectName, dir)
|
||||
assert.Nil(t, err)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(dir)
|
||||
}()
|
||||
|
||||
projectCtx, err := ctx.Prepare(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
p := parser.NewDefaultProtoParser()
|
||||
proto, err := p.Parse("./test.proto")
|
||||
assert.Nil(t, err)
|
||||
|
||||
dirCtx, err := mkdir(projectCtx, proto)
|
||||
assert.Nil(t, err)
|
||||
internal := filepath.Join(dir, "internal")
|
||||
assert.True(t, true, func() bool {
|
||||
return filepath.Join(dir, strings.ToLower(projectName)) == dirCtx.GetCall().Filename && projectName == dirCtx.GetCall().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return filepath.Join(dir, "etc") == dirCtx.GetEtc().Filename && filepath.Join(projectName, "etc") == dirCtx.GetEtc().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return internal == dirCtx.GetInternal().Filename && filepath.Join(projectName, "internal") == dirCtx.GetInternal().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return filepath.Join(internal, "config") == dirCtx.GetConfig().Filename && filepath.Join(projectName, "internal", "config") == dirCtx.GetConfig().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return filepath.Join(internal, "logic") == dirCtx.GetLogic().Filename && filepath.Join(projectName, "internal", "logic") == dirCtx.GetLogic().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return filepath.Join(internal, "server") == dirCtx.GetServer().Filename && filepath.Join(projectName, "internal", "server") == dirCtx.GetServer().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return filepath.Join(internal, "svc") == dirCtx.GetSvc().Filename && filepath.Join(projectName, "internal", "svc") == dirCtx.GetSvc().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return filepath.Join(internal, strings.ToLower(proto.Service.Name)) == dirCtx.GetPb().Filename && filepath.Join(projectName, "internal", strings.ToLower(proto.Service.Name)) == dirCtx.GetPb().Package
|
||||
}())
|
||||
assert.True(t, true, func() bool {
|
||||
return dir == dirCtx.GetMain().Filename && projectName == dirCtx.GetMain().Package
|
||||
}())
|
||||
}
|
||||
47
tools/goctl/rpc/generator/prototmpl.go
Normal file
47
tools/goctl/rpc/generator/prototmpl.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util/stringx"
|
||||
)
|
||||
|
||||
const rpcTemplateText = `syntax = "proto3";
|
||||
|
||||
package {{.package}};
|
||||
|
||||
message Request {
|
||||
string ping = 1;
|
||||
}
|
||||
|
||||
message Response {
|
||||
string pong = 1;
|
||||
}
|
||||
|
||||
service {{.serviceName}} {
|
||||
rpc Ping(Request) returns(Response);
|
||||
}
|
||||
`
|
||||
|
||||
func ProtoTmpl(out string) error {
|
||||
protoFilename := filepath.Base(out)
|
||||
serviceName := stringx.From(strings.TrimSuffix(protoFilename, filepath.Ext(protoFilename)))
|
||||
text, err := util.LoadTemplate(category, rpcTemplateFile, rpcTemplateText)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dir := filepath.Dir(out)
|
||||
err = util.MkdirIfNotExist(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = util.With("t").Parse(text).SaveTo(map[string]string{
|
||||
"package": serviceName.UnTitle(),
|
||||
"serviceName": serviceName.Title(),
|
||||
}, out, false)
|
||||
return err
|
||||
}
|
||||
21
tools/goctl/rpc/generator/prototmpl_test.go
Normal file
21
tools/goctl/rpc/generator/prototmpl_test.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestProtoTmpl(t *testing.T) {
|
||||
out, err := filepath.Abs("./test/test.proto")
|
||||
assert.Nil(t, err)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(filepath.Dir(out))
|
||||
}()
|
||||
err = ProtoTmpl(out)
|
||||
assert.Nil(t, err)
|
||||
_, err = os.Stat(out)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
67
tools/goctl/rpc/generator/template.go
Normal file
67
tools/goctl/rpc/generator/template.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
const (
|
||||
category = "rpc"
|
||||
callTemplateFile = "call.tpl"
|
||||
callInterfaceFunctionTemplateFile = "call-interface-func.tpl"
|
||||
callFunctionTemplateFile = "call-func.tpl"
|
||||
configTemplateFileFile = "config.tpl"
|
||||
etcTemplateFileFile = "etc.tpl"
|
||||
logicTemplateFileFile = "logic.tpl"
|
||||
logicFuncTemplateFileFile = "logic-func.tpl"
|
||||
mainTemplateFile = "main.tpl"
|
||||
serverTemplateFile = "server.tpl"
|
||||
serverFuncTemplateFile = "server-func.tpl"
|
||||
svcTemplateFile = "svc.tpl"
|
||||
rpcTemplateFile = "template.tpl"
|
||||
)
|
||||
|
||||
var templates = map[string]string{
|
||||
callTemplateFile: callTemplateText,
|
||||
callInterfaceFunctionTemplateFile: callInterfaceFunctionTemplate,
|
||||
callFunctionTemplateFile: callFunctionTemplate,
|
||||
configTemplateFileFile: configTemplate,
|
||||
etcTemplateFileFile: etcTemplate,
|
||||
logicTemplateFileFile: logicTemplate,
|
||||
logicFuncTemplateFileFile: logicFunctionTemplate,
|
||||
mainTemplateFile: mainTemplate,
|
||||
serverTemplateFile: serverTemplate,
|
||||
serverFuncTemplateFile: functionTemplate,
|
||||
svcTemplateFile: svcTemplate,
|
||||
rpcTemplateFile: rpcTemplateText,
|
||||
}
|
||||
|
||||
func GenTemplates(_ *cli.Context) error {
|
||||
return util.InitTemplates(category, templates)
|
||||
}
|
||||
|
||||
func RevertTemplate(name string) error {
|
||||
content, ok := templates[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("%s: no such file name", name)
|
||||
}
|
||||
return util.CreateTemplate(category, name, content)
|
||||
}
|
||||
|
||||
func Clean() error {
|
||||
return util.Clean(category)
|
||||
}
|
||||
|
||||
func Update(category string) error {
|
||||
err := Clean()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return util.InitTemplates(category, templates)
|
||||
}
|
||||
|
||||
func GetCategory() string {
|
||||
return category
|
||||
}
|
||||
96
tools/goctl/rpc/generator/template_test.go
Normal file
96
tools/goctl/rpc/generator/template_test.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/tools/goctl/util"
|
||||
)
|
||||
|
||||
func TestGenTemplates(t *testing.T) {
|
||||
err := util.InitTemplates(category, templates)
|
||||
assert.Nil(t, err)
|
||||
dir, err := util.GetTemplateDir(category)
|
||||
assert.Nil(t, err)
|
||||
file := filepath.Join(dir, "main.tpl")
|
||||
data, err := ioutil.ReadFile(file)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, string(data), mainTemplate)
|
||||
}
|
||||
|
||||
func TestRevertTemplate(t *testing.T) {
|
||||
name := "main.tpl"
|
||||
err := util.InitTemplates(category, templates)
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir, err := util.GetTemplateDir(category)
|
||||
assert.Nil(t, err)
|
||||
|
||||
file := filepath.Join(dir, name)
|
||||
data, err := ioutil.ReadFile(file)
|
||||
assert.Nil(t, err)
|
||||
|
||||
modifyData := string(data) + "modify"
|
||||
err = util.CreateTemplate(category, name, modifyData)
|
||||
assert.Nil(t, err)
|
||||
|
||||
data, err = ioutil.ReadFile(file)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, string(data), modifyData)
|
||||
|
||||
assert.Nil(t, RevertTemplate(name))
|
||||
|
||||
data, err = ioutil.ReadFile(file)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, mainTemplate, string(data))
|
||||
}
|
||||
|
||||
func TestClean(t *testing.T) {
|
||||
name := "main.tpl"
|
||||
err := util.InitTemplates(category, templates)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Nil(t, Clean())
|
||||
|
||||
dir, err := util.GetTemplateDir(category)
|
||||
assert.Nil(t, err)
|
||||
|
||||
file := filepath.Join(dir, name)
|
||||
_, err = ioutil.ReadFile(file)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
name := "main.tpl"
|
||||
err := util.InitTemplates(category, templates)
|
||||
assert.Nil(t, err)
|
||||
|
||||
dir, err := util.GetTemplateDir(category)
|
||||
assert.Nil(t, err)
|
||||
|
||||
file := filepath.Join(dir, name)
|
||||
data, err := ioutil.ReadFile(file)
|
||||
assert.Nil(t, err)
|
||||
|
||||
modifyData := string(data) + "modify"
|
||||
err = util.CreateTemplate(category, name, modifyData)
|
||||
assert.Nil(t, err)
|
||||
|
||||
data, err = ioutil.ReadFile(file)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, string(data), modifyData)
|
||||
|
||||
assert.Nil(t, Update(category))
|
||||
|
||||
data, err = ioutil.ReadFile(file)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, mainTemplate, string(data))
|
||||
}
|
||||
|
||||
func TestGetCategory(t *testing.T) {
|
||||
assert.Equal(t, category, GetCategory())
|
||||
}
|
||||
25
tools/goctl/rpc/generator/test.proto
Normal file
25
tools/goctl/rpc/generator/test.proto
Normal file
@@ -0,0 +1,25 @@
|
||||
// test proto
|
||||
syntax = "proto3";
|
||||
|
||||
package test;
|
||||
option go_package = "go";
|
||||
|
||||
import "test_base.proto";
|
||||
|
||||
message TestMessage{
|
||||
base.CommonReq req = 1;
|
||||
}
|
||||
message TestReq{}
|
||||
message TestReply{
|
||||
base.CommonReply reply = 2;
|
||||
}
|
||||
|
||||
enum TestEnum {
|
||||
unknown = 0;
|
||||
male = 1;
|
||||
female = 2;
|
||||
}
|
||||
|
||||
service TestService{
|
||||
rpc TestRpc (TestReq)returns(TestReply);
|
||||
}
|
||||
12
tools/goctl/rpc/generator/test_base.proto
Normal file
12
tools/goctl/rpc/generator/test_base.proto
Normal file
@@ -0,0 +1,12 @@
|
||||
// test proto
|
||||
syntax = "proto3";
|
||||
|
||||
package base;
|
||||
|
||||
message CommonReq {
|
||||
string in = 1;
|
||||
}
|
||||
|
||||
message CommonReply {
|
||||
string out = 1;
|
||||
}
|
||||
18
tools/goctl/rpc/generator/test_go_option.proto
Normal file
18
tools/goctl/rpc/generator/test_go_option.proto
Normal file
@@ -0,0 +1,18 @@
|
||||
// test proto
|
||||
syntax = "proto3";
|
||||
|
||||
package stream;
|
||||
|
||||
option go_package="go";
|
||||
|
||||
message StreamReq {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message StreamResp {
|
||||
string greet = 1;
|
||||
}
|
||||
|
||||
service StreamGreeter {
|
||||
rpc greet(StreamReq) returns (StreamResp);
|
||||
}
|
||||
18
tools/goctl/rpc/generator/test_import.proto
Normal file
18
tools/goctl/rpc/generator/test_import.proto
Normal file
@@ -0,0 +1,18 @@
|
||||
// test proto
|
||||
syntax = "proto3";
|
||||
|
||||
package greet;
|
||||
import "base/common.proto";
|
||||
|
||||
message In {
|
||||
string name = 1;
|
||||
common.User user = 2;
|
||||
}
|
||||
|
||||
message Out {
|
||||
string greet = 1;
|
||||
}
|
||||
|
||||
service StreamGreeter {
|
||||
rpc greet(In) returns (Out);
|
||||
}
|
||||
18
tools/goctl/rpc/generator/test_option.proto
Normal file
18
tools/goctl/rpc/generator/test_option.proto
Normal file
@@ -0,0 +1,18 @@
|
||||
// test proto
|
||||
syntax = "proto3";
|
||||
|
||||
package stream;
|
||||
|
||||
option go_package="github.com/tal-tech/go-zero";
|
||||
|
||||
message StreamReq {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message StreamResp {
|
||||
string greet = 1;
|
||||
}
|
||||
|
||||
service StreamGreeter {
|
||||
rpc greet(StreamReq) returns (StreamResp);
|
||||
}
|
||||
16
tools/goctl/rpc/generator/test_stream.proto
Normal file
16
tools/goctl/rpc/generator/test_stream.proto
Normal file
@@ -0,0 +1,16 @@
|
||||
// test proto
|
||||
syntax = "proto3";
|
||||
|
||||
package stream;
|
||||
|
||||
message StreamReq {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message StreamResp {
|
||||
string greet = 1;
|
||||
}
|
||||
|
||||
service StreamGreeter {
|
||||
rpc greet(StreamReq) returns (StreamResp);
|
||||
}
|
||||
18
tools/goctl/rpc/generator/test_word_option.proto
Normal file
18
tools/goctl/rpc/generator/test_word_option.proto
Normal file
@@ -0,0 +1,18 @@
|
||||
// test proto
|
||||
syntax = "proto3";
|
||||
|
||||
package stream;
|
||||
|
||||
option go_package="user";
|
||||
|
||||
message StreamReq {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message StreamResp {
|
||||
string greet = 1;
|
||||
}
|
||||
|
||||
service StreamGreeter {
|
||||
rpc greet(StreamReq) returns (StreamResp);
|
||||
}
|
||||
Reference in New Issue
Block a user