parent
c1f9b5ca81
commit
1481e14c12
@ -1,38 +1,31 @@ |
||||
### kratos tool protoc |
||||
|
||||
``` |
||||
// generate all |
||||
```shell |
||||
# generate all |
||||
kratos tool protoc api.proto |
||||
// generate gRPC |
||||
# generate gRPC |
||||
kratos tool protoc --grpc api.proto |
||||
// generate BM HTTP |
||||
# generate BM HTTP |
||||
kratos tool protoc --bm api.proto |
||||
// generate swagger |
||||
# generate ecode |
||||
kratos tool protoc --ecode api.proto |
||||
# generate swagger |
||||
kratos tool protoc --swagger api.proto |
||||
``` |
||||
执行对应生成 `api.pb.go/api.bm.go/api.swagger.json` 源文档。 |
||||
|
||||
> 该工具在Windows/Linux下运行,需提前安装好 protobuf 工具 |
||||
|
||||
该工具实际是一段`shell`脚本,其中自动将`protoc`命令进行了拼接,识别了需要的`*.proto`文件和当前目录下的`proto`文件,最终会拼接为如下命令进行执行: |
||||
|
||||
```shell |
||||
export $KRATOS_HOME = kratos路径 |
||||
export $KRATOS_DEMO = 项目路径 |
||||
执行生成如 `api.pb.go/api.bm.go/api.swagger.json/api.ecode.go` 的对应文件,需要注意的是:`ecode`生成有固定规则,需要首先是`enum`类型,且`enum`名字要以`ErrCode`结尾,如`enum UserErrCode`。详情可见:[example](https://github.com/bilibili/kratos/tree/master/example/protobuf) |
||||
|
||||
// 生成:api.pb.go |
||||
protoc -I$GOPATH/src:$KRATOS_HOME/third_party:$KRATOS_DEMO/api --gofast_out=plugins=grpc:$KRATOS_DEMO/api $KRATOS_DEMO/api/api.proto |
||||
> 该工具在Windows/Linux下运行,需提前安装好 [protobuf](https://github.com/google/protobuf) 工具 |
||||
|
||||
// 生成:api.bm.go |
||||
protoc -I$GOPATH/src:$KRATOS_HOME/third_party:$KRATOS_DEMO/api --bm_out=$KRATOS_DEMO/api $KRATOS_DEMO/api/api.proto |
||||
`kratos tool protoc`本质上是拼接好了`protoc`命令然后进行执行,在执行时会打印出对应执行的`protoc`命令,如下可见: |
||||
|
||||
// 生成:api.swagger.json |
||||
protoc -I$GOPATH/src:$KRATOS_HOME/third_party:$KRATOS_DEMO/api --bswagger_out=$KRATOS_DEMO/api $KRATOS_DEMO/api/api.proto |
||||
```shell |
||||
protoc --proto_path=$GOPATH --proto_path=$GOPATH/github.com/bilibili/kratos/third_party --proto_path=. --bm_out=:. api.proto |
||||
protoc --proto_path=$GOPATH --proto_path=$GOPATH/github.com/bilibili/kratos/third_party --proto_path=. --gofast_out=plugins=grpc:. api.proto |
||||
protoc --proto_path=$GOPATH --proto_path=$GOPATH/github.com/bilibili/kratos/third_party --proto_path=. --bswagger_out=:. api.proto |
||||
protoc --proto_path=$GOPATH --proto_path=$GOPATH/github.com/bilibili/kratos/third_party --proto_path=. --ecode_out=:. api.proto |
||||
``` |
||||
|
||||
大家也可以参考该命令进行`proto`生成,也可以参考 [protobuf](https://github.com/google/protobuf) 官方参数。 |
||||
|
||||
|
||||
------------- |
||||
|
||||
[文档目录树](summary.md) |
||||
|
@ -0,0 +1,40 @@ |
||||
// Code generated by protoc-gen-bm v0.1, DO NOT EDIT.
|
||||
// source: api.proto
|
||||
|
||||
package api |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
bm "github.com/bilibili/kratos/pkg/net/http/blademaster" |
||||
"github.com/bilibili/kratos/pkg/net/http/blademaster/binding" |
||||
) |
||||
|
||||
// to suppressed 'imported but not used warning'
|
||||
var _ *bm.Context |
||||
var _ context.Context |
||||
var _ binding.StructValidator |
||||
|
||||
var PathUserInfo = "/user.api.User/Info" |
||||
|
||||
// UserBMServer is the server API for User service.
|
||||
type UserBMServer interface { |
||||
Info(ctx context.Context, req *UserReq) (resp *InfoReply, err error) |
||||
} |
||||
|
||||
var UserSvc UserBMServer |
||||
|
||||
func userInfo(c *bm.Context) { |
||||
p := new(UserReq) |
||||
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil { |
||||
return |
||||
} |
||||
resp, err := UserSvc.Info(c, p) |
||||
c.JSON(resp, err) |
||||
} |
||||
|
||||
// RegisterUserBMServer Register the blademaster route
|
||||
func RegisterUserBMServer(e *bm.Engine, server UserBMServer) { |
||||
UserSvc = server |
||||
e.GET("/user.api.User/Info", userInfo) |
||||
} |
@ -0,0 +1,17 @@ |
||||
// Code generated by protoc-gen-ecode v0.1, DO NOT EDIT.
|
||||
// source: api.proto
|
||||
|
||||
package api |
||||
|
||||
import ( |
||||
"github.com/bilibili/kratos/pkg/ecode" |
||||
) |
||||
|
||||
// to suppressed 'imported but not used warning'
|
||||
var _ ecode.Codes |
||||
|
||||
// UserErrCode ecode
|
||||
var ( |
||||
UserNotExist = ecode.New(-404) |
||||
UserUpdateNameFailed = ecode.New(10000) |
||||
) |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,33 @@ |
||||
syntax = "proto3"; |
||||
|
||||
package user.api; |
||||
|
||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto"; |
||||
|
||||
option go_package = "api"; |
||||
|
||||
enum UserErrCode { |
||||
OK = 0; |
||||
UserNotExist = -404; |
||||
UserUpdateNameFailed = 10000; |
||||
} |
||||
|
||||
message Info { |
||||
int64 mid = 1 [(gogoproto.jsontag) = "mid"]; |
||||
string name = 2 [(gogoproto.jsontag) = "name"]; |
||||
string sex = 3 [(gogoproto.jsontag) = "sex"]; |
||||
string face = 4 [(gogoproto.jsontag) = "face"]; |
||||
string sign = 5 [(gogoproto.jsontag) = "sign"]; |
||||
} |
||||
|
||||
message UserReq { |
||||
int64 mid = 1 [(gogoproto.moretags) = "validate:\"gt=0,required\""]; |
||||
} |
||||
|
||||
message InfoReply { |
||||
Info info = 1; |
||||
} |
||||
|
||||
service User { |
||||
rpc Info(UserReq) returns (InfoReply); |
||||
} |
@ -0,0 +1,96 @@ |
||||
{ |
||||
"swagger": "2.0", |
||||
"info": { |
||||
"title": "api.proto", |
||||
"version": "" |
||||
}, |
||||
"schemes": [ |
||||
"http", |
||||
"https" |
||||
], |
||||
"consumes": [ |
||||
"application/json", |
||||
"multipart/form-data" |
||||
], |
||||
"produces": [ |
||||
"application/json" |
||||
], |
||||
"paths": { |
||||
"/user.api.User/Info": { |
||||
"get": { |
||||
"summary": "/user.api.User/Info", |
||||
"responses": { |
||||
"200": { |
||||
"description": "A successful response.", |
||||
"schema": { |
||||
"type": "object", |
||||
"properties": { |
||||
"code": { |
||||
"type": "integer" |
||||
}, |
||||
"message": { |
||||
"type": "string" |
||||
}, |
||||
"data": { |
||||
"$ref": "#/definitions/.user.api.InfoReply" |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
"parameters": [ |
||||
{ |
||||
"name": "mid", |
||||
"in": "query", |
||||
"required": true, |
||||
"type": "integer" |
||||
} |
||||
], |
||||
"tags": [ |
||||
"user.api.User" |
||||
] |
||||
} |
||||
} |
||||
}, |
||||
"definitions": { |
||||
".user.api.Info": { |
||||
"type": "object", |
||||
"properties": { |
||||
"mid": { |
||||
"type": "integer" |
||||
}, |
||||
"name": { |
||||
"type": "string" |
||||
}, |
||||
"sex": { |
||||
"type": "string" |
||||
}, |
||||
"face": { |
||||
"type": "string" |
||||
}, |
||||
"sign": { |
||||
"type": "string" |
||||
} |
||||
} |
||||
}, |
||||
".user.api.InfoReply": { |
||||
"type": "object", |
||||
"properties": { |
||||
"info": { |
||||
"$ref": "#/definitions/.user.api.Info" |
||||
} |
||||
} |
||||
}, |
||||
".user.api.UserReq": { |
||||
"type": "object", |
||||
"properties": { |
||||
"mid": { |
||||
"type": "integer" |
||||
} |
||||
}, |
||||
"required": [ |
||||
"mid" |
||||
] |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,3 @@ |
||||
#!/bin/bash |
||||
|
||||
kratos tool protoc api.proto |
@ -0,0 +1,25 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"os/exec" |
||||
|
||||
"github.com/urfave/cli" |
||||
) |
||||
|
||||
const ( |
||||
_getEcodeGen = "go get -u github.com/bilibili/kratos/tool/protobuf/protoc-gen-ecode" |
||||
_ecodeProtoc = "protoc --proto_path=%s --proto_path=%s --proto_path=%s --ecode_out=:." |
||||
) |
||||
|
||||
func installEcodeGen() error { |
||||
if _, err := exec.LookPath("protoc-gen-ecode"); err != nil { |
||||
if err := goget(_getEcodeGen); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func genEcode(ctx *cli.Context) error { |
||||
return generate(ctx, _ecodeProtoc) |
||||
} |
@ -0,0 +1,117 @@ |
||||
package generator |
||||
|
||||
import ( |
||||
"strconv" |
||||
"strings" |
||||
|
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/generator" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/naming" |
||||
"github.com/golang/protobuf/proto" |
||||
"github.com/golang/protobuf/protoc-gen-go/descriptor" |
||||
plugin "github.com/golang/protobuf/protoc-gen-go/plugin" |
||||
) |
||||
|
||||
type ecode struct { |
||||
generator.Base |
||||
filesHandled int |
||||
} |
||||
|
||||
// EcodeGenerator ecode generator.
|
||||
func EcodeGenerator() *ecode { |
||||
t := &ecode{} |
||||
return t |
||||
} |
||||
|
||||
// Generate ...
|
||||
func (t *ecode) Generate(in *plugin.CodeGeneratorRequest) *plugin.CodeGeneratorResponse { |
||||
t.Setup(in) |
||||
|
||||
// Showtime! Generate the response.
|
||||
resp := new(plugin.CodeGeneratorResponse) |
||||
for _, f := range t.GenFiles { |
||||
respFile := t.generateForFile(f) |
||||
if respFile != nil { |
||||
resp.File = append(resp.File, respFile) |
||||
} |
||||
} |
||||
return resp |
||||
} |
||||
|
||||
func (t *ecode) generateForFile(file *descriptor.FileDescriptorProto) *plugin.CodeGeneratorResponse_File { |
||||
var enums []*descriptor.EnumDescriptorProto |
||||
for _, enum := range file.EnumType { |
||||
if strings.HasSuffix(*enum.Name, "ErrCode") { |
||||
enums = append(enums, enum) |
||||
} |
||||
} |
||||
if len(enums) == 0 { |
||||
return nil |
||||
} |
||||
resp := new(plugin.CodeGeneratorResponse_File) |
||||
t.generateFileHeader(file, t.GenPkgName) |
||||
t.generateImports(file) |
||||
for _, enum := range enums { |
||||
t.generateEcode(file, enum) |
||||
} |
||||
|
||||
resp.Name = proto.String(naming.GenFileName(file, ".ecode.go")) |
||||
resp.Content = proto.String(t.FormattedOutput()) |
||||
t.Output.Reset() |
||||
|
||||
t.filesHandled++ |
||||
return resp |
||||
} |
||||
|
||||
func (t *ecode) generateFileHeader(file *descriptor.FileDescriptorProto, pkgName string) { |
||||
t.P("// Code generated by protoc-gen-ecode ", generator.Version, ", DO NOT EDIT.") |
||||
t.P("// source: ", file.GetName()) |
||||
t.P() |
||||
if t.filesHandled == 0 { |
||||
comment, err := t.Reg.FileComments(file) |
||||
if err == nil && comment.Leading != "" { |
||||
// doc for the first file
|
||||
t.P("/*") |
||||
t.P("Package ", t.GenPkgName, " is a generated ecode package.") |
||||
t.P("This code was generated with kratos/tool/protobuf/protoc-gen-ecode ", generator.Version, ".") |
||||
t.P() |
||||
for _, line := range strings.Split(comment.Leading, "\n") { |
||||
line = strings.TrimPrefix(line, " ") |
||||
// ensure we don't escape from the block comment
|
||||
line = strings.Replace(line, "*/", "* /", -1) |
||||
t.P(line) |
||||
} |
||||
t.P() |
||||
t.P("It is generated from these files:") |
||||
for _, f := range t.GenFiles { |
||||
t.P("\t", f.GetName()) |
||||
} |
||||
t.P("*/") |
||||
} |
||||
} |
||||
t.P(`package `, pkgName) |
||||
t.P() |
||||
} |
||||
|
||||
func (t *ecode) generateImports(file *descriptor.FileDescriptorProto) { |
||||
t.P(`import (`) |
||||
t.P(` "github.com/bilibili/kratos/pkg/ecode"`) |
||||
t.P(`)`) |
||||
t.P() |
||||
t.P(`// to suppressed 'imported but not used warning'`) |
||||
t.P(`var _ ecode.Codes`) |
||||
} |
||||
|
||||
func (t *ecode) generateEcode(file *descriptor.FileDescriptorProto, enum *descriptor.EnumDescriptorProto) { |
||||
t.P("// ", *enum.Name, " ecode") |
||||
t.P("var (") |
||||
|
||||
for _, item := range enum.Value { |
||||
if *item.Number == 0 { |
||||
continue |
||||
} |
||||
// NOTE: eg: t.P("UserNotExist = New(-404) ")
|
||||
t.P(*item.Name, " = ", "ecode.New(", strconv.Itoa(int(*item.Number)), ")") |
||||
} |
||||
|
||||
t.P(")") |
||||
} |
@ -0,0 +1,27 @@ |
||||
package generator |
||||
|
||||
import ( |
||||
"os" |
||||
"os/exec" |
||||
"testing" |
||||
|
||||
"github.com/golang/protobuf/proto" |
||||
plugin "github.com/golang/protobuf/protoc-gen-go/plugin" |
||||
) |
||||
|
||||
func TestGenerateParseCommandLineParamsError(t *testing.T) { |
||||
if os.Getenv("BE_CRASHER") == "1" { |
||||
g := &ecode{} |
||||
g.Generate(&plugin.CodeGeneratorRequest{ |
||||
Parameter: proto.String("invalid"), |
||||
}) |
||||
return |
||||
} |
||||
cmd := exec.Command(os.Args[0], "-test.run=TestGenerateParseCommandLineParamsError") |
||||
cmd.Env = append(os.Environ(), "BE_CRASHER=1") |
||||
err := cmd.Run() |
||||
if e, ok := err.(*exec.ExitError); ok && !e.Success() { |
||||
return |
||||
} |
||||
t.Fatalf("process ran with err %v, want exit status 1", err) |
||||
} |
@ -0,0 +1,23 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"flag" |
||||
"fmt" |
||||
"os" |
||||
|
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/gen" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/generator" |
||||
ecodegen "github.com/bilibili/kratos/tool/protobuf/protoc-gen-ecode/generator" |
||||
) |
||||
|
||||
func main() { |
||||
versionFlag := flag.Bool("version", false, "print version and exit") |
||||
flag.Parse() |
||||
if *versionFlag { |
||||
fmt.Println(generator.Version) |
||||
os.Exit(0) |
||||
} |
||||
|
||||
g := ecodegen.EcodeGenerator() |
||||
gen.Main(g) |
||||
} |
Loading…
Reference in new issue