From 1481e14c1227fc72de7be47ead26a8e6707b321f Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Fri, 16 Aug 2019 11:15:38 +0800 Subject: [PATCH] add protoc gen ecode (#274) * add protoc gen ecode * add protobuf example --- .gitignore | 1 + doc/wiki-cn/kratos-protoc.md | 37 +- example/protobuf/api.bm.go | 40 + example/protobuf/api.ecode.go | 17 + example/protobuf/api.pb.go | 1000 +++++++++++++++++ example/protobuf/api.proto | 33 + example/protobuf/api.swagger.json | 96 ++ example/protobuf/gen.sh | 3 + tool/kratos-protoc/bm.go | 2 +- tool/kratos-protoc/ecode.go | 25 + tool/kratos-protoc/main.go | 5 + tool/kratos-protoc/protoc.go | 12 +- tool/kratos-protoc/swagger.go | 2 +- tool/protobuf/pkg/naming/naming.go | 11 + .../protoc-gen-bm/generator/generator.go | 28 +- .../protobuf/protoc-gen-bswagger/generator.go | 2 +- .../protoc-gen-ecode/generator/generator.go | 117 ++ .../generator/generator_test.go | 27 + tool/protobuf/protoc-gen-ecode/main.go | 23 + 19 files changed, 1438 insertions(+), 43 deletions(-) create mode 100644 example/protobuf/api.bm.go create mode 100644 example/protobuf/api.ecode.go create mode 100644 example/protobuf/api.pb.go create mode 100644 example/protobuf/api.proto create mode 100644 example/protobuf/api.swagger.json create mode 100644 example/protobuf/gen.sh create mode 100644 tool/kratos-protoc/ecode.go create mode 100644 tool/protobuf/protoc-gen-ecode/generator/generator.go create mode 100644 tool/protobuf/protoc-gen-ecode/generator/generator_test.go create mode 100644 tool/protobuf/protoc-gen-ecode/main.go diff --git a/.gitignore b/.gitignore index 3ccbd8e00..f9f02aeb8 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,5 @@ tool/kratos-gen-bts/kratos-gen-bts tool/kratos-gen-mc/kratos-gen-mc tool/kratos/kratos-protoc/kratos-protoc tool/kratos/protobuf/protoc-gen-bm/protoc-gen-bm +tool/kratos/protobuf/protoc-gen-ecode/protoc-gen-ecode tool/kratos/protobuf/protoc-gen-bswagger/protoc-gen-bswagger diff --git a/doc/wiki-cn/kratos-protoc.md b/doc/wiki-cn/kratos-protoc.md index 817b16373..dd416d196 100644 --- a/doc/wiki-cn/kratos-protoc.md +++ b/doc/wiki-cn/kratos-protoc.md @@ -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) diff --git a/example/protobuf/api.bm.go b/example/protobuf/api.bm.go new file mode 100644 index 000000000..4e29bad26 --- /dev/null +++ b/example/protobuf/api.bm.go @@ -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) +} diff --git a/example/protobuf/api.ecode.go b/example/protobuf/api.ecode.go new file mode 100644 index 000000000..dfed755c1 --- /dev/null +++ b/example/protobuf/api.ecode.go @@ -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) +) diff --git a/example/protobuf/api.pb.go b/example/protobuf/api.pb.go new file mode 100644 index 000000000..3cdf09b00 --- /dev/null +++ b/example/protobuf/api.pb.go @@ -0,0 +1,1000 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: api.proto + +package api + +import ( + context "context" + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + io "io" + 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.ProtoPackageIsVersion2 // please upgrade the proto package + +type UserErrCode int32 + +const ( + UserErrCode_OK UserErrCode = 0 + UserErrCode_UserNotExist UserErrCode = -404 + UserErrCode_UserUpdateNameFailed UserErrCode = 10000 +) + +var UserErrCode_name = map[int32]string{ + 0: "OK", + -404: "UserNotExist", + 10000: "UserUpdateNameFailed", +} + +var UserErrCode_value = map[string]int32{ + "OK": 0, + "UserNotExist": -404, + "UserUpdateNameFailed": 10000, +} + +func (x UserErrCode) String() string { + return proto.EnumName(UserErrCode_name, int32(x)) +} + +func (UserErrCode) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_00212fb1f9d3bf1c, []int{0} +} + +type Info struct { + Mid int64 `protobuf:"varint,1,opt,name=mid,proto3" json:"mid"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"` + Sex string `protobuf:"bytes,3,opt,name=sex,proto3" json:"sex"` + Face string `protobuf:"bytes,4,opt,name=face,proto3" json:"face"` + Sign string `protobuf:"bytes,5,opt,name=sign,proto3" json:"sign"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Info) Reset() { *m = Info{} } +func (m *Info) String() string { return proto.CompactTextString(m) } +func (*Info) ProtoMessage() {} +func (*Info) Descriptor() ([]byte, []int) { + return fileDescriptor_00212fb1f9d3bf1c, []int{0} +} +func (m *Info) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Info) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Info.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Info) XXX_Merge(src proto.Message) { + xxx_messageInfo_Info.Merge(m, src) +} +func (m *Info) XXX_Size() int { + return m.Size() +} +func (m *Info) XXX_DiscardUnknown() { + xxx_messageInfo_Info.DiscardUnknown(m) +} + +var xxx_messageInfo_Info proto.InternalMessageInfo + +func (m *Info) GetMid() int64 { + if m != nil { + return m.Mid + } + return 0 +} + +func (m *Info) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Info) GetSex() string { + if m != nil { + return m.Sex + } + return "" +} + +func (m *Info) GetFace() string { + if m != nil { + return m.Face + } + return "" +} + +func (m *Info) GetSign() string { + if m != nil { + return m.Sign + } + return "" +} + +type UserReq struct { + Mid int64 `protobuf:"varint,1,opt,name=mid,proto3" json:"mid,omitempty" validate:"gt=0,required"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UserReq) Reset() { *m = UserReq{} } +func (m *UserReq) String() string { return proto.CompactTextString(m) } +func (*UserReq) ProtoMessage() {} +func (*UserReq) Descriptor() ([]byte, []int) { + return fileDescriptor_00212fb1f9d3bf1c, []int{1} +} +func (m *UserReq) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UserReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UserReq.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UserReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_UserReq.Merge(m, src) +} +func (m *UserReq) XXX_Size() int { + return m.Size() +} +func (m *UserReq) XXX_DiscardUnknown() { + xxx_messageInfo_UserReq.DiscardUnknown(m) +} + +var xxx_messageInfo_UserReq proto.InternalMessageInfo + +func (m *UserReq) GetMid() int64 { + if m != nil { + return m.Mid + } + return 0 +} + +type InfoReply struct { + Info *Info `protobuf:"bytes,1,opt,name=info,proto3" json:"info,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *InfoReply) Reset() { *m = InfoReply{} } +func (m *InfoReply) String() string { return proto.CompactTextString(m) } +func (*InfoReply) ProtoMessage() {} +func (*InfoReply) Descriptor() ([]byte, []int) { + return fileDescriptor_00212fb1f9d3bf1c, []int{2} +} +func (m *InfoReply) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *InfoReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_InfoReply.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *InfoReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_InfoReply.Merge(m, src) +} +func (m *InfoReply) XXX_Size() int { + return m.Size() +} +func (m *InfoReply) XXX_DiscardUnknown() { + xxx_messageInfo_InfoReply.DiscardUnknown(m) +} + +var xxx_messageInfo_InfoReply proto.InternalMessageInfo + +func (m *InfoReply) GetInfo() *Info { + if m != nil { + return m.Info + } + return nil +} + +func init() { + proto.RegisterEnum("user.api.UserErrCode", UserErrCode_name, UserErrCode_value) + proto.RegisterType((*Info)(nil), "user.api.Info") + proto.RegisterType((*UserReq)(nil), "user.api.UserReq") + proto.RegisterType((*InfoReply)(nil), "user.api.InfoReply") +} + +func init() { proto.RegisterFile("api.proto", fileDescriptor_00212fb1f9d3bf1c) } + +var fileDescriptor_00212fb1f9d3bf1c = []byte{ + // 366 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x51, 0x4d, 0x4b, 0xeb, 0x40, + 0x14, 0xed, 0x34, 0x79, 0xfd, 0x98, 0x3e, 0x1e, 0x7d, 0xf3, 0x9e, 0x90, 0x96, 0x92, 0x96, 0xac, + 0x8a, 0x68, 0x2a, 0x15, 0x04, 0x05, 0x37, 0x95, 0x0a, 0x52, 0xa8, 0x10, 0xe8, 0xc6, 0xdd, 0xb4, + 0x99, 0xc4, 0x81, 0x26, 0x93, 0xe6, 0x43, 0xea, 0xbf, 0x70, 0x25, 0xfe, 0x24, 0x97, 0xfe, 0x82, + 0x22, 0x75, 0x57, 0x5c, 0xb9, 0x16, 0x94, 0x7b, 0x5b, 0xa9, 0x38, 0x8b, 0xc3, 0x9c, 0x39, 0xf7, + 0x70, 0xcf, 0xbd, 0x43, 0xcb, 0x3c, 0x92, 0x76, 0x14, 0xab, 0x54, 0xb1, 0x52, 0x96, 0x88, 0xd8, + 0xe6, 0x91, 0xac, 0xef, 0xfb, 0x32, 0xbd, 0xce, 0xc6, 0xf6, 0x44, 0x05, 0x1d, 0x5f, 0xf9, 0xaa, + 0x83, 0x05, 0xe3, 0xcc, 0x43, 0x86, 0x04, 0x6f, 0x6b, 0xa3, 0x75, 0x4f, 0xa8, 0x7e, 0x11, 0x7a, + 0x8a, 0xd5, 0xa8, 0x16, 0x48, 0xd7, 0x20, 0x2d, 0xd2, 0xd6, 0x7a, 0xc5, 0xd5, 0xa2, 0x09, 0xd4, + 0x01, 0x60, 0x0d, 0xaa, 0x87, 0x3c, 0x10, 0x46, 0xbe, 0x45, 0xda, 0xe5, 0x5e, 0x69, 0xb5, 0x68, + 0x22, 0x77, 0x10, 0xc1, 0x98, 0x88, 0xb9, 0xa1, 0xa1, 0x88, 0xc6, 0x44, 0xcc, 0x1d, 0x00, 0x30, + 0x7a, 0x7c, 0x22, 0x0c, 0x7d, 0x6b, 0x04, 0xee, 0x20, 0x82, 0x9a, 0x48, 0x3f, 0x34, 0x7e, 0x6d, + 0x55, 0xe0, 0x0e, 0xa2, 0x75, 0x4c, 0x8b, 0xa3, 0x44, 0xc4, 0x8e, 0x98, 0x31, 0xfb, 0x7b, 0xb4, + 0xc6, 0xdb, 0xa2, 0x69, 0xdc, 0xf0, 0xa9, 0x74, 0x79, 0x2a, 0x4e, 0x2c, 0x3f, 0x3d, 0x3d, 0xd8, + 0x8b, 0xc5, 0x2c, 0x93, 0xb1, 0x70, 0x2d, 0xcc, 0x6b, 0x75, 0x68, 0x19, 0x46, 0x72, 0x44, 0x34, + 0xbd, 0x65, 0x16, 0xd5, 0x65, 0xe8, 0x29, 0x74, 0x57, 0xba, 0x7f, 0xec, 0xaf, 0x45, 0xd9, 0x58, + 0x82, 0xda, 0xee, 0x80, 0x56, 0xa0, 0x57, 0x3f, 0x8e, 0xcf, 0x94, 0x2b, 0x58, 0x81, 0xe6, 0x2f, + 0x07, 0xd5, 0x1c, 0xab, 0xd1, 0xdf, 0xf0, 0x3c, 0x54, 0x69, 0x7f, 0x2e, 0x93, 0xb4, 0xfa, 0xfa, + 0xfe, 0xb1, 0x3e, 0x84, 0xd5, 0xe8, 0x7f, 0x90, 0x46, 0x11, 0xa4, 0x18, 0xf2, 0x40, 0x9c, 0x73, + 0x39, 0x15, 0x6e, 0xf5, 0x6e, 0xd8, 0x3d, 0xa2, 0x3a, 0x48, 0xcc, 0xde, 0x2c, 0xf6, 0xef, 0xb6, + 0xe5, 0x66, 0xa0, 0xfa, 0xbf, 0x1f, 0x29, 0x20, 0x68, 0x6f, 0xe7, 0x71, 0x69, 0x92, 0xa7, 0xa5, + 0x49, 0x9e, 0x97, 0x26, 0x79, 0x78, 0x31, 0x73, 0x57, 0x1a, 0x8f, 0xe4, 0xb8, 0x80, 0xff, 0x74, + 0xf8, 0x19, 0x00, 0x00, 0xff, 0xff, 0x9d, 0xa7, 0xb7, 0x22, 0xed, 0x01, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// UserClient is the client API for User service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type UserClient interface { + Info(ctx context.Context, in *UserReq, opts ...grpc.CallOption) (*InfoReply, error) +} + +type userClient struct { + cc *grpc.ClientConn +} + +func NewUserClient(cc *grpc.ClientConn) UserClient { + return &userClient{cc} +} + +func (c *userClient) Info(ctx context.Context, in *UserReq, opts ...grpc.CallOption) (*InfoReply, error) { + out := new(InfoReply) + err := c.cc.Invoke(ctx, "/user.api.User/Info", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UserServer is the server API for User service. +type UserServer interface { + Info(context.Context, *UserReq) (*InfoReply, error) +} + +func RegisterUserServer(s *grpc.Server, srv UserServer) { + s.RegisterService(&_User_serviceDesc, srv) +} + +func _User_Info_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).Info(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.api.User/Info", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).Info(ctx, req.(*UserReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _User_serviceDesc = grpc.ServiceDesc{ + ServiceName: "user.api.User", + HandlerType: (*UserServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Info", + Handler: _User_Info_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "api.proto", +} + +func (m *Info) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Info) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Mid != 0 { + dAtA[i] = 0x8 + i++ + i = encodeVarintApi(dAtA, i, uint64(m.Mid)) + } + if len(m.Name) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintApi(dAtA, i, uint64(len(m.Name))) + i += copy(dAtA[i:], m.Name) + } + if len(m.Sex) > 0 { + dAtA[i] = 0x1a + i++ + i = encodeVarintApi(dAtA, i, uint64(len(m.Sex))) + i += copy(dAtA[i:], m.Sex) + } + if len(m.Face) > 0 { + dAtA[i] = 0x22 + i++ + i = encodeVarintApi(dAtA, i, uint64(len(m.Face))) + i += copy(dAtA[i:], m.Face) + } + if len(m.Sign) > 0 { + dAtA[i] = 0x2a + i++ + i = encodeVarintApi(dAtA, i, uint64(len(m.Sign))) + i += copy(dAtA[i:], m.Sign) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *UserReq) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UserReq) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Mid != 0 { + dAtA[i] = 0x8 + i++ + i = encodeVarintApi(dAtA, i, uint64(m.Mid)) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *InfoReply) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *InfoReply) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Info != nil { + dAtA[i] = 0xa + i++ + i = encodeVarintApi(dAtA, i, uint64(m.Info.Size())) + n1, err := m.Info.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n1 + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func encodeVarintApi(dAtA []byte, offset int, v uint64) int { + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return offset + 1 +} +func (m *Info) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Mid != 0 { + n += 1 + sovApi(uint64(m.Mid)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovApi(uint64(l)) + } + l = len(m.Sex) + if l > 0 { + n += 1 + l + sovApi(uint64(l)) + } + l = len(m.Face) + if l > 0 { + n += 1 + l + sovApi(uint64(l)) + } + l = len(m.Sign) + if l > 0 { + n += 1 + l + sovApi(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *UserReq) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Mid != 0 { + n += 1 + sovApi(uint64(m.Mid)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *InfoReply) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Info != nil { + l = m.Info.Size() + n += 1 + l + sovApi(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovApi(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozApi(x uint64) (n int) { + return sovApi(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Info) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Info: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Info: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Mid", wireType) + } + m.Mid = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Mid |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthApi + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApi + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sex", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthApi + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApi + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sex = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Face", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthApi + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApi + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Face = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sign", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthApi + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApi + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sign = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipApi(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthApi + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthApi + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UserReq) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UserReq: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UserReq: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Mid", wireType) + } + m.Mid = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Mid |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipApi(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthApi + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthApi + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *InfoReply) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: InfoReply: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: InfoReply: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthApi + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthApi + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Info == nil { + m.Info = &Info{} + } + if err := m.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipApi(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthApi + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthApi + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipApi(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowApi + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowApi + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + return iNdEx, nil + case 1: + iNdEx += 8 + return iNdEx, nil + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowApi + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthApi + } + iNdEx += length + if iNdEx < 0 { + return 0, ErrInvalidLengthApi + } + return iNdEx, nil + case 3: + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowApi + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipApi(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next + if iNdEx < 0 { + return 0, ErrInvalidLengthApi + } + } + return iNdEx, nil + case 4: + return iNdEx, nil + case 5: + iNdEx += 4 + return iNdEx, nil + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + } + panic("unreachable") +} + +var ( + ErrInvalidLengthApi = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowApi = fmt.Errorf("proto: integer overflow") +) diff --git a/example/protobuf/api.proto b/example/protobuf/api.proto new file mode 100644 index 000000000..ef3d04abd --- /dev/null +++ b/example/protobuf/api.proto @@ -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); +} diff --git a/example/protobuf/api.swagger.json b/example/protobuf/api.swagger.json new file mode 100644 index 000000000..32266a239 --- /dev/null +++ b/example/protobuf/api.swagger.json @@ -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" + ] + } + } +} \ No newline at end of file diff --git a/example/protobuf/gen.sh b/example/protobuf/gen.sh new file mode 100644 index 000000000..96984776c --- /dev/null +++ b/example/protobuf/gen.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +kratos tool protoc api.proto diff --git a/tool/kratos-protoc/bm.go b/tool/kratos-protoc/bm.go index 638e99876..2c6b4e13f 100644 --- a/tool/kratos-protoc/bm.go +++ b/tool/kratos-protoc/bm.go @@ -8,7 +8,7 @@ import ( const ( _getBMGen = "go get -u github.com/bilibili/kratos/tool/protobuf/protoc-gen-bm" - _bmProtoc = "protoc --proto_path=%s --proto_path=%s --proto_path=%s --bm_out=explicit_http=true:." + _bmProtoc = "protoc --proto_path=%s --proto_path=%s --proto_path=%s --bm_out=:." ) func installBMGen() error { diff --git a/tool/kratos-protoc/ecode.go b/tool/kratos-protoc/ecode.go new file mode 100644 index 000000000..22966e121 --- /dev/null +++ b/tool/kratos-protoc/ecode.go @@ -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) +} diff --git a/tool/kratos-protoc/main.go b/tool/kratos-protoc/main.go index 3b379f726..7279b39d1 100644 --- a/tool/kratos-protoc/main.go +++ b/tool/kratos-protoc/main.go @@ -27,6 +27,11 @@ func main() { Usage: "whether to use swagger for generation", Destination: &withSwagger, }, + cli.BoolFlag{ + Name: "ecode", + Usage: "whether to use ecode for generation", + Destination: &withEcode, + }, } app.Action = func(c *cli.Context) error { return protocAction(c) diff --git a/tool/kratos-protoc/protoc.go b/tool/kratos-protoc/protoc.go index 5d1058213..af96ad91b 100644 --- a/tool/kratos-protoc/protoc.go +++ b/tool/kratos-protoc/protoc.go @@ -20,16 +20,18 @@ var ( withBM bool withGRPC bool withSwagger bool + withEcode bool ) func protocAction(ctx *cli.Context) (err error) { if err = checkProtoc(); err != nil { return err } - if !withGRPC && !withBM && !withSwagger { + if !withGRPC && !withBM && !withSwagger && !withEcode { withBM = true withGRPC = true withSwagger = true + withEcode = true } if withBM { if err = installBMGen(); err != nil { @@ -55,6 +57,14 @@ func protocAction(ctx *cli.Context) (err error) { return } } + if withEcode { + if err = installEcodeGen(); err != nil { + return + } + if err = genEcode(ctx); err != nil { + return + } + } log.Printf("generate %v success.\n", ctx.Args()) return nil } diff --git a/tool/kratos-protoc/swagger.go b/tool/kratos-protoc/swagger.go index 5559cb7e9..7d1b61aaf 100644 --- a/tool/kratos-protoc/swagger.go +++ b/tool/kratos-protoc/swagger.go @@ -8,7 +8,7 @@ import ( const ( _getSwaggerGen = "go get -u github.com/bilibili/kratos/tool/protobuf/protoc-gen-bswagger" - _swaggerProtoc = "protoc --proto_path=%s --proto_path=%s --proto_path=%s --bswagger_out=explicit_http=true:." + _swaggerProtoc = "protoc --proto_path=%s --proto_path=%s --proto_path=%s --bswagger_out=:." ) func installSwaggerGen() error { diff --git a/tool/protobuf/pkg/naming/naming.go b/tool/protobuf/pkg/naming/naming.go index 7dc615c1c..37176116f 100644 --- a/tool/protobuf/pkg/naming/naming.go +++ b/tool/protobuf/pkg/naming/naming.go @@ -2,6 +2,7 @@ package naming import ( "os" + "path" "path/filepath" "strings" @@ -25,6 +26,16 @@ func GetVersionPrefix(pkg string) string { return "" } +// GenFileName returns the output name for the generated Go file. +func GenFileName(f *descriptor.FileDescriptorProto, suffix string) string { + name := *f.Name + if ext := path.Ext(name); ext == ".pb" || ext == ".proto" || ext == ".protodevel" { + name = name[:len(name)-len(ext)] + } + name += suffix + return name +} + func ServiceName(service *descriptor.ServiceDescriptorProto) string { return utils.CamelCase(service.GetName()) } diff --git a/tool/protobuf/protoc-gen-bm/generator/generator.go b/tool/protobuf/protoc-gen-bm/generator/generator.go index 149ccbc63..ca9a06b50 100644 --- a/tool/protobuf/protoc-gen-bm/generator/generator.go +++ b/tool/protobuf/protoc-gen-bm/generator/generator.go @@ -44,9 +44,6 @@ func (t *bm) Generate(in *plugin.CodeGeneratorRequest) *plugin.CodeGeneratorResp func (t *bm) generateForFile(file *descriptor.FileDescriptorProto) *plugin.CodeGeneratorResponse_File { resp := new(plugin.CodeGeneratorResponse_File) - //if len(file.Service) == 0 { - // return nil - //} t.generateFileHeader(file, t.GenPkgName) t.generateImports(file) @@ -56,11 +53,8 @@ func (t *bm) generateForFile(file *descriptor.FileDescriptorProto) *plugin.CodeG count += t.generateBMInterface(file, service) t.generateBMRoute(file, service, i) } - //if count == 0 { - // return nil - //} - resp.Name = proto.String(naming.GoFileName(file, ".bm.go")) + resp.Name = proto.String(naming.GenFileName(file, ".bm.go")) resp.Content = proto.String(t.FormattedOutput()) t.Output.Reset() @@ -88,13 +82,13 @@ func (t *bm) generateFileHeader(file *descriptor.FileDescriptorProto, pkgName st t.P("// source: ", file.GetName()) t.P() if t.filesHandled == 0 { - // doc for the first file - t.P("/*") - t.P("Package ", t.GenPkgName, " is a generated blademaster stub package.") - t.P("This code was generated with kratos/tool/protobuf/protoc-gen-bm ", generator.Version, ".") - t.P() 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 blademaster stub package.") + t.P("This code was generated with kratos/tool/protobuf/protoc-gen-bm ", 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 @@ -102,12 +96,12 @@ func (t *bm) generateFileHeader(file *descriptor.FileDescriptorProto, pkgName st 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("It is generated from these files:") - for _, f := range t.GenFiles { - t.P("\t", f.GetName()) - } - t.P("*/") } t.P(`package `, pkgName) t.P() diff --git a/tool/protobuf/protoc-gen-bswagger/generator.go b/tool/protobuf/protoc-gen-bswagger/generator.go index ec1a9d71b..b39fe16f2 100644 --- a/tool/protobuf/protoc-gen-bswagger/generator.go +++ b/tool/protobuf/protoc-gen-bswagger/generator.go @@ -66,7 +66,7 @@ func (t *swaggerGen) generateSwagger(file *descriptor.FileDescriptorProto) *plug t.defsMap = map[string]*typemap.MessageDefinition{} out := &plugin.CodeGeneratorResponse_File{} - name := naming.GoFileName(file, ".swagger.json") + name := naming.GenFileName(file, ".swagger.json") for _, svc := range file.Service { for _, meth := range svc.Method { if !t.ShouldGenForMethod(file, svc, meth) { diff --git a/tool/protobuf/protoc-gen-ecode/generator/generator.go b/tool/protobuf/protoc-gen-ecode/generator/generator.go new file mode 100644 index 000000000..0aa88cab1 --- /dev/null +++ b/tool/protobuf/protoc-gen-ecode/generator/generator.go @@ -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(")") +} diff --git a/tool/protobuf/protoc-gen-ecode/generator/generator_test.go b/tool/protobuf/protoc-gen-ecode/generator/generator_test.go new file mode 100644 index 000000000..35e1a9240 --- /dev/null +++ b/tool/protobuf/protoc-gen-ecode/generator/generator_test.go @@ -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) +} diff --git a/tool/protobuf/protoc-gen-ecode/main.go b/tool/protobuf/protoc-gen-ecode/main.go new file mode 100644 index 000000000..0ce35e37a --- /dev/null +++ b/tool/protobuf/protoc-gen-ecode/main.go @@ -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) +}