![Sourcegraph](https://sourcegraph.com/github.com/searKing/golang/-/badge.svg)
protoc-gen-go-tag
Generates Go code using a package as a tag rewriter that enhanced protoc-gen-go.
protoc-gen-go-tag Generates Go code using a package as a tag rewriter that enhanced protoc-gen-go.
The file xxx.pb.go is modified by protoc-gen-go based on xxx.proto. It has helpful defaults designed for use with
protobuf with custom struct tags.
For example, given this snippet,
apply this proto file
syntax = "proto3";
package pb;
//import "google/protobuf/descriptor.proto";
import "github.com/searKing/golang/tools/cmd/protoc-gen-go-tag/tag/tag.proto";
message Http{
string protocol = 1;
string version = 2[json_name = "Url", (google.protobuf.field_tag) = {struct_tag: "validate:\"gte=0,lte=130\""}];;
Url url = 3[json_name = "Url", (google.protobuf.field_tag) = {struct_tag: "json:\"url_tag,omitempty\""}];
message Url {
string scheme = 1[json_name = "Scheme", (google.protobuf.field_tag) = {struct_tag: "json:\"schema_tag,omitempty\""}];
// string scheme = 1[json_name = "Scheme"];
}
}
running this command
# https://github.com/searKing/golang/blob/master/tools/cmd/protoc-gen-go-tag/tag/tag.proto
# `tag.proto` needs to be on the `protoc` include path
protoc -I . --go-tag_out=paths=source_relative:. *.proto
in the same directory will create the file pill.pb.go, containing
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: tag.proto
package pb
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
_ "github.com/searKing/golang/tools/cmd/protoc-gen-go-tag/tag"
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 Http struct {
Protocol string `protobuf:"bytes,1,opt,name=protocol,proto3" json:"protocol,omitempty"`
Version string `protobuf:"bytes,2,opt,name=version,json=Url,proto3" json:"version,omitempty" validate:"gte=0,lte=130"`
Url *Http_Url `protobuf:"bytes,3,opt,name=url,json=Url,proto3" json:"url_tag,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Http) Reset() { *m = Http{} }
func (m *Http) String() string { return proto.CompactTextString(m) }
func (*Http) ProtoMessage() {}
func (*Http) Descriptor() ([]byte, []int) {
return fileDescriptor_27f545bcde37ecb5, []int{0}
}
func (m *Http) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Http.Unmarshal(m, b)
}
func (m *Http) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Http.Marshal(b, m, deterministic)
}
func (m *Http) XXX_Merge(src proto.Message) {
xxx_messageInfo_Http.Merge(m, src)
}
func (m *Http) XXX_Size() int {
return xxx_messageInfo_Http.Size(m)
}
func (m *Http) XXX_DiscardUnknown() {
xxx_messageInfo_Http.DiscardUnknown(m)
}
var xxx_messageInfo_Http proto.InternalMessageInfo
func (m *Http) GetProtocol() string {
if m != nil {
return m.Protocol
}
return ""
}
func (m *Http) GetVersion() string {
if m != nil {
return m.Version
}
return ""
}
func (m *Http) GetUrl() *Http_Url {
if m != nil {
return m.Url
}
return nil
}
type Http_Url struct {
Scheme string `protobuf:"bytes,1,opt,name=scheme,json=Scheme,proto3" json:"schema_tag,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Http_Url) Reset() { *m = Http_Url{} }
func (m *Http_Url) String() string { return proto.CompactTextString(m) }
func (*Http_Url) ProtoMessage() {}
func (*Http_Url) Descriptor() ([]byte, []int) {
return fileDescriptor_27f545bcde37ecb5, []int{0, 0}
}
func (m *Http_Url) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Http_Url.Unmarshal(m, b)
}
func (m *Http_Url) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Http_Url.Marshal(b, m, deterministic)
}
func (m *Http_Url) XXX_Merge(src proto.Message) {
xxx_messageInfo_Http_Url.Merge(m, src)
}
func (m *Http_Url) XXX_Size() int {
return xxx_messageInfo_Http_Url.Size(m)
}
func (m *Http_Url) XXX_DiscardUnknown() {
xxx_messageInfo_Http_Url.DiscardUnknown(m)
}
var xxx_messageInfo_Http_Url proto.InternalMessageInfo
func (m *Http_Url) GetScheme() string {
if m != nil {
return m.Scheme
}
return ""
}
func init() {
proto.RegisterType((*Http)(nil), "pb.Http")
proto.RegisterType((*Http_Url)(nil), "pb.Http.Url")
}
func init() { proto.RegisterFile("tag.proto", fileDescriptor_27f545bcde37ecb5) }
var fileDescriptor_27f545bcde37ecb5 = []byte{
// 262 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x8f, 0x31, 0x4f, 0xc3, 0x30,
0x10, 0x85, 0x95, 0x16, 0x05, 0x6a, 0x98, 0x32, 0x45, 0x41, 0xd0, 0x92, 0xa9, 0x43, 0x13, 0x17,
0xca, 0x42, 0xa5, 0x22, 0x54, 0x31, 0x20, 0xb1, 0x15, 0x75, 0x46, 0x4e, 0x6a, 0x5d, 0x83, 0x1c,
0x9f, 0x65, 0x5f, 0x2a, 0xf1, 0xf7, 0xfa, 0x33, 0x18, 0xfa, 0x5b, 0x50, 0x6d, 0x60, 0x60, 0xb8,
0xe1, 0xf4, 0xde, 0xf7, 0xee, 0x1e, 0x1b, 0x90, 0x80, 0xd2, 0x58, 0x24, 0x4c, 0x7a, 0xa6, 0xca,
0x9e, 0xa1, 0xa1, 0x6d, 0x57, 0x95, 0x35, 0xb6, 0xdc, 0x49, 0x61, 0x5f, 0x1b, 0x0d, 0x1c, 0x50,
0x09, 0x0d, 0x9c, 0x10, 0x95, 0xe3, 0x75, 0xbb, 0xe1, 0xde, 0x5f, 0x17, 0x20, 0x75, 0x01, 0x58,
0x90, 0x00, 0xfe, 0x33, 0x21, 0x29, 0xff, 0x8a, 0xd8, 0xc9, 0x0b, 0x91, 0x49, 0x32, 0x76, 0x16,
0xbc, 0xa8, 0xd2, 0x68, 0x14, 0x8d, 0x07, 0xab, 0xbf, 0x3d, 0xb9, 0x67, 0xa7, 0x3b, 0x69, 0x5d,
0x83, 0x3a, 0xed, 0x1d, 0xa5, 0xe5, 0xf5, 0xfe, 0x30, 0xcc, 0x58, 0xba, 0x13, 0xaa, 0xd9, 0x08,
0x92, 0xf3, 0x1c, 0x48, 0x2e, 0xa6, 0x13, 0x45, 0x72, 0x71, 0x3b, 0x9b, 0xe6, 0xab, 0xfe, 0xda,
0xaa, 0xe4, 0x91, 0xf5, 0x3b, 0xab, 0xd2, 0xfe, 0x28, 0x1a, 0x9f, 0xdf, 0x5d, 0x94, 0xa6, 0x2a,
0x8f, 0x87, 0xca, 0xb5, 0x55, 0xbf, 0xfc, 0x87, 0x43, 0x3d, 0xcf, 0x3b, 0xab, 0xde, 0x49, 0xc0,
0x04, 0xdb, 0x86, 0x64, 0x6b, 0xe8, 0x33, 0xf0, 0xd9, 0x13, 0xf3, 0x31, 0x0f, 0x2c, 0x76, 0xf5,
0x56, 0xb6, 0x32, 0xbc, 0xb5, 0xbc, 0xd9, 0x1f, 0x86, 0x57, 0xec, 0x32, 0xb0, 0x5e, 0x11, 0xff,
0xf1, 0xf8, 0xcd, 0x03, 0x55, 0xec, 0x1b, 0xcc, 0xbe, 0x03, 0x00, 0x00, 0xff, 0xff, 0xaf, 0x2e,
0x0f, 0x31, 0x3a, 0x01, 0x00, 0x00,
}
Download/Install
The easiest way to install is to
run go get -u github.com/searKing/golang/tools/cmd/protoc-gen-go-tag@v1.0.175;go get -u github.com/searKing/golang/tools/cmd/protoc-gen-go-tag
. You can also manually git clone the repository to $GOPATH/src/github.com/searKing/golang/tools/cmd/protoc-gen-go-tag
.
protoc-gen-go-tag: program not found or is not executable
The protoc
compiler expects to find plugins named proto-gen-xxx
on the execution $PATH
. So first:
export PATH=${PATH}:$(go env GOPATH)/bin
xxx.proto: Tried to write the same file twice.
- The
protoc-gen-go-tag
rewrites *.pb.go
by proto-gen-go
already. So use protoc-gen-go-tag
instead
of protoc-gen-go
protoc-gen-go
is installed by go get -u google.golang.org/protobuf/cmd/protoc-gen-go
- Basically the magical incantation (apart from includes) is the
--go-tag_out
. That triggers the
protoc-gen-go-tag
plugin to generate *.pb.go
. That's it :)
- github.com/golang/protobuf has been superseded by
the google.golang.org/protobuf module
- install
protoc-gen-go-tag
by go get github.com/searKing/golang/tools/cmd/protoc-gen-go-tag@e27209892e58d3df53c587f1feefb6290af17d85
protoc -I . --go_out=paths=source_relative:. --go-tag_out=paths=source_relative:. *.proto
*.pb.go
generated by protoc-gen-go
will be rewritten by protoc-gen-go-tag
trick: embedded tag.proto into your proto directly, avoid include the tag.proto
- Step 1 replace
import "github.com/searKing/golang/tools/cmd/protoc-gen-go-tag/tag/tag.proto";
with code in
the tag.proto
- Step 2 replace
google.protobuf.field_tag
with field_tag
syntax = "proto3";
package pb;
// import "github.com/searKing/golang/tools/cmd/protoc-gen-go-tag/tag/tag.proto";
import "google/protobuf/descriptor.proto";
extend google.protobuf.FieldOptions {
FieldTag field_tag = 65000;
}
message FieldTag {
// struct tag.
string struct_tag = 1;// custom struct tag
UpdateStrategy update_strategy = 2;// update strategy
enum UpdateStrategy {
update = 0;// use custom struct tag to update struct tag generated by proto
replace = 1;// use custom struct tag to replace struct tag generated by proto
}
}
message Http{
string protocol = 1;
string version = 2[json_name = "Url", (field_tag) = {struct_tag: "validate:\"gte=0,lte=130\""}];;
Url url = 3[json_name = "Url", (field_tag) = {struct_tag: "json:\"url_tag,omitempty\""}];
message Url {
string scheme = 1[json_name = "Scheme", (field_tag) = {struct_tag: "json:\"schema_tag,omitempty\""}];
// string scheme = 1[json_name = "Scheme"];
}
}
Inspiring projects