Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/gotags #26

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
# For files created by specific development environment (e.g. editor),
# use alternative ways to exclude files from git.
# For example, set up .git/info/exclude or use a global .gitignore.
.idea
137 changes: 137 additions & 0 deletions cmd/protoc-gen-go/internal_gengo/gotags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Added by Hao Luo <haozzzzzzzz@gmail.com>
// Source: https://github.com/hacksomecn/protobuf-go.git
// Branch: feature/tags

// Package internal_gengo Support add custom struct field tags
// Protoc parse field tags from field's tailing comment, declare extra tags like:
// message Example {
// ...
// string name = 1; // @go_tags(`bson:"name" yaml:"name"`) FORM 1 support comment tail
// ...
// }
//
// FORM 1: Go tags regexp: `(\s?)@go_tags\(` + "(`.*`)" + `\)\s`
package internal_gengo

import (
"google.golang.org/protobuf/compiler/protogen"
"log"
"regexp"
"strings"
)

var tailingGoTagsExcludeKeys = map[string]bool{
"protobuf": true,
"protobuf_key": true,
"protobuf_val": true,
}

var commentGoTagsRe *regexp.Regexp

func init() {
var err error
commentGoTagsRe, err = regexp.Compile(`(\s?)@go_tags\(` + "(`.*`)" + `\)\s`)
if err != nil {
log.Fatalf("compile comment go tags regexp failed. %s", err)
return
}
}

// AppendGoTagsFromFieldComment append extra tags parsed from tailing comment
// tag with same name will be replaced except protobuf tags like "protobuf"、"protobuf_key"、"protobuf_val"
func AppendGoTagsFromFieldComment(
existsTags structTags,
tailComment protogen.Comments,
) (
newTags structTags,
newTailing protogen.Comments,
) {
newTags = existsTags
newTailing = tailComment

tagsMap := map[string]string{} // key -> value
seqKeys := make([]string, 0)
for _, existTags := range existsTags {
key := existTags[0]
value := existTags[1]
tagsMap[key] = value
seqKeys = append(seqKeys, key)
}

tailTags, newTailing := ParseGoTagsFromTailingComment(tailComment)
for _, tailTag := range tailTags {
key := tailTag.Key
value := tailTag.Value
if tailingGoTagsExcludeKeys[key] {
continue
}

_, exists := tagsMap[key]
if !exists { // keep sequence
seqKeys = append(seqKeys, key)
}

tagsMap[key] = value
}

newTags = make([][2]string, 0)
for _, key := range seqKeys {
tag := tagsMap[key]
newTags = append(newTags, [2]string{key, tag})
}

return
}

type GoTag struct {
Key string
Value string
}

// ParseGoTagsFromTailingComment parse go tags from comment
func ParseGoTagsFromTailingComment(tailing protogen.Comments) (
tags []GoTag,
newTailing protogen.Comments,
) {
newTailing = tailing

matched := commentGoTagsRe.FindStringSubmatch(string(tailing))
if len(matched) != 3 {
return
}

strMatched := matched[0]
strStart := matched[1]
strTagsReplacer := strings.Replace(strMatched, strStart, "", 1)
newTailing = protogen.Comments(strings.Replace(string(tailing), strTagsReplacer, "", 1))

strTags := matched[2]
strTags = strings.Trim(strTags, "`")

strPairs := strings.Split(strTags, " ")
for _, pair := range strPairs {
pair = strings.TrimSpace(pair)
if pair == "" {
continue
}

separateIndex := strings.Index(pair, ":")
if separateIndex < 0 || separateIndex == len(pair)-1 {
continue
}

key := pair[:separateIndex]
value := pair[separateIndex+1:]
value = strings.Trim(value, "\"")

tags = append(tags, GoTag{
Key: key,
Value: value,
})
}

return
}
42 changes: 42 additions & 0 deletions cmd/protoc-gen-go/internal_gengo/gotags_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package internal_gengo

import (
"fmt"
"google.golang.org/protobuf/compiler/protogen"
"regexp"
"testing"
)

func TestCommentTagsReg(t *testing.T) {
re, err := regexp.Compile(`(\s?)@go_tags\(` + "(`.*`)" + `\)\s`)
if err != nil {
t.Error(err)
return
}

str := " @go_tags(`json:\"name\"`) abc"
matched := re.FindStringSubmatch(str)
fmt.Println(len(matched), matched)
}

func TestParseGoTagsFromTailingComment(t *testing.T) {
str := " @go_tags(`json:\"name,omitempty\"`) abc"
tags, newTailing := ParseGoTagsFromTailingComment(protogen.Comments(str))
for key, value := range tags {
fmt.Println(key, value)
}
fmt.Println(newTailing)
}

func TestAppendGoTagsFromTailingComment(t *testing.T) {
tags := structTags{
{"protobuf", "abc"},
{"json", "efg"},
{"protobuf_key", "string"},
{"protobuf_val", "string"},
}
str := " @go_tags(`json:\"name,omitempty\" bson:\"name\"`) abc"
newTags, newTailing := AppendGoTagsFromFieldComment(tags, protogen.Comments(str))
fmt.Println(newTailing)
fmt.Println(newTags)
}
10 changes: 8 additions & 2 deletions cmd/protoc-gen-go/internal_gengo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,17 +418,23 @@ func genMessageField(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo, fie
tags = append(tags, gotrackTags...)
}

var leftLeading protogen.Comments
var leftTailing protogen.Comments
tags, leftLeading = AppendGoTagsFromFieldComment(tags, field.Comments.Leading)
tags, leftTailing = AppendGoTagsFromFieldComment(tags, field.Comments.Trailing)

name := field.GoName
if field.Desc.IsWeak() {
name = genid.WeakFieldPrefix_goname + name
}
g.Annotate(m.GoIdent.GoName+"."+name, field.Location)
leadingComments := appendDeprecationSuffix(field.Comments.Leading,
leadingComments := appendDeprecationSuffix(leftLeading,
field.Desc.ParentFile(),
field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated())
g.P(leadingComments,
name, " ", goType, tags,
trailingComment(field.Comments.Trailing))
//trailingComment(field.Comments.Trailing))
trailingComment(leftTailing))
sf.append(field.GoName)
}

Expand Down