parent
8266a50f3d
commit
e5fe1e4f63
@ -1,19 +0,0 @@ |
||||
#!/bin/bash |
||||
set -e |
||||
if [[ -z $GOPATH ]]; then |
||||
GOPATH=${HOME}/go |
||||
fi |
||||
BIN_PATH=$( cut -d ':' -f 1 <<< "$GOPATH" )/bin |
||||
if [[ ! -z $GOBIN ]]; then |
||||
BIN_PATH=$GOBIN |
||||
fi |
||||
if [[ ! -z $INSTALL_PATH ]]; then |
||||
BIN_PATH=$INSTALL_PATH |
||||
fi |
||||
if [[ -f $BIN_PATH/kprotoc ]]; then |
||||
echo "kprotoc alreay install, remove $BIN_PATH/kprotoc first to reinstall." |
||||
exit 1; |
||||
fi |
||||
|
||||
ln -s $GOPATH/src/github.com/bilibili/kratos/tool/kprotoc/kprotoc.sh $BIN_PATH/kprotoc |
||||
echo "install kprotoc to $BIN_PATH/kprotoc done!" |
@ -1,118 +0,0 @@ |
||||
#!/bin/bash |
||||
DEFAULT_PROTOC_GEN="gogofast" |
||||
DEFAULT_PROTOC="protoc" |
||||
KRATOS_DIR_NAME="github.com/bilibili/kratos" |
||||
USR_INCLUDE_DIR="/usr/local/include" |
||||
GOPATH=$GOPATH |
||||
if [[ -z $GOPATH ]]; then |
||||
GOPATH=${HOME}/go |
||||
fi |
||||
|
||||
function _install_protoc() { |
||||
osname=$(uname -s) |
||||
echo "install protoc ..." |
||||
case $osname in |
||||
"Darwin" ) |
||||
brew install protobuf |
||||
;; |
||||
*) |
||||
echo "unknown operating system, need install protobuf manual see: https://developers.google.com/protocol-buffers" |
||||
exit 1 |
||||
;; |
||||
esac |
||||
} |
||||
|
||||
function _install_protoc_gen() { |
||||
local protoc_gen=$1 |
||||
case $protoc_gen in |
||||
"gofast" ) |
||||
echo "install gofast from github.com/gogo/protobuf/protoc-gen-gofast" |
||||
go get github.com/gogo/protobuf/protoc-gen-gofast |
||||
;; |
||||
"gogofast" ) |
||||
echo "install gogofast from github.com/gogo/protobuf/protoc-gen-gogofast" |
||||
go get github.com/gogo/protobuf/protoc-gen-gogofast |
||||
;; |
||||
"gogo" ) |
||||
echo "install gogo from github.com/gogo/protobuf/protoc-gen-gogo" |
||||
go get github.com/gogo/protobuf/protoc-gen-gogo |
||||
;; |
||||
"go" ) |
||||
echo "install protoc-gen-go from github.com/golang/protobuf" |
||||
go get github.com/golang/protobuf/{proto,protoc-gen-go} |
||||
;; |
||||
*) |
||||
echo "can't install protoc-gen-${protoc_gen} automatic !" |
||||
exit 1; |
||||
;; |
||||
esac |
||||
} |
||||
|
||||
function _find_kratos_dir() { |
||||
local kratos_dir_name=$1 |
||||
local current_dir="$GOPATH/src/$kratos_dir_name" |
||||
if [[ ! -d $current_dir ]]; then |
||||
go get -u $kratos_dir_name |
||||
fi |
||||
echo $current_dir |
||||
} |
||||
|
||||
function _esc_string() { |
||||
echo $(echo "$1" | sed 's_/_\\/_g') |
||||
} |
||||
|
||||
function _run_protoc() { |
||||
local proto_dir=$1 |
||||
local proto_files=$(find $proto_dir -maxdepth 1 -name "*.proto") |
||||
if [[ -z $proto_files ]]; then |
||||
return |
||||
fi |
||||
local protoc_cmd="$PROTOC -I$PROTO_PATH --${PROTOC_GEN}_out=plugins=grpc:${GOPATH}/src ${proto_files}" |
||||
echo $protoc_cmd |
||||
$protoc_cmd |
||||
} |
||||
|
||||
if [[ -z $PROTOC ]]; then |
||||
PROTOC=${DEFAULT_PROTOC} |
||||
which $PROTOC |
||||
if [[ "$?" -ne "0" ]]; then |
||||
_install_protoc |
||||
fi |
||||
fi |
||||
if [[ -z $PROTOC_GEN ]]; then |
||||
PROTOC_GEN=${DEFAULT_PROTOC_GEN} |
||||
which protoc-gen-$PROTOC_GEN |
||||
if [[ "$?" -ne "0" ]]; then |
||||
_install_protoc_gen $PROTOC_GEN |
||||
fi |
||||
fi |
||||
|
||||
KRATOS_DIR=$(_find_kratos_dir $KRATOS_DIR_NAME) |
||||
if [[ "$?" != "0" ]]; then |
||||
echo "can't find kratos directoy" |
||||
exit 1 |
||||
fi |
||||
|
||||
KRATOS_PARENT=$(dirname $KRATOS_DIR) |
||||
|
||||
if [[ -z $PROTO_PATH ]]; then |
||||
PROTO_PATH=$GOPATH/src:$KRATOS_PARENT:$USR_INCLUDE_DIR |
||||
else |
||||
PROTO_PATH=$GOPATH/src:$PROTO_PATH:$KRATOS_PARENT:$USR_INCLUDE_DIR |
||||
fi |
||||
|
||||
if [[ ! -z $1 ]]; then |
||||
cd $1 |
||||
fi |
||||
TARGET_DIR=$(pwd) |
||||
|
||||
# switch to $GOPATH/src |
||||
cd $GOPATH/src |
||||
echo "switch workdir to $GOPATH/src" |
||||
|
||||
DIRS=$(find $TARGET_DIR -type d) |
||||
|
||||
for dir in $DIRS; do |
||||
echo "run protoc in $dir" |
||||
_run_protoc $dir |
||||
done |
@ -0,0 +1,25 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"os/exec" |
||||
|
||||
"github.com/urfave/cli" |
||||
) |
||||
|
||||
const ( |
||||
_getBMGen = "go get 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:." |
||||
) |
||||
|
||||
func installBMGen() error { |
||||
if _, err := exec.LookPath("protoc-gen-bm"); err != nil { |
||||
if err := goget(_getBMGen); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func genBM(ctx *cli.Context) error { |
||||
return generate(ctx, _bmProtoc) |
||||
} |
@ -0,0 +1,25 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"os/exec" |
||||
|
||||
"github.com/urfave/cli" |
||||
) |
||||
|
||||
const ( |
||||
_getGRPCGen = "go get github.com/gogo/protobuf/protoc-gen-gogofast" |
||||
_grpcProtoc = "protoc --proto_path=%s --proto_path=%s --proto_path=%s --gogofast_out=plugins=grpc:." |
||||
) |
||||
|
||||
func installGRPCGen() error { |
||||
if _, err := exec.LookPath("protoc-gen-gogofast"); err != nil { |
||||
if err := goget(_getGRPCGen); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func genGRPC(ctx *cli.Context) error { |
||||
return generate(ctx, _grpcProtoc) |
||||
} |
@ -0,0 +1,37 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"log" |
||||
"os" |
||||
|
||||
"github.com/urfave/cli" |
||||
) |
||||
|
||||
func main() { |
||||
app := cli.NewApp() |
||||
app.Name = "protc" |
||||
app.Usage = "protobuf生成工具" |
||||
app.Flags = []cli.Flag{ |
||||
cli.BoolFlag{ |
||||
Name: "bm", |
||||
Usage: "whether to use BM for generation", |
||||
Destination: &withBM, |
||||
}, |
||||
cli.BoolFlag{ |
||||
Name: "grpc", |
||||
Usage: "whether to use gRPC for generation", |
||||
Destination: &withGRPC, |
||||
}, |
||||
cli.BoolFlag{ |
||||
Name: "swagger", |
||||
Usage: "whether to use swagger for generation", |
||||
Destination: &withSwagger, |
||||
}, |
||||
} |
||||
app.Action = func(c *cli.Context) error { |
||||
return protocAction(c) |
||||
} |
||||
if err := app.Run(os.Args); err != nil { |
||||
log.Fatal(err) |
||||
} |
||||
} |
@ -0,0 +1,160 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
"go/build" |
||||
"io/ioutil" |
||||
"log" |
||||
"os" |
||||
"os/exec" |
||||
"path" |
||||
"path/filepath" |
||||
"runtime" |
||||
"strings" |
||||
|
||||
"github.com/urfave/cli" |
||||
) |
||||
|
||||
var ( |
||||
withBM bool |
||||
withGRPC bool |
||||
withSwagger bool |
||||
) |
||||
|
||||
func protocAction(ctx *cli.Context) (err error) { |
||||
if err = checkProtoc(); err != nil { |
||||
return err |
||||
} |
||||
if !withGRPC && !withBM && !withSwagger { |
||||
withBM = true |
||||
withGRPC = true |
||||
withSwagger = true |
||||
} |
||||
if withBM { |
||||
if err = installBMGen(); err != nil { |
||||
return |
||||
} |
||||
if err = genBM(ctx); err != nil { |
||||
return |
||||
} |
||||
} |
||||
if withGRPC { |
||||
if err = installGRPCGen(); err != nil { |
||||
return err |
||||
} |
||||
if err = genGRPC(ctx); err != nil { |
||||
return |
||||
} |
||||
} |
||||
if withSwagger { |
||||
if err = installSwaggerGen(); err != nil { |
||||
return |
||||
} |
||||
if err = genSwagger(ctx); err != nil { |
||||
return |
||||
} |
||||
} |
||||
log.Printf("generate %v success.\n", ctx.Args()) |
||||
return nil |
||||
} |
||||
|
||||
func checkProtoc() error { |
||||
if _, err := exec.LookPath("protoc"); err != nil { |
||||
switch runtime.GOOS { |
||||
case "darwin": |
||||
fmt.Println("brew install protobuf") |
||||
cmd := exec.Command("brew", "install", "protobuf") |
||||
cmd.Stdout = os.Stdout |
||||
cmd.Stderr = os.Stderr |
||||
if err = cmd.Run(); err != nil { |
||||
return err |
||||
} |
||||
case "linux": |
||||
fmt.Println("snap install --classic protobuf") |
||||
cmd := exec.Command("snap", "install", "--classic", "protobuf") |
||||
cmd.Stdout = os.Stdout |
||||
cmd.Stderr = os.Stderr |
||||
if err = cmd.Run(); err != nil { |
||||
return err |
||||
} |
||||
default: |
||||
return errors.New("您还没安装protobuf,请进行手动安装:https://github.com/protocolbuffers/protobuf/releases") |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func generate(ctx *cli.Context, protoc string) error { |
||||
pwd, _ := os.Getwd() |
||||
gosrc := path.Join(gopath(), "src") |
||||
ext, err := latestKratos() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
line := fmt.Sprintf(protoc, gosrc, ext, pwd) |
||||
log.Println(line, strings.Join(ctx.Args(), " ")) |
||||
args := strings.Split(line, " ") |
||||
args = append(args, ctx.Args()...) |
||||
cmd := exec.Command(args[0], args[1:]...) |
||||
cmd.Dir = pwd |
||||
cmd.Env = os.Environ() |
||||
cmd.Stdout = os.Stdout |
||||
cmd.Stderr = os.Stderr |
||||
if err := cmd.Run(); err != nil { |
||||
return err |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func goget(url string) error { |
||||
args := strings.Split(url, " ") |
||||
cmd := exec.Command(args[0], args[1:]...) |
||||
cmd.Env = os.Environ() |
||||
cmd.Stdout = os.Stdout |
||||
cmd.Stderr = os.Stderr |
||||
log.Println(url) |
||||
return cmd.Run() |
||||
} |
||||
|
||||
func latestKratos() (string, error) { |
||||
gopath := gopath() |
||||
ext := path.Join(gopath, "src/github.com/bilibili/kratos/tool/protobuf/pkg/extensions") |
||||
if _, err := os.Stat(ext); !os.IsNotExist(err) { |
||||
return ext, nil |
||||
} |
||||
ext = path.Join(gopath, "pkg/mod/github.com/bilibili") |
||||
files, err := ioutil.ReadDir(ext) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
if len(files) == 0 { |
||||
return "", errors.New("not found kratos package") |
||||
} |
||||
return path.Join(ext, files[len(files)-1].Name(), "tool/protobuf/pkg/extensions"), nil |
||||
} |
||||
|
||||
func gopath() (gp string) { |
||||
gopaths := strings.Split(os.Getenv("GOPATH"), ":") |
||||
if len(gopaths) == 1 { |
||||
return gopaths[0] |
||||
} |
||||
pwd, err := os.Getwd() |
||||
if err != nil { |
||||
return |
||||
} |
||||
abspwd, err := filepath.Abs(pwd) |
||||
if err != nil { |
||||
return |
||||
} |
||||
for _, gopath := range gopaths { |
||||
absgp, err := filepath.Abs(gopath) |
||||
if err != nil { |
||||
return |
||||
} |
||||
if strings.HasPrefix(abspwd, absgp) { |
||||
return absgp |
||||
} |
||||
} |
||||
return build.Default.GOPATH |
||||
} |
@ -0,0 +1,25 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"os/exec" |
||||
|
||||
"github.com/urfave/cli" |
||||
) |
||||
|
||||
const ( |
||||
_getSwaggerGen = "go get 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:." |
||||
) |
||||
|
||||
func installSwaggerGen() error { |
||||
if _, err := exec.LookPath("protoc-gen-bswagger"); err != nil { |
||||
if err := goget(_getSwaggerGen); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func genSwagger(ctx *cli.Context) error { |
||||
return generate(ctx, _swaggerProtoc) |
||||
} |
@ -0,0 +1,9 @@ |
||||
regenerate: |
||||
go install go-common/vendor/github.com/golang/protobuf/protoc-gen-go
|
||||
protoc --go_out=paths=source_relative:. gogo.proto
|
||||
|
||||
restore: |
||||
cp gogo.pb.golden gogo.pb.go
|
||||
|
||||
preserve: |
||||
cp gogo.pb.go gogo.pb.golden
|
@ -0,0 +1,818 @@ |
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: gogo.proto
|
||||
|
||||
package gogoproto // import "github.com/bilibili/kratos/tool/protobuf/pkg/extensions/gogoproto"
|
||||
|
||||
import proto "github.com/golang/protobuf/proto" |
||||
import fmt "fmt" |
||||
import math "math" |
||||
import descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" |
||||
|
||||
// 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
|
||||
|
||||
var E_GoprotoEnumPrefix = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.EnumOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 62001, |
||||
Name: "gogoproto.goproto_enum_prefix", |
||||
Tag: "varint,62001,opt,name=goproto_enum_prefix,json=goprotoEnumPrefix", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_GoprotoEnumStringer = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.EnumOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 62021, |
||||
Name: "gogoproto.goproto_enum_stringer", |
||||
Tag: "varint,62021,opt,name=goproto_enum_stringer,json=goprotoEnumStringer", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_EnumStringer = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.EnumOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 62022, |
||||
Name: "gogoproto.enum_stringer", |
||||
Tag: "varint,62022,opt,name=enum_stringer,json=enumStringer", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_EnumCustomname = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.EnumOptions)(nil), |
||||
ExtensionType: (*string)(nil), |
||||
Field: 62023, |
||||
Name: "gogoproto.enum_customname", |
||||
Tag: "bytes,62023,opt,name=enum_customname,json=enumCustomname", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Enumdecl = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.EnumOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 62024, |
||||
Name: "gogoproto.enumdecl", |
||||
Tag: "varint,62024,opt,name=enumdecl", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_EnumvalueCustomname = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.EnumValueOptions)(nil), |
||||
ExtensionType: (*string)(nil), |
||||
Field: 66001, |
||||
Name: "gogoproto.enumvalue_customname", |
||||
Tag: "bytes,66001,opt,name=enumvalue_customname,json=enumvalueCustomname", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_GoprotoGettersAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63001, |
||||
Name: "gogoproto.goproto_getters_all", |
||||
Tag: "varint,63001,opt,name=goproto_getters_all,json=goprotoGettersAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_GoprotoEnumPrefixAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63002, |
||||
Name: "gogoproto.goproto_enum_prefix_all", |
||||
Tag: "varint,63002,opt,name=goproto_enum_prefix_all,json=goprotoEnumPrefixAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_GoprotoStringerAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63003, |
||||
Name: "gogoproto.goproto_stringer_all", |
||||
Tag: "varint,63003,opt,name=goproto_stringer_all,json=goprotoStringerAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_VerboseEqualAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63004, |
||||
Name: "gogoproto.verbose_equal_all", |
||||
Tag: "varint,63004,opt,name=verbose_equal_all,json=verboseEqualAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_FaceAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63005, |
||||
Name: "gogoproto.face_all", |
||||
Tag: "varint,63005,opt,name=face_all,json=faceAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_GostringAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63006, |
||||
Name: "gogoproto.gostring_all", |
||||
Tag: "varint,63006,opt,name=gostring_all,json=gostringAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_PopulateAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63007, |
||||
Name: "gogoproto.populate_all", |
||||
Tag: "varint,63007,opt,name=populate_all,json=populateAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_StringerAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63008, |
||||
Name: "gogoproto.stringer_all", |
||||
Tag: "varint,63008,opt,name=stringer_all,json=stringerAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_OnlyoneAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63009, |
||||
Name: "gogoproto.onlyone_all", |
||||
Tag: "varint,63009,opt,name=onlyone_all,json=onlyoneAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_EqualAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63013, |
||||
Name: "gogoproto.equal_all", |
||||
Tag: "varint,63013,opt,name=equal_all,json=equalAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_DescriptionAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63014, |
||||
Name: "gogoproto.description_all", |
||||
Tag: "varint,63014,opt,name=description_all,json=descriptionAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_TestgenAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63015, |
||||
Name: "gogoproto.testgen_all", |
||||
Tag: "varint,63015,opt,name=testgen_all,json=testgenAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_BenchgenAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63016, |
||||
Name: "gogoproto.benchgen_all", |
||||
Tag: "varint,63016,opt,name=benchgen_all,json=benchgenAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_MarshalerAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63017, |
||||
Name: "gogoproto.marshaler_all", |
||||
Tag: "varint,63017,opt,name=marshaler_all,json=marshalerAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_UnmarshalerAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63018, |
||||
Name: "gogoproto.unmarshaler_all", |
||||
Tag: "varint,63018,opt,name=unmarshaler_all,json=unmarshalerAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_StableMarshalerAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63019, |
||||
Name: "gogoproto.stable_marshaler_all", |
||||
Tag: "varint,63019,opt,name=stable_marshaler_all,json=stableMarshalerAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_SizerAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63020, |
||||
Name: "gogoproto.sizer_all", |
||||
Tag: "varint,63020,opt,name=sizer_all,json=sizerAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_GoprotoEnumStringerAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63021, |
||||
Name: "gogoproto.goproto_enum_stringer_all", |
||||
Tag: "varint,63021,opt,name=goproto_enum_stringer_all,json=goprotoEnumStringerAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_EnumStringerAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63022, |
||||
Name: "gogoproto.enum_stringer_all", |
||||
Tag: "varint,63022,opt,name=enum_stringer_all,json=enumStringerAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_UnsafeMarshalerAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63023, |
||||
Name: "gogoproto.unsafe_marshaler_all", |
||||
Tag: "varint,63023,opt,name=unsafe_marshaler_all,json=unsafeMarshalerAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_UnsafeUnmarshalerAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63024, |
||||
Name: "gogoproto.unsafe_unmarshaler_all", |
||||
Tag: "varint,63024,opt,name=unsafe_unmarshaler_all,json=unsafeUnmarshalerAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_GoprotoExtensionsMapAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63025, |
||||
Name: "gogoproto.goproto_extensions_map_all", |
||||
Tag: "varint,63025,opt,name=goproto_extensions_map_all,json=goprotoExtensionsMapAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_GoprotoUnrecognizedAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63026, |
||||
Name: "gogoproto.goproto_unrecognized_all", |
||||
Tag: "varint,63026,opt,name=goproto_unrecognized_all,json=goprotoUnrecognizedAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_GogoprotoImport = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63027, |
||||
Name: "gogoproto.gogoproto_import", |
||||
Tag: "varint,63027,opt,name=gogoproto_import,json=gogoprotoImport", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_ProtosizerAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63028, |
||||
Name: "gogoproto.protosizer_all", |
||||
Tag: "varint,63028,opt,name=protosizer_all,json=protosizerAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_CompareAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63029, |
||||
Name: "gogoproto.compare_all", |
||||
Tag: "varint,63029,opt,name=compare_all,json=compareAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_TypedeclAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63030, |
||||
Name: "gogoproto.typedecl_all", |
||||
Tag: "varint,63030,opt,name=typedecl_all,json=typedeclAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_EnumdeclAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63031, |
||||
Name: "gogoproto.enumdecl_all", |
||||
Tag: "varint,63031,opt,name=enumdecl_all,json=enumdeclAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_GoprotoRegistration = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63032, |
||||
Name: "gogoproto.goproto_registration", |
||||
Tag: "varint,63032,opt,name=goproto_registration,json=goprotoRegistration", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_MessagenameAll = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FileOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 63033, |
||||
Name: "gogoproto.messagename_all", |
||||
Tag: "varint,63033,opt,name=messagename_all,json=messagenameAll", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_GoprotoGetters = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64001, |
||||
Name: "gogoproto.goproto_getters", |
||||
Tag: "varint,64001,opt,name=goproto_getters,json=goprotoGetters", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_GoprotoStringer = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64003, |
||||
Name: "gogoproto.goproto_stringer", |
||||
Tag: "varint,64003,opt,name=goproto_stringer,json=goprotoStringer", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_VerboseEqual = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64004, |
||||
Name: "gogoproto.verbose_equal", |
||||
Tag: "varint,64004,opt,name=verbose_equal,json=verboseEqual", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Face = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64005, |
||||
Name: "gogoproto.face", |
||||
Tag: "varint,64005,opt,name=face", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Gostring = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64006, |
||||
Name: "gogoproto.gostring", |
||||
Tag: "varint,64006,opt,name=gostring", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Populate = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64007, |
||||
Name: "gogoproto.populate", |
||||
Tag: "varint,64007,opt,name=populate", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Stringer = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 67008, |
||||
Name: "gogoproto.stringer", |
||||
Tag: "varint,67008,opt,name=stringer", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Onlyone = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64009, |
||||
Name: "gogoproto.onlyone", |
||||
Tag: "varint,64009,opt,name=onlyone", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Equal = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64013, |
||||
Name: "gogoproto.equal", |
||||
Tag: "varint,64013,opt,name=equal", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Description = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64014, |
||||
Name: "gogoproto.description", |
||||
Tag: "varint,64014,opt,name=description", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Testgen = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64015, |
||||
Name: "gogoproto.testgen", |
||||
Tag: "varint,64015,opt,name=testgen", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Benchgen = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64016, |
||||
Name: "gogoproto.benchgen", |
||||
Tag: "varint,64016,opt,name=benchgen", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Marshaler = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64017, |
||||
Name: "gogoproto.marshaler", |
||||
Tag: "varint,64017,opt,name=marshaler", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Unmarshaler = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64018, |
||||
Name: "gogoproto.unmarshaler", |
||||
Tag: "varint,64018,opt,name=unmarshaler", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_StableMarshaler = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64019, |
||||
Name: "gogoproto.stable_marshaler", |
||||
Tag: "varint,64019,opt,name=stable_marshaler,json=stableMarshaler", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Sizer = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64020, |
||||
Name: "gogoproto.sizer", |
||||
Tag: "varint,64020,opt,name=sizer", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_UnsafeMarshaler = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64023, |
||||
Name: "gogoproto.unsafe_marshaler", |
||||
Tag: "varint,64023,opt,name=unsafe_marshaler,json=unsafeMarshaler", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_UnsafeUnmarshaler = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64024, |
||||
Name: "gogoproto.unsafe_unmarshaler", |
||||
Tag: "varint,64024,opt,name=unsafe_unmarshaler,json=unsafeUnmarshaler", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_GoprotoExtensionsMap = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64025, |
||||
Name: "gogoproto.goproto_extensions_map", |
||||
Tag: "varint,64025,opt,name=goproto_extensions_map,json=goprotoExtensionsMap", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_GoprotoUnrecognized = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64026, |
||||
Name: "gogoproto.goproto_unrecognized", |
||||
Tag: "varint,64026,opt,name=goproto_unrecognized,json=goprotoUnrecognized", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Protosizer = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64028, |
||||
Name: "gogoproto.protosizer", |
||||
Tag: "varint,64028,opt,name=protosizer", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Compare = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64029, |
||||
Name: "gogoproto.compare", |
||||
Tag: "varint,64029,opt,name=compare", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Typedecl = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64030, |
||||
Name: "gogoproto.typedecl", |
||||
Tag: "varint,64030,opt,name=typedecl", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Messagename = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.MessageOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 64033, |
||||
Name: "gogoproto.messagename", |
||||
Tag: "varint,64033,opt,name=messagename", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Nullable = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FieldOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 65001, |
||||
Name: "gogoproto.nullable", |
||||
Tag: "varint,65001,opt,name=nullable", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Embed = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FieldOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 65002, |
||||
Name: "gogoproto.embed", |
||||
Tag: "varint,65002,opt,name=embed", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Customtype = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FieldOptions)(nil), |
||||
ExtensionType: (*string)(nil), |
||||
Field: 65003, |
||||
Name: "gogoproto.customtype", |
||||
Tag: "bytes,65003,opt,name=customtype", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Customname = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FieldOptions)(nil), |
||||
ExtensionType: (*string)(nil), |
||||
Field: 65004, |
||||
Name: "gogoproto.customname", |
||||
Tag: "bytes,65004,opt,name=customname", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Jsontag = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FieldOptions)(nil), |
||||
ExtensionType: (*string)(nil), |
||||
Field: 65005, |
||||
Name: "gogoproto.jsontag", |
||||
Tag: "bytes,65005,opt,name=jsontag", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Moretags = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FieldOptions)(nil), |
||||
ExtensionType: (*string)(nil), |
||||
Field: 65006, |
||||
Name: "gogoproto.moretags", |
||||
Tag: "bytes,65006,opt,name=moretags", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Casttype = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FieldOptions)(nil), |
||||
ExtensionType: (*string)(nil), |
||||
Field: 65007, |
||||
Name: "gogoproto.casttype", |
||||
Tag: "bytes,65007,opt,name=casttype", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Castkey = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FieldOptions)(nil), |
||||
ExtensionType: (*string)(nil), |
||||
Field: 65008, |
||||
Name: "gogoproto.castkey", |
||||
Tag: "bytes,65008,opt,name=castkey", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Castvalue = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FieldOptions)(nil), |
||||
ExtensionType: (*string)(nil), |
||||
Field: 65009, |
||||
Name: "gogoproto.castvalue", |
||||
Tag: "bytes,65009,opt,name=castvalue", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Stdtime = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FieldOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 65010, |
||||
Name: "gogoproto.stdtime", |
||||
Tag: "varint,65010,opt,name=stdtime", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
var E_Stdduration = &proto.ExtensionDesc{ |
||||
ExtendedType: (*descriptor.FieldOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 65011, |
||||
Name: "gogoproto.stdduration", |
||||
Tag: "varint,65011,opt,name=stdduration", |
||||
Filename: "gogo.proto", |
||||
} |
||||
|
||||
func init() { |
||||
proto.RegisterExtension(E_GoprotoEnumPrefix) |
||||
proto.RegisterExtension(E_GoprotoEnumStringer) |
||||
proto.RegisterExtension(E_EnumStringer) |
||||
proto.RegisterExtension(E_EnumCustomname) |
||||
proto.RegisterExtension(E_Enumdecl) |
||||
proto.RegisterExtension(E_EnumvalueCustomname) |
||||
proto.RegisterExtension(E_GoprotoGettersAll) |
||||
proto.RegisterExtension(E_GoprotoEnumPrefixAll) |
||||
proto.RegisterExtension(E_GoprotoStringerAll) |
||||
proto.RegisterExtension(E_VerboseEqualAll) |
||||
proto.RegisterExtension(E_FaceAll) |
||||
proto.RegisterExtension(E_GostringAll) |
||||
proto.RegisterExtension(E_PopulateAll) |
||||
proto.RegisterExtension(E_StringerAll) |
||||
proto.RegisterExtension(E_OnlyoneAll) |
||||
proto.RegisterExtension(E_EqualAll) |
||||
proto.RegisterExtension(E_DescriptionAll) |
||||
proto.RegisterExtension(E_TestgenAll) |
||||
proto.RegisterExtension(E_BenchgenAll) |
||||
proto.RegisterExtension(E_MarshalerAll) |
||||
proto.RegisterExtension(E_UnmarshalerAll) |
||||
proto.RegisterExtension(E_StableMarshalerAll) |
||||
proto.RegisterExtension(E_SizerAll) |
||||
proto.RegisterExtension(E_GoprotoEnumStringerAll) |
||||
proto.RegisterExtension(E_EnumStringerAll) |
||||
proto.RegisterExtension(E_UnsafeMarshalerAll) |
||||
proto.RegisterExtension(E_UnsafeUnmarshalerAll) |
||||
proto.RegisterExtension(E_GoprotoExtensionsMapAll) |
||||
proto.RegisterExtension(E_GoprotoUnrecognizedAll) |
||||
proto.RegisterExtension(E_GogoprotoImport) |
||||
proto.RegisterExtension(E_ProtosizerAll) |
||||
proto.RegisterExtension(E_CompareAll) |
||||
proto.RegisterExtension(E_TypedeclAll) |
||||
proto.RegisterExtension(E_EnumdeclAll) |
||||
proto.RegisterExtension(E_GoprotoRegistration) |
||||
proto.RegisterExtension(E_MessagenameAll) |
||||
proto.RegisterExtension(E_GoprotoGetters) |
||||
proto.RegisterExtension(E_GoprotoStringer) |
||||
proto.RegisterExtension(E_VerboseEqual) |
||||
proto.RegisterExtension(E_Face) |
||||
proto.RegisterExtension(E_Gostring) |
||||
proto.RegisterExtension(E_Populate) |
||||
proto.RegisterExtension(E_Stringer) |
||||
proto.RegisterExtension(E_Onlyone) |
||||
proto.RegisterExtension(E_Equal) |
||||
proto.RegisterExtension(E_Description) |
||||
proto.RegisterExtension(E_Testgen) |
||||
proto.RegisterExtension(E_Benchgen) |
||||
proto.RegisterExtension(E_Marshaler) |
||||
proto.RegisterExtension(E_Unmarshaler) |
||||
proto.RegisterExtension(E_StableMarshaler) |
||||
proto.RegisterExtension(E_Sizer) |
||||
proto.RegisterExtension(E_UnsafeMarshaler) |
||||
proto.RegisterExtension(E_UnsafeUnmarshaler) |
||||
proto.RegisterExtension(E_GoprotoExtensionsMap) |
||||
proto.RegisterExtension(E_GoprotoUnrecognized) |
||||
proto.RegisterExtension(E_Protosizer) |
||||
proto.RegisterExtension(E_Compare) |
||||
proto.RegisterExtension(E_Typedecl) |
||||
proto.RegisterExtension(E_Messagename) |
||||
proto.RegisterExtension(E_Nullable) |
||||
proto.RegisterExtension(E_Embed) |
||||
proto.RegisterExtension(E_Customtype) |
||||
proto.RegisterExtension(E_Customname) |
||||
proto.RegisterExtension(E_Jsontag) |
||||
proto.RegisterExtension(E_Moretags) |
||||
proto.RegisterExtension(E_Casttype) |
||||
proto.RegisterExtension(E_Castkey) |
||||
proto.RegisterExtension(E_Castvalue) |
||||
proto.RegisterExtension(E_Stdtime) |
||||
proto.RegisterExtension(E_Stdduration) |
||||
} |
||||
|
||||
func init() { proto.RegisterFile("gogo.proto", fileDescriptor_gogo_e935c22a8aa82c87) } |
||||
|
||||
var fileDescriptor_gogo_e935c22a8aa82c87 = []byte{ |
||||
// 1260 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x98, 0xc9, 0x6f, 0x1c, 0x45, |
||||
0x17, 0xc0, 0xf5, 0xe9, 0x4b, 0x14, 0xcf, 0xf3, 0x86, 0xc7, 0xc6, 0x84, 0x08, 0x44, 0xb8, 0x71, |
||||
0xc1, 0x73, 0x40, 0x11, 0x4a, 0x59, 0x91, 0xe5, 0x58, 0x8e, 0x15, 0x84, 0xc1, 0x98, 0xd8, 0x6c, |
||||
0x87, 0x51, 0xcf, 0x4c, 0xb9, 0x33, 0xa4, 0xbb, 0xab, 0xe9, 0xae, 0x8e, 0xe2, 0xdc, 0x50, 0x58, |
||||
0x84, 0x10, 0x3b, 0x12, 0x24, 0x24, 0x81, 0x1c, 0xd8, 0xd7, 0xb0, 0x73, 0xe3, 0xc2, 0x72, 0xe5, |
||||
0x7f, 0xe0, 0x02, 0x98, 0xdd, 0x37, 0x5f, 0xd0, 0xeb, 0x7e, 0xaf, 0xa7, 0x66, 0x3c, 0x52, 0xd5, |
||||
0xdc, 0xda, 0x76, 0xfd, 0x7e, 0xae, 0x7e, 0xaf, 0xea, 0xbd, 0x37, 0x03, 0xe0, 0x2b, 0x5f, 0xcd, |
||||
0xc4, 0x89, 0xd2, 0xaa, 0x5a, 0xc1, 0xe7, 0xfc, 0xf1, 0xc0, 0x41, 0x5f, 0x29, 0x3f, 0x90, 0xb5, |
||||
0xfc, 0xa7, 0x46, 0xb6, 0x51, 0x6b, 0xc9, 0xb4, 0x99, 0xb4, 0x63, 0xad, 0x92, 0x62, 0xb1, 0xb8, |
||||
0x0b, 0x26, 0x69, 0x71, 0x5d, 0x46, 0x59, 0x58, 0x8f, 0x13, 0xb9, 0xd1, 0x3e, 0x53, 0xbd, 0x61, |
||||
0xa6, 0x20, 0x67, 0x98, 0x9c, 0x59, 0x8c, 0xb2, 0xf0, 0xee, 0x58, 0xb7, 0x55, 0x94, 0xee, 0xbf, |
||||
0xfa, 0xf3, 0xff, 0x0f, 0xfe, 0xef, 0x96, 0xa1, 0xd5, 0x09, 0x42, 0xf1, 0x6f, 0x2b, 0x39, 0x28, |
||||
0x56, 0xe1, 0xda, 0x2e, 0x5f, 0xaa, 0x93, 0x76, 0xe4, 0xcb, 0xc4, 0x62, 0xfc, 0x8e, 0x8c, 0x93, |
||||
0x86, 0xf1, 0x5e, 0x42, 0xc5, 0x02, 0x8c, 0x0e, 0xe2, 0xfa, 0x9e, 0x5c, 0x23, 0xd2, 0x94, 0x2c, |
||||
0xc1, 0x78, 0x2e, 0x69, 0x66, 0xa9, 0x56, 0x61, 0xe4, 0x85, 0xd2, 0xa2, 0xf9, 0x21, 0xd7, 0x54, |
||||
0x56, 0xc7, 0x10, 0x5b, 0x28, 0x29, 0x21, 0x60, 0x08, 0x7f, 0xd3, 0x92, 0xcd, 0xc0, 0x62, 0xf8, |
||||
0x91, 0x36, 0x52, 0xae, 0x17, 0xeb, 0x30, 0x85, 0xcf, 0xa7, 0xbd, 0x20, 0x93, 0xe6, 0x4e, 0x6e, |
||||
0xee, 0xeb, 0x59, 0xc7, 0x65, 0x2c, 0xfb, 0xe9, 0xdc, 0x9e, 0x7c, 0x3b, 0x93, 0xa5, 0xc0, 0xd8, |
||||
0x93, 0x91, 0x45, 0x5f, 0x6a, 0x2d, 0x93, 0xb4, 0xee, 0x05, 0xfd, 0xb6, 0x77, 0xac, 0x1d, 0x94, |
||||
0xc6, 0xf3, 0x5b, 0xdd, 0x59, 0x5c, 0x2a, 0xc8, 0xf9, 0x20, 0x10, 0x6b, 0x70, 0x5d, 0x9f, 0x53, |
||||
0xe1, 0xe0, 0xbc, 0x40, 0xce, 0xa9, 0x5d, 0x27, 0x03, 0xb5, 0x2b, 0xc0, 0xbf, 0x2f, 0x73, 0xe9, |
||||
0xe0, 0x7c, 0x8d, 0x9c, 0x55, 0x62, 0x39, 0xa5, 0x68, 0xbc, 0x03, 0x26, 0x4e, 0xcb, 0xa4, 0xa1, |
||||
0x52, 0x59, 0x97, 0x8f, 0x64, 0x5e, 0xe0, 0xa0, 0xbb, 0x48, 0xba, 0x71, 0x02, 0x17, 0x91, 0x43, |
||||
0xd7, 0x61, 0x18, 0xda, 0xf0, 0x9a, 0xd2, 0x41, 0x71, 0x89, 0x14, 0xfb, 0x70, 0x3d, 0xa2, 0xf3, |
||||
0x30, 0xe2, 0xab, 0xe2, 0x95, 0x1c, 0xf0, 0xcb, 0x84, 0x0f, 0x33, 0x43, 0x8a, 0x58, 0xc5, 0x59, |
||||
0xe0, 0x69, 0x97, 0x1d, 0xbc, 0xce, 0x0a, 0x66, 0x48, 0x31, 0x40, 0x58, 0xdf, 0x60, 0x45, 0x6a, |
||||
0xc4, 0x73, 0x0e, 0x86, 0x55, 0x14, 0x6c, 0xaa, 0xc8, 0x65, 0x13, 0x57, 0xc8, 0x00, 0x84, 0xa0, |
||||
0x60, 0x16, 0x2a, 0xae, 0x89, 0x78, 0x73, 0x8b, 0xaf, 0x07, 0x67, 0x60, 0x09, 0xc6, 0xb9, 0x40, |
||||
0xb5, 0x55, 0xe4, 0xa0, 0x78, 0x8b, 0x14, 0x63, 0x06, 0x46, 0xaf, 0xa1, 0x65, 0xaa, 0x7d, 0xe9, |
||||
0x22, 0x79, 0x9b, 0x5f, 0x83, 0x10, 0x0a, 0x65, 0x43, 0x46, 0xcd, 0x93, 0x6e, 0x86, 0x77, 0x38, |
||||
0x94, 0xcc, 0xa0, 0x62, 0x01, 0x46, 0x43, 0x2f, 0x49, 0x4f, 0x7a, 0x81, 0x53, 0x3a, 0xde, 0x25, |
||||
0xc7, 0x48, 0x09, 0x51, 0x44, 0xb2, 0x68, 0x10, 0xcd, 0x7b, 0x1c, 0x11, 0x03, 0xa3, 0xab, 0x97, |
||||
0x6a, 0xaf, 0x11, 0xc8, 0xfa, 0x20, 0xb6, 0xf7, 0xf9, 0xea, 0x15, 0xec, 0xb2, 0x69, 0x9c, 0x85, |
||||
0x4a, 0xda, 0x3e, 0xeb, 0xa4, 0xf9, 0x80, 0x33, 0x9d, 0x03, 0x08, 0x3f, 0x00, 0xd7, 0xf7, 0x6d, |
||||
0x13, 0x0e, 0xb2, 0x0f, 0x49, 0x36, 0xdd, 0xa7, 0x55, 0x50, 0x49, 0x18, 0x54, 0xf9, 0x11, 0x97, |
||||
0x04, 0xd9, 0xe3, 0x5a, 0x81, 0xa9, 0x2c, 0x4a, 0xbd, 0x8d, 0xc1, 0xa2, 0xf6, 0x31, 0x47, 0xad, |
||||
0x60, 0xbb, 0xa2, 0x76, 0x02, 0xa6, 0xc9, 0x38, 0x58, 0x5e, 0x3f, 0xe1, 0xc2, 0x5a, 0xd0, 0x6b, |
||||
0xdd, 0xd9, 0x7d, 0x08, 0x0e, 0x94, 0xe1, 0x3c, 0xa3, 0x65, 0x94, 0x22, 0x53, 0x0f, 0xbd, 0xd8, |
||||
0xc1, 0x7c, 0x95, 0xcc, 0x5c, 0xf1, 0x17, 0x4b, 0xc1, 0xb2, 0x17, 0xa3, 0xfc, 0x7e, 0xd8, 0xcf, |
||||
0xf2, 0x2c, 0x4a, 0x64, 0x53, 0xf9, 0x51, 0xfb, 0xac, 0x6c, 0x39, 0xa8, 0x3f, 0xed, 0x49, 0xd5, |
||||
0x9a, 0x81, 0xa3, 0xf9, 0x38, 0x5c, 0x53, 0xce, 0x2a, 0xf5, 0x76, 0x18, 0xab, 0x44, 0x5b, 0x8c, |
||||
0x9f, 0x71, 0xa6, 0x4a, 0xee, 0x78, 0x8e, 0x89, 0x45, 0x18, 0xcb, 0x7f, 0x74, 0x3d, 0x92, 0x9f, |
||||
0x93, 0x68, 0xb4, 0x43, 0x51, 0xe1, 0x68, 0xaa, 0x30, 0xf6, 0x12, 0x97, 0xfa, 0xf7, 0x05, 0x17, |
||||
0x0e, 0x42, 0xa8, 0x70, 0xe8, 0xcd, 0x58, 0x62, 0xb7, 0x77, 0x30, 0x7c, 0xc9, 0x85, 0x83, 0x19, |
||||
0x52, 0xf0, 0xc0, 0xe0, 0xa0, 0xf8, 0x8a, 0x15, 0xcc, 0xa0, 0xe2, 0x9e, 0x4e, 0xa3, 0x4d, 0xa4, |
||||
0xdf, 0x4e, 0x75, 0xe2, 0xe1, 0x6a, 0x8b, 0xea, 0xeb, 0xad, 0xee, 0x21, 0x6c, 0xd5, 0x40, 0xb1, |
||||
0x12, 0x85, 0x32, 0x4d, 0x3d, 0x5f, 0xe2, 0xc4, 0xe1, 0xb0, 0xb1, 0x6f, 0xb8, 0x12, 0x19, 0x58, |
||||
0x71, 0x3f, 0xc7, 0x7b, 0x66, 0x95, 0xea, 0x4d, 0xbb, 0x44, 0xcb, 0x05, 0xc3, 0xae, 0x47, 0xb7, |
||||
0xc9, 0xd5, 0x3d, 0xaa, 0x88, 0x3b, 0xf1, 0x00, 0x75, 0x0f, 0x14, 0x76, 0xd9, 0xb9, 0xed, 0xf2, |
||||
0x0c, 0x75, 0xcd, 0x13, 0xe2, 0x18, 0x8c, 0x76, 0x0d, 0x13, 0x76, 0xd5, 0x63, 0xa4, 0x1a, 0x31, |
||||
0x67, 0x09, 0x71, 0x08, 0xf6, 0xe0, 0x60, 0x60, 0xc7, 0x1f, 0x27, 0x3c, 0x5f, 0x2e, 0x8e, 0xc0, |
||||
0x10, 0x0f, 0x04, 0x76, 0xf4, 0x09, 0x42, 0x4b, 0x04, 0x71, 0x1e, 0x06, 0xec, 0xf8, 0x93, 0x8c, |
||||
0x33, 0x82, 0xb8, 0x7b, 0x08, 0xbf, 0x7d, 0x7a, 0x0f, 0x15, 0x74, 0x8e, 0xdd, 0x2c, 0xec, 0xa3, |
||||
0x29, 0xc0, 0x4e, 0x3f, 0x45, 0xff, 0x9c, 0x09, 0x71, 0x3b, 0xec, 0x75, 0x0c, 0xf8, 0x33, 0x84, |
||||
0x16, 0xeb, 0xc5, 0x02, 0x0c, 0x1b, 0x9d, 0xdf, 0x8e, 0x3f, 0x4b, 0xb8, 0x49, 0xe1, 0xd6, 0xa9, |
||||
0xf3, 0xdb, 0x05, 0xcf, 0xf1, 0xd6, 0x89, 0xc0, 0xb0, 0x71, 0xd3, 0xb7, 0xd3, 0xcf, 0x73, 0xd4, |
||||
0x19, 0x11, 0x73, 0x50, 0x29, 0x0b, 0xb9, 0x9d, 0x7f, 0x81, 0xf8, 0x0e, 0x83, 0x11, 0x30, 0x1a, |
||||
0x89, 0x5d, 0xf1, 0x22, 0x47, 0xc0, 0xa0, 0xf0, 0x1a, 0xf5, 0x0e, 0x07, 0x76, 0xd3, 0x4b, 0x7c, |
||||
0x8d, 0x7a, 0x66, 0x03, 0xcc, 0x66, 0x5e, 0x4f, 0xed, 0x8a, 0x97, 0x39, 0x9b, 0xf9, 0x7a, 0xdc, |
||||
0x46, 0x6f, 0xb7, 0xb5, 0x3b, 0x5e, 0xe1, 0x6d, 0xf4, 0x34, 0x5b, 0xb1, 0x02, 0xd5, 0xdd, 0x9d, |
||||
0xd6, 0xee, 0x7b, 0x95, 0x7c, 0x13, 0xbb, 0x1a, 0xad, 0xb8, 0x0f, 0xa6, 0xfb, 0x77, 0x59, 0xbb, |
||||
0xf5, 0xfc, 0x76, 0xcf, 0xe7, 0x22, 0xb3, 0xc9, 0x8a, 0x13, 0x9d, 0x72, 0x6d, 0x76, 0x58, 0xbb, |
||||
0xf6, 0xc2, 0x76, 0x77, 0xc5, 0x36, 0x1b, 0xac, 0x98, 0x07, 0xe8, 0x34, 0x37, 0xbb, 0xeb, 0x22, |
||||
0xb9, 0x0c, 0x08, 0xaf, 0x06, 0xf5, 0x36, 0x3b, 0x7f, 0x89, 0xaf, 0x06, 0x11, 0x78, 0x35, 0xb8, |
||||
0xad, 0xd9, 0xe9, 0xcb, 0x7c, 0x35, 0x18, 0xc1, 0x93, 0x6d, 0x74, 0x0e, 0xbb, 0xe1, 0x0a, 0x9f, |
||||
0x6c, 0x83, 0x12, 0xb3, 0x30, 0x14, 0x65, 0x41, 0x80, 0x07, 0xb4, 0x7a, 0x63, 0x9f, 0x76, 0x25, |
||||
0x83, 0x16, 0xf3, 0xbf, 0xec, 0xd0, 0x0e, 0x18, 0x10, 0x87, 0x60, 0xaf, 0x0c, 0x1b, 0xb2, 0x65, |
||||
0x23, 0x7f, 0xdd, 0xe1, 0xa2, 0x84, 0xab, 0xc5, 0x1c, 0x40, 0xf1, 0xd1, 0x1e, 0x5f, 0xc5, 0xc6, |
||||
0xfe, 0xb6, 0x53, 0x7c, 0xcb, 0x60, 0x20, 0x1d, 0x41, 0xfe, 0xe2, 0x16, 0xc1, 0x56, 0xb7, 0x20, |
||||
0x7f, 0xeb, 0xc3, 0xb0, 0xef, 0xe1, 0x54, 0x45, 0xda, 0xf3, 0x6d, 0xf4, 0xef, 0x44, 0xf3, 0x7a, |
||||
0x0c, 0x58, 0xa8, 0x12, 0xa9, 0x3d, 0x3f, 0xb5, 0xb1, 0x7f, 0x10, 0x5b, 0x02, 0x08, 0x37, 0xbd, |
||||
0x54, 0xbb, 0xbc, 0xf7, 0x9f, 0x0c, 0x33, 0x80, 0x9b, 0xc6, 0xe7, 0x53, 0x72, 0xd3, 0xc6, 0xfe, |
||||
0xc5, 0x9b, 0xa6, 0xf5, 0xe2, 0x08, 0x54, 0xf0, 0x31, 0xff, 0x56, 0xc4, 0x06, 0xff, 0x4d, 0x70, |
||||
0x87, 0xc0, 0xff, 0x9c, 0xea, 0x96, 0x6e, 0xdb, 0x83, 0xfd, 0x0f, 0x65, 0x9a, 0xd7, 0x8b, 0x79, |
||||
0x18, 0x4e, 0x75, 0xab, 0x95, 0xd1, 0x7c, 0x65, 0xc1, 0xff, 0xdd, 0x29, 0x3f, 0x72, 0x97, 0xcc, |
||||
0xd1, 0x75, 0x98, 0x6c, 0xaa, 0xb0, 0x17, 0x3c, 0x0a, 0x4b, 0x6a, 0x49, 0xad, 0xe4, 0x57, 0xf1, |
||||
0xc1, 0xdb, 0x7c, 0x75, 0x6b, 0x53, 0x85, 0xa1, 0x8a, 0x6a, 0x5e, 0x1c, 0xd7, 0xb4, 0x52, 0x41, |
||||
0xad, 0x11, 0xe6, 0x4b, 0x6b, 0xf1, 0x29, 0xbf, 0xd6, 0xa9, 0x46, 0xb5, 0x72, 0x2e, 0xfe, 0x2f, |
||||
0x00, 0x00, 0xff, 0xff, 0x97, 0xb1, 0x98, 0x88, 0x13, 0x14, 0x00, 0x00, |
||||
} |
@ -0,0 +1,45 @@ |
||||
// Code generated by protoc-gen-go. |
||||
// source: gogo.proto |
||||
// DO NOT EDIT! |
||||
|
||||
package gogoproto |
||||
|
||||
import proto "github.com/gogo/protobuf/proto" |
||||
import json "encoding/json" |
||||
import math "math" |
||||
import google_protobuf "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" |
||||
|
||||
// Reference proto, json, and math imports to suppress error if they are not otherwise used. |
||||
var _ = proto.Marshal |
||||
var _ = &json.SyntaxError{} |
||||
var _ = math.Inf |
||||
|
||||
var E_Nullable = &proto.ExtensionDesc{ |
||||
ExtendedType: (*google_protobuf.FieldOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 51235, |
||||
Name: "gogoproto.nullable", |
||||
Tag: "varint,51235,opt,name=nullable", |
||||
} |
||||
|
||||
var E_Embed = &proto.ExtensionDesc{ |
||||
ExtendedType: (*google_protobuf.FieldOptions)(nil), |
||||
ExtensionType: (*bool)(nil), |
||||
Field: 51236, |
||||
Name: "gogoproto.embed", |
||||
Tag: "varint,51236,opt,name=embed", |
||||
} |
||||
|
||||
var E_Customtype = &proto.ExtensionDesc{ |
||||
ExtendedType: (*google_protobuf.FieldOptions)(nil), |
||||
ExtensionType: (*string)(nil), |
||||
Field: 51237, |
||||
Name: "gogoproto.customtype", |
||||
Tag: "bytes,51237,opt,name=customtype", |
||||
} |
||||
|
||||
func init() { |
||||
proto.RegisterExtension(E_Nullable) |
||||
proto.RegisterExtension(E_Embed) |
||||
proto.RegisterExtension(E_Customtype) |
||||
} |
@ -0,0 +1,136 @@ |
||||
// Protocol Buffers for Go with Gadgets |
||||
// |
||||
// Copyright (c) 2013, The GoGo Authors. All rights reserved. |
||||
// http://github.com/gogo/protobuf |
||||
// |
||||
// Redistribution and use in source and binary forms, with or without |
||||
// modification, are permitted provided that the following conditions are |
||||
// met: |
||||
// |
||||
// * Redistributions of source code must retain the above copyright |
||||
// notice, this list of conditions and the following disclaimer. |
||||
// * Redistributions in binary form must reproduce the above |
||||
// copyright notice, this list of conditions and the following disclaimer |
||||
// in the documentation and/or other materials provided with the |
||||
// distribution. |
||||
// |
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
syntax = "proto2"; |
||||
package gogoproto; |
||||
|
||||
import "google/protobuf/descriptor.proto"; |
||||
|
||||
option java_package = "com.google.protobuf"; |
||||
option java_outer_classname = "GoGoProtos"; |
||||
option go_package = "github.com/bilibili/kratos/tool/protobuf/pkg/extensions/gogoproto"; |
||||
|
||||
extend google.protobuf.EnumOptions { |
||||
optional bool goproto_enum_prefix = 62001; |
||||
optional bool goproto_enum_stringer = 62021; |
||||
optional bool enum_stringer = 62022; |
||||
optional string enum_customname = 62023; |
||||
optional bool enumdecl = 62024; |
||||
} |
||||
|
||||
extend google.protobuf.EnumValueOptions { |
||||
optional string enumvalue_customname = 66001; |
||||
} |
||||
|
||||
extend google.protobuf.FileOptions { |
||||
optional bool goproto_getters_all = 63001; |
||||
optional bool goproto_enum_prefix_all = 63002; |
||||
optional bool goproto_stringer_all = 63003; |
||||
optional bool verbose_equal_all = 63004; |
||||
optional bool face_all = 63005; |
||||
optional bool gostring_all = 63006; |
||||
optional bool populate_all = 63007; |
||||
optional bool stringer_all = 63008; |
||||
optional bool onlyone_all = 63009; |
||||
|
||||
optional bool equal_all = 63013; |
||||
optional bool description_all = 63014; |
||||
optional bool testgen_all = 63015; |
||||
optional bool benchgen_all = 63016; |
||||
optional bool marshaler_all = 63017; |
||||
optional bool unmarshaler_all = 63018; |
||||
optional bool stable_marshaler_all = 63019; |
||||
|
||||
optional bool sizer_all = 63020; |
||||
|
||||
optional bool goproto_enum_stringer_all = 63021; |
||||
optional bool enum_stringer_all = 63022; |
||||
|
||||
optional bool unsafe_marshaler_all = 63023; |
||||
optional bool unsafe_unmarshaler_all = 63024; |
||||
|
||||
optional bool goproto_extensions_map_all = 63025; |
||||
optional bool goproto_unrecognized_all = 63026; |
||||
optional bool gogoproto_import = 63027; |
||||
optional bool protosizer_all = 63028; |
||||
optional bool compare_all = 63029; |
||||
optional bool typedecl_all = 63030; |
||||
optional bool enumdecl_all = 63031; |
||||
|
||||
optional bool goproto_registration = 63032; |
||||
optional bool messagename_all = 63033; |
||||
} |
||||
|
||||
extend google.protobuf.MessageOptions { |
||||
optional bool goproto_getters = 64001; |
||||
optional bool goproto_stringer = 64003; |
||||
optional bool verbose_equal = 64004; |
||||
optional bool face = 64005; |
||||
optional bool gostring = 64006; |
||||
optional bool populate = 64007; |
||||
optional bool stringer = 67008; |
||||
optional bool onlyone = 64009; |
||||
|
||||
optional bool equal = 64013; |
||||
optional bool description = 64014; |
||||
optional bool testgen = 64015; |
||||
optional bool benchgen = 64016; |
||||
optional bool marshaler = 64017; |
||||
optional bool unmarshaler = 64018; |
||||
optional bool stable_marshaler = 64019; |
||||
|
||||
optional bool sizer = 64020; |
||||
|
||||
optional bool unsafe_marshaler = 64023; |
||||
optional bool unsafe_unmarshaler = 64024; |
||||
|
||||
optional bool goproto_extensions_map = 64025; |
||||
optional bool goproto_unrecognized = 64026; |
||||
|
||||
optional bool protosizer = 64028; |
||||
optional bool compare = 64029; |
||||
|
||||
optional bool typedecl = 64030; |
||||
|
||||
optional bool messagename = 64033; |
||||
} |
||||
|
||||
extend google.protobuf.FieldOptions { |
||||
optional bool nullable = 65001; |
||||
optional bool embed = 65002; |
||||
optional string customtype = 65003; |
||||
optional string customname = 65004; |
||||
optional string jsontag = 65005; |
||||
optional string moretags = 65006; |
||||
optional string casttype = 65007; |
||||
optional string castkey = 65008; |
||||
optional string castvalue = 65009; |
||||
|
||||
optional bool stdtime = 65010; |
||||
optional bool stdduration = 65011; |
||||
} |
@ -0,0 +1,31 @@ |
||||
// Copyright (c) 2015, Google Inc. |
||||
// |
||||
// Licensed under the Apache License, Version 2.0 (the "License"); |
||||
// you may not use this file except in compliance with the License. |
||||
// You may obtain a copy of the License at |
||||
// |
||||
// http://www.apache.org/licenses/LICENSE-2.0 |
||||
// |
||||
// Unless required by applicable law or agreed to in writing, software |
||||
// distributed under the License is distributed on an "AS IS" BASIS, |
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
// See the License for the specific language governing permissions and |
||||
// limitations under the License. |
||||
|
||||
syntax = "proto3"; |
||||
|
||||
package google.api; |
||||
|
||||
import "google/api/http.proto"; |
||||
import "google/protobuf/descriptor.proto"; |
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; |
||||
option java_multiple_files = true; |
||||
option java_outer_classname = "AnnotationsProto"; |
||||
option java_package = "com.google.api"; |
||||
option objc_class_prefix = "GAPI"; |
||||
|
||||
extend google.protobuf.MethodOptions { |
||||
// See `HttpRule`. |
||||
HttpRule http = 72295728; |
||||
} |
@ -0,0 +1,318 @@ |
||||
// Copyright 2018 Google LLC |
||||
// |
||||
// Licensed under the Apache License, Version 2.0 (the "License"); |
||||
// you may not use this file except in compliance with the License. |
||||
// You may obtain a copy of the License at |
||||
// |
||||
// http://www.apache.org/licenses/LICENSE-2.0 |
||||
// |
||||
// Unless required by applicable law or agreed to in writing, software |
||||
// distributed under the License is distributed on an "AS IS" BASIS, |
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
// See the License for the specific language governing permissions and |
||||
// limitations under the License. |
||||
|
||||
syntax = "proto3"; |
||||
|
||||
package google.api; |
||||
|
||||
option cc_enable_arenas = true; |
||||
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; |
||||
option java_multiple_files = true; |
||||
option java_outer_classname = "HttpProto"; |
||||
option java_package = "com.google.api"; |
||||
option objc_class_prefix = "GAPI"; |
||||
|
||||
|
||||
// Defines the HTTP configuration for an API service. It contains a list of |
||||
// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method |
||||
// to one or more HTTP REST API methods. |
||||
message Http { |
||||
// A list of HTTP configuration rules that apply to individual API methods. |
||||
// |
||||
// **NOTE:** All service configuration rules follow "last one wins" order. |
||||
repeated HttpRule rules = 1; |
||||
|
||||
// When set to true, URL path parmeters will be fully URI-decoded except in |
||||
// cases of single segment matches in reserved expansion, where "%2F" will be |
||||
// left encoded. |
||||
// |
||||
// The default behavior is to not decode RFC 6570 reserved characters in multi |
||||
// segment matches. |
||||
bool fully_decode_reserved_expansion = 2; |
||||
} |
||||
|
||||
// `HttpRule` defines the mapping of an RPC method to one or more HTTP |
||||
// REST API methods. The mapping specifies how different portions of the RPC |
||||
// request message are mapped to URL path, URL query parameters, and |
||||
// HTTP request body. The mapping is typically specified as an |
||||
// `google.api.http` annotation on the RPC method, |
||||
// see "google/api/annotations.proto" for details. |
||||
// |
||||
// The mapping consists of a field specifying the path template and |
||||
// method kind. The path template can refer to fields in the request |
||||
// message, as in the example below which describes a REST GET |
||||
// operation on a resource collection of messages: |
||||
// |
||||
// |
||||
// service Messaging { |
||||
// rpc GetMessage(GetMessageRequest) returns (Message) { |
||||
// option (google.api.http).get = "/v1/messages/{message_id}/{sub.subfield}"; |
||||
// } |
||||
// } |
||||
// message GetMessageRequest { |
||||
// message SubMessage { |
||||
// string subfield = 1; |
||||
// } |
||||
// string message_id = 1; // mapped to the URL |
||||
// SubMessage sub = 2; // `sub.subfield` is url-mapped |
||||
// } |
||||
// message Message { |
||||
// string text = 1; // content of the resource |
||||
// } |
||||
// |
||||
// The same http annotation can alternatively be expressed inside the |
||||
// `GRPC API Configuration` YAML file. |
||||
// |
||||
// http: |
||||
// rules: |
||||
// - selector: <proto_package_name>.Messaging.GetMessage |
||||
// get: /v1/messages/{message_id}/{sub.subfield} |
||||
// |
||||
// This definition enables an automatic, bidrectional mapping of HTTP |
||||
// JSON to RPC. Example: |
||||
// |
||||
// HTTP | RPC |
||||
// -----|----- |
||||
// `GET /v1/messages/123456/foo` | `GetMessage(message_id: "123456" sub: SubMessage(subfield: "foo"))` |
||||
// |
||||
// In general, not only fields but also field paths can be referenced |
||||
// from a path pattern. Fields mapped to the path pattern cannot be |
||||
// repeated and must have a primitive (non-message) type. |
||||
// |
||||
// Any fields in the request message which are not bound by the path |
||||
// pattern automatically become (optional) HTTP query |
||||
// parameters. Assume the following definition of the request message: |
||||
// |
||||
// |
||||
// service Messaging { |
||||
// rpc GetMessage(GetMessageRequest) returns (Message) { |
||||
// option (google.api.http).get = "/v1/messages/{message_id}"; |
||||
// } |
||||
// } |
||||
// message GetMessageRequest { |
||||
// message SubMessage { |
||||
// string subfield = 1; |
||||
// } |
||||
// string message_id = 1; // mapped to the URL |
||||
// int64 revision = 2; // becomes a parameter |
||||
// SubMessage sub = 3; // `sub.subfield` becomes a parameter |
||||
// } |
||||
// |
||||
// |
||||
// This enables a HTTP JSON to RPC mapping as below: |
||||
// |
||||
// HTTP | RPC |
||||
// -----|----- |
||||
// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: "foo"))` |
||||
// |
||||
// Note that fields which are mapped to HTTP parameters must have a |
||||
// primitive type or a repeated primitive type. Message types are not |
||||
// allowed. In the case of a repeated type, the parameter can be |
||||
// repeated in the URL, as in `...?param=A¶m=B`. |
||||
// |
||||
// For HTTP method kinds which allow a request body, the `body` field |
||||
// specifies the mapping. Consider a REST update method on the |
||||
// message resource collection: |
||||
// |
||||
// |
||||
// service Messaging { |
||||
// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { |
||||
// option (google.api.http) = { |
||||
// put: "/v1/messages/{message_id}" |
||||
// body: "message" |
||||
// }; |
||||
// } |
||||
// } |
||||
// message UpdateMessageRequest { |
||||
// string message_id = 1; // mapped to the URL |
||||
// Message message = 2; // mapped to the body |
||||
// } |
||||
// |
||||
// |
||||
// The following HTTP JSON to RPC mapping is enabled, where the |
||||
// representation of the JSON in the request body is determined by |
||||
// protos JSON encoding: |
||||
// |
||||
// HTTP | RPC |
||||
// -----|----- |
||||
// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" message { text: "Hi!" })` |
||||
// |
||||
// The special name `*` can be used in the body mapping to define that |
||||
// every field not bound by the path template should be mapped to the |
||||
// request body. This enables the following alternative definition of |
||||
// the update method: |
||||
// |
||||
// service Messaging { |
||||
// rpc UpdateMessage(Message) returns (Message) { |
||||
// option (google.api.http) = { |
||||
// put: "/v1/messages/{message_id}" |
||||
// body: "*" |
||||
// }; |
||||
// } |
||||
// } |
||||
// message Message { |
||||
// string message_id = 1; |
||||
// string text = 2; |
||||
// } |
||||
// |
||||
// |
||||
// The following HTTP JSON to RPC mapping is enabled: |
||||
// |
||||
// HTTP | RPC |
||||
// -----|----- |
||||
// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" text: "Hi!")` |
||||
// |
||||
// Note that when using `*` in the body mapping, it is not possible to |
||||
// have HTTP parameters, as all fields not bound by the path end in |
||||
// the body. This makes this option more rarely used in practice of |
||||
// defining REST APIs. The common usage of `*` is in custom methods |
||||
// which don't use the URL at all for transferring data. |
||||
// |
||||
// It is possible to define multiple HTTP methods for one RPC by using |
||||
// the `additional_bindings` option. Example: |
||||
// |
||||
// service Messaging { |
||||
// rpc GetMessage(GetMessageRequest) returns (Message) { |
||||
// option (google.api.http) = { |
||||
// get: "/v1/messages/{message_id}" |
||||
// additional_bindings { |
||||
// get: "/v1/users/{user_id}/messages/{message_id}" |
||||
// } |
||||
// }; |
||||
// } |
||||
// } |
||||
// message GetMessageRequest { |
||||
// string message_id = 1; |
||||
// string user_id = 2; |
||||
// } |
||||
// |
||||
// |
||||
// This enables the following two alternative HTTP JSON to RPC |
||||
// mappings: |
||||
// |
||||
// HTTP | RPC |
||||
// -----|----- |
||||
// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` |
||||
// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: "123456")` |
||||
// |
||||
// # Rules for HTTP mapping |
||||
// |
||||
// The rules for mapping HTTP path, query parameters, and body fields |
||||
// to the request message are as follows: |
||||
// |
||||
// 1. The `body` field specifies either `*` or a field path, or is |
||||
// omitted. If omitted, it indicates there is no HTTP request body. |
||||
// 2. Leaf fields (recursive expansion of nested messages in the |
||||
// request) can be classified into three types: |
||||
// (a) Matched in the URL template. |
||||
// (b) Covered by body (if body is `*`, everything except (a) fields; |
||||
// else everything under the body field) |
||||
// (c) All other fields. |
||||
// 3. URL query parameters found in the HTTP request are mapped to (c) fields. |
||||
// 4. Any body sent with an HTTP request can contain only (b) fields. |
||||
// |
||||
// The syntax of the path template is as follows: |
||||
// |
||||
// Template = "/" Segments [ Verb ] ; |
||||
// Segments = Segment { "/" Segment } ; |
||||
// Segment = "*" | "**" | LITERAL | Variable ; |
||||
// Variable = "{" FieldPath [ "=" Segments ] "}" ; |
||||
// FieldPath = IDENT { "." IDENT } ; |
||||
// Verb = ":" LITERAL ; |
||||
// |
||||
// The syntax `*` matches a single path segment. The syntax `**` matches zero |
||||
// or more path segments, which must be the last part of the path except the |
||||
// `Verb`. The syntax `LITERAL` matches literal text in the path. |
||||
// |
||||
// The syntax `Variable` matches part of the URL path as specified by its |
||||
// template. A variable template must not contain other variables. If a variable |
||||
// matches a single path segment, its template may be omitted, e.g. `{var}` |
||||
// is equivalent to `{var=*}`. |
||||
// |
||||
// If a variable contains exactly one path segment, such as `"{var}"` or |
||||
// `"{var=*}"`, when such a variable is expanded into a URL path, all characters |
||||
// except `[-_.~0-9a-zA-Z]` are percent-encoded. Such variables show up in the |
||||
// Discovery Document as `{var}`. |
||||
// |
||||
// If a variable contains one or more path segments, such as `"{var=foo/*}"` |
||||
// or `"{var=**}"`, when such a variable is expanded into a URL path, all |
||||
// characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. Such variables |
||||
// show up in the Discovery Document as `{+var}`. |
||||
// |
||||
// NOTE: While the single segment variable matches the semantics of |
||||
// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 |
||||
// Simple String Expansion, the multi segment variable **does not** match |
||||
// RFC 6570 Reserved Expansion. The reason is that the Reserved Expansion |
||||
// does not expand special characters like `?` and `#`, which would lead |
||||
// to invalid URLs. |
||||
// |
||||
// NOTE: the field paths in variables and in the `body` must not refer to |
||||
// repeated fields or map fields. |
||||
message HttpRule { |
||||
// Selects methods to which this rule applies. |
||||
// |
||||
// Refer to [selector][google.api.DocumentationRule.selector] for syntax details. |
||||
string selector = 1; |
||||
|
||||
// Determines the URL pattern is matched by this rules. This pattern can be |
||||
// used with any of the {get|put|post|delete|patch} methods. A custom method |
||||
// can be defined using the 'custom' field. |
||||
oneof pattern { |
||||
// Used for listing and getting information about resources. |
||||
string get = 2; |
||||
|
||||
// Used for updating a resource. |
||||
string put = 3; |
||||
|
||||
// Used for creating a resource. |
||||
string post = 4; |
||||
|
||||
// Used for deleting a resource. |
||||
string delete = 5; |
||||
|
||||
// Used for updating a resource. |
||||
string patch = 6; |
||||
|
||||
// The custom pattern is used for specifying an HTTP method that is not |
||||
// included in the `pattern` field, such as HEAD, or "*" to leave the |
||||
// HTTP method unspecified for this rule. The wild-card rule is useful |
||||
// for services that provide content to Web (HTML) clients. |
||||
CustomHttpPattern custom = 8; |
||||
} |
||||
|
||||
// The name of the request field whose value is mapped to the HTTP body, or |
||||
// `*` for mapping all fields not captured by the path pattern to the HTTP |
||||
// body. NOTE: the referred field must not be a repeated field and must be |
||||
// present at the top-level of request message type. |
||||
string body = 7; |
||||
|
||||
// Optional. The name of the response field whose value is mapped to the HTTP |
||||
// body of response. Other response fields are ignored. When |
||||
// not set, the response message will be used as HTTP body of response. |
||||
string response_body = 12; |
||||
|
||||
// Additional HTTP bindings for the selector. Nested bindings must |
||||
// not contain an `additional_bindings` field themselves (that is, |
||||
// the nesting may only be one level deep). |
||||
repeated HttpRule additional_bindings = 11; |
||||
} |
||||
|
||||
// A custom pattern is used for defining custom HTTP verb. |
||||
message CustomHttpPattern { |
||||
// The name of this custom HTTP verb. |
||||
string kind = 1; |
||||
|
||||
// The path matched by this custom verb. |
||||
string path = 2; |
||||
} |
@ -0,0 +1,94 @@ |
||||
package gen |
||||
|
||||
import ( |
||||
"io" |
||||
"io/ioutil" |
||||
"os" |
||||
"strings" |
||||
"log" |
||||
|
||||
"github.com/golang/protobuf/proto" |
||||
"github.com/golang/protobuf/protoc-gen-go/descriptor" |
||||
plugin "github.com/golang/protobuf/protoc-gen-go/plugin" |
||||
) |
||||
|
||||
// Generator ...
|
||||
type Generator interface { |
||||
Generate(in *plugin.CodeGeneratorRequest) *plugin.CodeGeneratorResponse |
||||
} |
||||
|
||||
// Main ...
|
||||
func Main(g Generator) { |
||||
req := readGenRequest() |
||||
resp := g.Generate(req) |
||||
writeResponse(os.Stdout, resp) |
||||
} |
||||
|
||||
// FilesToGenerate ...
|
||||
func FilesToGenerate(req *plugin.CodeGeneratorRequest) []*descriptor.FileDescriptorProto { |
||||
genFiles := make([]*descriptor.FileDescriptorProto, 0) |
||||
Outer: |
||||
for _, name := range req.FileToGenerate { |
||||
for _, f := range req.ProtoFile { |
||||
if f.GetName() == name { |
||||
genFiles = append(genFiles, f) |
||||
continue Outer |
||||
} |
||||
} |
||||
Fail("could not find file named", name) |
||||
} |
||||
|
||||
return genFiles |
||||
} |
||||
|
||||
func readGenRequest() *plugin.CodeGeneratorRequest { |
||||
data, err := ioutil.ReadAll(os.Stdin) |
||||
if err != nil { |
||||
Error(err, "reading input") |
||||
} |
||||
|
||||
req := new(plugin.CodeGeneratorRequest) |
||||
if err = proto.Unmarshal(data, req); err != nil { |
||||
Error(err, "parsing input proto") |
||||
} |
||||
|
||||
if len(req.FileToGenerate) == 0 { |
||||
Fail("no files to generate") |
||||
} |
||||
|
||||
return req |
||||
} |
||||
|
||||
func writeResponse(w io.Writer, resp *plugin.CodeGeneratorResponse) { |
||||
data, err := proto.Marshal(resp) |
||||
if err != nil { |
||||
Error(err, "marshaling response") |
||||
} |
||||
_, err = w.Write(data) |
||||
if err != nil { |
||||
Error(err, "writing response") |
||||
} |
||||
} |
||||
|
||||
|
||||
// Fail log and exit
|
||||
func Fail(msgs ...string) { |
||||
s := strings.Join(msgs, " ") |
||||
log.Print("error:", s) |
||||
os.Exit(1) |
||||
} |
||||
|
||||
// Fail log and exit
|
||||
func Info(msgs ...string) { |
||||
s := strings.Join(msgs, " ") |
||||
log.Print("info:", s) |
||||
os.Exit(1) |
||||
} |
||||
|
||||
|
||||
// Error log and exit
|
||||
func Error(err error, msgs ...string) { |
||||
s := strings.Join(msgs, " ") + ":" + err.Error() |
||||
log.Print("error:", s) |
||||
os.Exit(1) |
||||
} |
@ -0,0 +1,71 @@ |
||||
package generator |
||||
|
||||
import ( |
||||
"fmt" |
||||
"strings" |
||||
) |
||||
|
||||
type ParamsBase struct { |
||||
ImportPrefix string // String to prefix to imported package file names.
|
||||
ImportMap map[string]string // Mapping from .proto file name to import path.
|
||||
//Tpl bool // generate service implementation template
|
||||
ExplicitHTTP bool // Only generate for method that add http option
|
||||
} |
||||
|
||||
type GeneratorParamsInterface interface { |
||||
GetBase() *ParamsBase |
||||
SetParam(key string, value string) error |
||||
} |
||||
|
||||
type BasicParam struct{ ParamsBase } |
||||
|
||||
func (b *BasicParam) GetBase() *ParamsBase { |
||||
return &b.ParamsBase |
||||
} |
||||
func (b *BasicParam) SetParam(key string, value string) error { |
||||
return nil |
||||
} |
||||
|
||||
func ParseGeneratorParams(parameter string, result GeneratorParamsInterface) error { |
||||
ps := make(map[string]string) |
||||
for _, p := range strings.Split(parameter, ",") { |
||||
if p == "" { |
||||
continue |
||||
} |
||||
i := strings.Index(p, "=") |
||||
if i < 0 { |
||||
return fmt.Errorf("invalid parameter %q: expected format of parameter to be k=v", p) |
||||
} |
||||
k := p[0:i] |
||||
v := p[i+1:] |
||||
if v == "" { |
||||
return fmt.Errorf("invalid parameter %q: expected format of parameter to be k=v", k) |
||||
} |
||||
ps[k] = v |
||||
} |
||||
|
||||
if result.GetBase().ImportMap == nil { |
||||
result.GetBase().ImportMap = map[string]string{} |
||||
} |
||||
for k, v := range ps { |
||||
switch { |
||||
case k == "explicit_http": |
||||
if v == "true" || v == "1" { |
||||
result.GetBase().ExplicitHTTP = true |
||||
} |
||||
case k == "import_prefix": |
||||
result.GetBase().ImportPrefix = v |
||||
// Support import map 'M' prefix per https://github.com/golang/protobuf/blob/6fb5325/protoc-gen-go/generator/generator.go#L497.
|
||||
case len(k) > 0 && k[0] == 'M': |
||||
result.GetBase().ImportMap[k[1:]] = v // 1 is the length of 'M'.
|
||||
case len(k) > 0 && strings.HasPrefix(k, "go_import_mapping@"): |
||||
result.GetBase().ImportMap[k[18:]] = v // 18 is the length of 'go_import_mapping@'.
|
||||
default: |
||||
e := result.SetParam(k, v) |
||||
if e != nil { |
||||
return e |
||||
} |
||||
} |
||||
} |
||||
return nil |
||||
} |
@ -0,0 +1,310 @@ |
||||
package generator |
||||
|
||||
import ( |
||||
"bufio" |
||||
"bytes" |
||||
"fmt" |
||||
"go/parser" |
||||
"go/printer" |
||||
"go/token" |
||||
"path" |
||||
"strconv" |
||||
"strings" |
||||
|
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/gen" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/naming" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/typemap" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/utils" |
||||
"github.com/golang/protobuf/protoc-gen-go/descriptor" |
||||
plugin "github.com/golang/protobuf/protoc-gen-go/plugin" |
||||
"github.com/pkg/errors" |
||||
) |
||||
|
||||
const Version = "v0.1" |
||||
|
||||
var GoModuleImportPath = "github.com/bilibili/kratos" |
||||
var GoModuleDirName = "github.com/bilibili/kratos" |
||||
|
||||
type Base struct { |
||||
Reg *typemap.Registry |
||||
|
||||
// Map to record whether we've built each package
|
||||
// pkgName => alias name
|
||||
pkgs map[string]string |
||||
pkgNamesInUse map[string]bool |
||||
|
||||
ImportPrefix string // String to prefix to imported package file names.
|
||||
importMap map[string]string // Mapping from .proto file name to import path.
|
||||
|
||||
// Package naming:
|
||||
GenPkgName string // Name of the package that we're generating
|
||||
PackageName string // Name of the proto file package
|
||||
fileToGoPackageName map[*descriptor.FileDescriptorProto]string |
||||
|
||||
// List of files that were inputs to the generator. We need to hold this in
|
||||
// the struct so we can write a header for the file that lists its inputs.
|
||||
GenFiles []*descriptor.FileDescriptorProto |
||||
|
||||
// Output buffer that holds the bytes we want to write out for a single file.
|
||||
// Gets reset after working on a file.
|
||||
Output *bytes.Buffer |
||||
|
||||
// key: pkgName
|
||||
// value: importPath
|
||||
Deps map[string]string |
||||
|
||||
Params *ParamsBase |
||||
|
||||
httpInfoCache map[string]*HTTPInfo |
||||
} |
||||
|
||||
// RegisterPackageName name is the go package name or proto pkg name
|
||||
// return go pkg alias
|
||||
func (t *Base) RegisterPackageName(name string) (alias string) { |
||||
alias = name |
||||
i := 1 |
||||
for t.pkgNamesInUse[alias] { |
||||
alias = name + strconv.Itoa(i) |
||||
i++ |
||||
} |
||||
t.pkgNamesInUse[alias] = true |
||||
t.pkgs[name] = alias |
||||
return alias |
||||
} |
||||
|
||||
func (t *Base) Setup(in *plugin.CodeGeneratorRequest, paramsOpt ...GeneratorParamsInterface) { |
||||
t.httpInfoCache = make(map[string]*HTTPInfo) |
||||
t.pkgs = make(map[string]string) |
||||
t.pkgNamesInUse = make(map[string]bool) |
||||
t.importMap = make(map[string]string) |
||||
t.Deps = make(map[string]string) |
||||
t.fileToGoPackageName = make(map[*descriptor.FileDescriptorProto]string) |
||||
t.Output = bytes.NewBuffer(nil) |
||||
|
||||
var params GeneratorParamsInterface |
||||
if len(paramsOpt) > 0 { |
||||
params = paramsOpt[0] |
||||
} else { |
||||
params = &BasicParam{} |
||||
} |
||||
err := ParseGeneratorParams(in.GetParameter(), params) |
||||
if err != nil { |
||||
gen.Fail("could not parse parameters", err.Error()) |
||||
} |
||||
t.Params = params.GetBase() |
||||
t.ImportPrefix = params.GetBase().ImportPrefix |
||||
t.importMap = params.GetBase().ImportMap |
||||
|
||||
t.GenFiles = gen.FilesToGenerate(in) |
||||
|
||||
// Collect information on types.
|
||||
t.Reg = typemap.New(in.ProtoFile) |
||||
t.RegisterPackageName("context") |
||||
t.RegisterPackageName("ioutil") |
||||
t.RegisterPackageName("proto") |
||||
// Time to figure out package names of objects defined in protobuf. First,
|
||||
// we'll figure out the name for the package we're generating.
|
||||
genPkgName, err := DeduceGenPkgName(t.GenFiles) |
||||
if err != nil { |
||||
gen.Fail(err.Error()) |
||||
} |
||||
t.GenPkgName = genPkgName |
||||
// Next, we need to pick names for all the files that are dependencies.
|
||||
if len(in.ProtoFile) > 0 { |
||||
t.PackageName = t.GenFiles[0].GetPackage() |
||||
} |
||||
|
||||
for _, f := range in.ProtoFile { |
||||
if fileDescSliceContains(t.GenFiles, f) { |
||||
// This is a file we are generating. It gets the shared package name.
|
||||
t.fileToGoPackageName[f] = t.GenPkgName |
||||
} else { |
||||
// This is a dependency. Use its package name.
|
||||
name := f.GetPackage() |
||||
if name == "" { |
||||
name = utils.BaseName(f.GetName()) |
||||
} |
||||
name = utils.CleanIdentifier(name) |
||||
alias := t.RegisterPackageName(name) |
||||
t.fileToGoPackageName[f] = alias |
||||
} |
||||
} |
||||
|
||||
for _, f := range t.GenFiles { |
||||
deps := t.DeduceDeps(f) |
||||
for k, v := range deps { |
||||
t.Deps[k] = v |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (t *Base) DeduceDeps(file *descriptor.FileDescriptorProto) map[string]string { |
||||
deps := make(map[string]string) // Map of package name to quoted import path.
|
||||
ourImportPath := path.Dir(naming.GoFileName(file, "")) |
||||
for _, s := range file.Service { |
||||
for _, m := range s.Method { |
||||
defs := []*typemap.MessageDefinition{ |
||||
t.Reg.MethodInputDefinition(m), |
||||
t.Reg.MethodOutputDefinition(m), |
||||
} |
||||
for _, def := range defs { |
||||
if def.File.GetPackage() == t.PackageName { |
||||
continue |
||||
} |
||||
// By default, import path is the dirname of the Go filename.
|
||||
importPath := path.Dir(naming.GoFileName(def.File, "")) |
||||
if importPath == ourImportPath { |
||||
continue |
||||
} |
||||
importPath = t.SubstituteImportPath(importPath, def.File.GetName()) |
||||
importPath = t.ImportPrefix + importPath |
||||
pkg := t.GoPackageNameForProtoFile(def.File) |
||||
deps[pkg] = strconv.Quote(importPath) |
||||
} |
||||
} |
||||
} |
||||
return deps |
||||
} |
||||
|
||||
// DeduceGenPkgName figures out the go package name to use for generated code.
|
||||
// Will try to use the explicit go_package setting in a file (if set, must be
|
||||
// consistent in all files). If no files have go_package set, then use the
|
||||
// protobuf package name (must be consistent in all files)
|
||||
func DeduceGenPkgName(genFiles []*descriptor.FileDescriptorProto) (string, error) { |
||||
var genPkgName string |
||||
for _, f := range genFiles { |
||||
name, explicit := naming.GoPackageName(f) |
||||
if explicit { |
||||
name = utils.CleanIdentifier(name) |
||||
if genPkgName != "" && genPkgName != name { |
||||
// Make sure they're all set consistently.
|
||||
return "", errors.Errorf("files have conflicting go_package settings, must be the same: %q and %q", genPkgName, name) |
||||
} |
||||
genPkgName = name |
||||
} |
||||
} |
||||
if genPkgName != "" { |
||||
return genPkgName, nil |
||||
} |
||||
|
||||
// If there is no explicit setting, then check the implicit package name
|
||||
// (derived from the protobuf package name) of the files and make sure it's
|
||||
// consistent.
|
||||
for _, f := range genFiles { |
||||
name, _ := naming.GoPackageName(f) |
||||
name = utils.CleanIdentifier(name) |
||||
if genPkgName != "" && genPkgName != name { |
||||
return "", errors.Errorf("files have conflicting package names, must be the same or overridden with go_package: %q and %q", genPkgName, name) |
||||
} |
||||
genPkgName = name |
||||
} |
||||
|
||||
// All the files have the same name, so we're good.
|
||||
return genPkgName, nil |
||||
} |
||||
|
||||
func (t *Base) GoPackageNameForProtoFile(file *descriptor.FileDescriptorProto) string { |
||||
return t.fileToGoPackageName[file] |
||||
} |
||||
|
||||
func fileDescSliceContains(slice []*descriptor.FileDescriptorProto, f *descriptor.FileDescriptorProto) bool { |
||||
for _, sf := range slice { |
||||
if f == sf { |
||||
return true |
||||
} |
||||
} |
||||
return false |
||||
} |
||||
|
||||
// P forwards to g.gen.P, which prints output.
|
||||
func (t *Base) P(args ...string) { |
||||
for _, v := range args { |
||||
t.Output.WriteString(v) |
||||
} |
||||
t.Output.WriteByte('\n') |
||||
} |
||||
|
||||
func (t *Base) FormattedOutput() string { |
||||
// Reformat generated code.
|
||||
fset := token.NewFileSet() |
||||
raw := t.Output.Bytes() |
||||
ast, err := parser.ParseFile(fset, "", raw, parser.ParseComments) |
||||
if err != nil { |
||||
// Print out the bad code with line numbers.
|
||||
// This should never happen in practice, but it can while changing generated code,
|
||||
// so consider this a debugging aid.
|
||||
var src bytes.Buffer |
||||
s := bufio.NewScanner(bytes.NewReader(raw)) |
||||
for line := 1; s.Scan(); line++ { |
||||
fmt.Fprintf(&src, "%5d\t%s\n", line, s.Bytes()) |
||||
} |
||||
gen.Fail("bad Go source code was generated:", err.Error(), "\n"+src.String()) |
||||
} |
||||
|
||||
out := bytes.NewBuffer(nil) |
||||
err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(out, fset, ast) |
||||
if err != nil { |
||||
gen.Fail("generated Go source code could not be reformatted:", err.Error()) |
||||
} |
||||
|
||||
return out.String() |
||||
} |
||||
|
||||
func (t *Base) PrintComments(comments typemap.DefinitionComments) bool { |
||||
text := strings.TrimSuffix(comments.Leading, "\n") |
||||
if len(strings.TrimSpace(text)) == 0 { |
||||
return false |
||||
} |
||||
split := strings.Split(text, "\n") |
||||
for _, line := range split { |
||||
t.P("// ", strings.TrimPrefix(line, " ")) |
||||
} |
||||
return len(split) > 0 |
||||
} |
||||
|
||||
// IsOwnPackage ...
|
||||
// protoName is fully qualified name of a type
|
||||
func (t *Base) IsOwnPackage(protoName string) bool { |
||||
def := t.Reg.MessageDefinition(protoName) |
||||
if def == nil { |
||||
gen.Fail("could not find message for", protoName) |
||||
} |
||||
return def.File.GetPackage() == t.PackageName |
||||
} |
||||
|
||||
// Given a protobuf name for a Message, return the Go name we will use for that
|
||||
// type, including its package prefix.
|
||||
func (t *Base) GoTypeName(protoName string) string { |
||||
def := t.Reg.MessageDefinition(protoName) |
||||
if def == nil { |
||||
gen.Fail("could not find message for", protoName) |
||||
} |
||||
|
||||
var prefix string |
||||
if def.File.GetPackage() != t.PackageName { |
||||
prefix = t.GoPackageNameForProtoFile(def.File) + "." |
||||
} |
||||
|
||||
var name string |
||||
for _, parent := range def.Lineage() { |
||||
name += parent.Descriptor.GetName() + "_" |
||||
} |
||||
name += def.Descriptor.GetName() |
||||
return prefix + name |
||||
} |
||||
|
||||
func (t *Base) ShouldGenForMethod(file *descriptor.FileDescriptorProto, |
||||
service *descriptor.ServiceDescriptorProto, |
||||
method *descriptor.MethodDescriptorProto) bool { |
||||
if !t.Params.ExplicitHTTP { |
||||
return true |
||||
} |
||||
httpInfo := t.GetHttpInfoCached(file, service, method) |
||||
return httpInfo.HasExplicitHTTPPath |
||||
} |
||||
func (t *Base) SubstituteImportPath(importPath string, importFile string) string { |
||||
if substitution, ok := t.importMap[importFile]; ok { |
||||
importPath = substitution |
||||
} |
||||
return importPath |
||||
} |
@ -0,0 +1,136 @@ |
||||
package generator |
||||
|
||||
import ( |
||||
"reflect" |
||||
"strings" |
||||
|
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/extensions/gogoproto" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/tag" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/typemap" |
||||
"github.com/golang/protobuf/proto" |
||||
"github.com/golang/protobuf/protoc-gen-go/descriptor" |
||||
) |
||||
|
||||
// GetJSONFieldName get name from gogoproto.jsontag
|
||||
// else the original name
|
||||
func GetJSONFieldName(field *descriptor.FieldDescriptorProto) string { |
||||
if field == nil { |
||||
return "" |
||||
} |
||||
if field.Options != nil { |
||||
v, err := proto.GetExtension(field.Options, gogoproto.E_Jsontag) |
||||
if err == nil && v.(*string) != nil { |
||||
ret := *(v.(*string)) |
||||
i := strings.Index(ret, ",") |
||||
if i != -1 { |
||||
ret = ret[:i] |
||||
} |
||||
return ret |
||||
} |
||||
} |
||||
return field.GetName() |
||||
} |
||||
|
||||
// GetFormOrJSONName get name from form tag, then json tag
|
||||
// then original name
|
||||
func GetFormOrJSONName(field *descriptor.FieldDescriptorProto) string { |
||||
if field == nil { |
||||
return "" |
||||
} |
||||
tags := tag.GetMoreTags(field) |
||||
if tags != nil { |
||||
tag := reflect.StructTag(*tags) |
||||
fName := tag.Get("form") |
||||
if fName != "" { |
||||
i := strings.Index(fName, ",") |
||||
if i != -1 { |
||||
fName = fName[:i] |
||||
} |
||||
return fName |
||||
} |
||||
} |
||||
return GetJSONFieldName(field) |
||||
} |
||||
|
||||
// IsScalar Is this field a scalar numeric type?
|
||||
func IsScalar(field *descriptor.FieldDescriptorProto) bool { |
||||
if field.Type == nil { |
||||
return false |
||||
} |
||||
switch *field.Type { |
||||
case descriptor.FieldDescriptorProto_TYPE_DOUBLE, |
||||
descriptor.FieldDescriptorProto_TYPE_FLOAT, |
||||
descriptor.FieldDescriptorProto_TYPE_INT64, |
||||
descriptor.FieldDescriptorProto_TYPE_UINT64, |
||||
descriptor.FieldDescriptorProto_TYPE_INT32, |
||||
descriptor.FieldDescriptorProto_TYPE_FIXED64, |
||||
descriptor.FieldDescriptorProto_TYPE_FIXED32, |
||||
descriptor.FieldDescriptorProto_TYPE_BOOL, |
||||
descriptor.FieldDescriptorProto_TYPE_UINT32, |
||||
descriptor.FieldDescriptorProto_TYPE_ENUM, |
||||
descriptor.FieldDescriptorProto_TYPE_SFIXED32, |
||||
descriptor.FieldDescriptorProto_TYPE_SFIXED64, |
||||
descriptor.FieldDescriptorProto_TYPE_SINT32, |
||||
descriptor.FieldDescriptorProto_TYPE_SINT64, |
||||
descriptor.FieldDescriptorProto_TYPE_BYTES, |
||||
descriptor.FieldDescriptorProto_TYPE_STRING: |
||||
return true |
||||
default: |
||||
return false |
||||
} |
||||
} |
||||
|
||||
// IsMap is protocol buffer map
|
||||
func IsMap(field *descriptor.FieldDescriptorProto, reg *typemap.Registry) bool { |
||||
if field.GetType() != descriptor.FieldDescriptorProto_TYPE_MESSAGE { |
||||
return false |
||||
} |
||||
md := reg.MessageDefinition(field.GetTypeName()) |
||||
if md == nil || !md.Descriptor.GetOptions().GetMapEntry() { |
||||
return false |
||||
} |
||||
return true |
||||
} |
||||
|
||||
// IsRepeated Is this field repeated?
|
||||
func IsRepeated(field *descriptor.FieldDescriptorProto) bool { |
||||
return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED |
||||
|
||||
} |
||||
|
||||
// GetFieldRequired is field required?
|
||||
// eg. validate="required"
|
||||
func GetFieldRequired( |
||||
f *descriptor.FieldDescriptorProto, |
||||
reg *typemap.Registry, |
||||
md *typemap.MessageDefinition, |
||||
) bool { |
||||
fComment, _ := reg.FieldComments(md, f) |
||||
var tags []reflect.StructTag |
||||
{ |
||||
//get required info from gogoproto.moretags
|
||||
moretags := tag.GetMoreTags(f) |
||||
if moretags != nil { |
||||
tags = []reflect.StructTag{reflect.StructTag(*moretags)} |
||||
} |
||||
} |
||||
if len(tags) == 0 { |
||||
tags = tag.GetTagsInComment(fComment.Leading) |
||||
} |
||||
validateTag := tag.GetTagValue("validate", tags) |
||||
var validateRules []string |
||||
if validateTag != "" { |
||||
validateRules = strings.Split(validateTag, ",") |
||||
} |
||||
required := false |
||||
for _, rule := range validateRules { |
||||
if rule == "required" { |
||||
required = true |
||||
} |
||||
} |
||||
return required |
||||
} |
||||
|
||||
func MakeIndentStr(i int) string { |
||||
return strings.Repeat(" ", i) |
||||
} |
@ -0,0 +1,145 @@ |
||||
package generator |
||||
|
||||
import ( |
||||
"fmt" |
||||
"net/http" |
||||
"strings" |
||||
|
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/tag" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/typemap" |
||||
"github.com/golang/protobuf/proto" |
||||
"github.com/golang/protobuf/protoc-gen-go/descriptor" |
||||
"google.golang.org/genproto/googleapis/api/annotations" |
||||
) |
||||
|
||||
// HTTPInfo http info for method
|
||||
type HTTPInfo struct { |
||||
HttpMethod string |
||||
Path string |
||||
LegacyPath string |
||||
NewPath string |
||||
IsLegacyPath bool |
||||
Title string |
||||
Description string |
||||
// is http path added in the google.api.http option ?
|
||||
HasExplicitHTTPPath bool |
||||
} |
||||
|
||||
type googleMethodOptionInfo struct { |
||||
Method string |
||||
PathPattern string |
||||
HTTPRule *annotations.HttpRule |
||||
} |
||||
|
||||
// GetHTTPInfo http info of method
|
||||
func GetHTTPInfo( |
||||
file *descriptor.FileDescriptorProto, |
||||
service *descriptor.ServiceDescriptorProto, |
||||
method *descriptor.MethodDescriptorProto, |
||||
reg *typemap.Registry) *HTTPInfo { |
||||
var ( |
||||
title string |
||||
desc string |
||||
httpMethod string |
||||
newPath string |
||||
explicitHTTPPath bool |
||||
) |
||||
comment, _ := reg.MethodComments(file, service, method) |
||||
tags := tag.GetTagsInComment(comment.Leading) |
||||
cleanComments := tag.GetCommentWithoutTag(comment.Leading) |
||||
if len(cleanComments) > 0 { |
||||
title = strings.Trim(cleanComments[0], "\n\r ") |
||||
if len(cleanComments) > 1 { |
||||
descLines := cleanComments[1:] |
||||
desc = strings.Trim(strings.Join(descLines, "\n"), "\r\n ") |
||||
} else { |
||||
desc = "" |
||||
} |
||||
} else { |
||||
title = "" |
||||
} |
||||
googleOptionInfo, err := ParseBMMethod(method) |
||||
if err == nil { |
||||
httpMethod = strings.ToUpper(googleOptionInfo.Method) |
||||
p := googleOptionInfo.PathPattern |
||||
if p != "" { |
||||
explicitHTTPPath = true |
||||
newPath = p |
||||
goto END |
||||
} |
||||
} |
||||
|
||||
if httpMethod == "" { |
||||
// resolve http method
|
||||
httpMethod = tag.GetTagValue("method", tags) |
||||
if httpMethod == "" { |
||||
httpMethod = "GET" |
||||
} else { |
||||
httpMethod = strings.ToUpper(httpMethod) |
||||
} |
||||
} |
||||
|
||||
newPath = "/" + file.GetPackage() + "." + service.GetName() + "/" + method.GetName() |
||||
END: |
||||
var p = newPath |
||||
param := &HTTPInfo{HttpMethod: httpMethod, |
||||
Path: p, |
||||
NewPath: newPath, |
||||
IsLegacyPath: false, |
||||
Title: title, |
||||
Description: desc, |
||||
HasExplicitHTTPPath: explicitHTTPPath, |
||||
} |
||||
if title == "" { |
||||
param.Title = param.Path |
||||
} |
||||
return param |
||||
} |
||||
|
||||
func (t *Base) GetHttpInfoCached(file *descriptor.FileDescriptorProto, |
||||
service *descriptor.ServiceDescriptorProto, |
||||
method *descriptor.MethodDescriptorProto) *HTTPInfo { |
||||
key := file.GetPackage() + service.GetName() + method.GetName() |
||||
httpInfo, ok := t.httpInfoCache[key] |
||||
if !ok { |
||||
httpInfo = GetHTTPInfo(file, service, method, t.Reg) |
||||
t.httpInfoCache[key] = httpInfo |
||||
} |
||||
return httpInfo |
||||
} |
||||
|
||||
// ParseBMMethod parse BMMethodDescriptor form method descriptor proto
|
||||
func ParseBMMethod(method *descriptor.MethodDescriptorProto) (*googleMethodOptionInfo, error) { |
||||
ext, err := proto.GetExtension(method.GetOptions(), annotations.E_Http) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("get extension error: %s", err) |
||||
} |
||||
rule := ext.(*annotations.HttpRule) |
||||
var httpMethod string |
||||
var pathPattern string |
||||
switch pattern := rule.Pattern.(type) { |
||||
case *annotations.HttpRule_Get: |
||||
pathPattern = pattern.Get |
||||
httpMethod = http.MethodGet |
||||
case *annotations.HttpRule_Put: |
||||
pathPattern = pattern.Put |
||||
httpMethod = http.MethodPut |
||||
case *annotations.HttpRule_Post: |
||||
pathPattern = pattern.Post |
||||
httpMethod = http.MethodPost |
||||
case *annotations.HttpRule_Patch: |
||||
pathPattern = pattern.Patch |
||||
httpMethod = http.MethodPatch |
||||
case *annotations.HttpRule_Delete: |
||||
pathPattern = pattern.Delete |
||||
httpMethod = http.MethodDelete |
||||
default: |
||||
return nil, fmt.Errorf("unsupport http pattern %s", rule.Pattern) |
||||
} |
||||
bmMethod := &googleMethodOptionInfo{ |
||||
Method: httpMethod, |
||||
PathPattern: pathPattern, |
||||
HTTPRule: rule, |
||||
} |
||||
return bmMethod, nil |
||||
} |
@ -0,0 +1,27 @@ |
||||
package naming |
||||
|
||||
import ( |
||||
"path" |
||||
|
||||
"github.com/golang/protobuf/protoc-gen-go/descriptor" |
||||
) |
||||
|
||||
// GoFileName returns the output name for the generated Go file.
|
||||
func GoFileName(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 |
||||
|
||||
// Does the file have a "go_package" option? If it does, it may override the
|
||||
// filename.
|
||||
if impPath, _, ok := goPackageOption(f); ok && impPath != "" { |
||||
// Replace the existing dirname with the declared import path.
|
||||
_, name = path.Split(name) |
||||
name = path.Join(impPath, name) |
||||
return name |
||||
} |
||||
|
||||
return name |
||||
} |
@ -0,0 +1,101 @@ |
||||
package naming |
||||
|
||||
import ( |
||||
"os" |
||||
"path/filepath" |
||||
"strings" |
||||
|
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/utils" |
||||
"github.com/golang/protobuf/protoc-gen-go/descriptor" |
||||
"github.com/pkg/errors" |
||||
"github.com/siddontang/go/ioutil2" |
||||
) |
||||
|
||||
// GetVersionPrefix 根据go包名获取api版本前缀
|
||||
// @param pkg 从proto获取到的对应的go报名
|
||||
// @return 如果是v*开始的 返回v*
|
||||
// 否则返回空
|
||||
func GetVersionPrefix(pkg string) string { |
||||
if pkg == "" { |
||||
return "" |
||||
} |
||||
if pkg[:1] == "v" { |
||||
return pkg |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func ServiceName(service *descriptor.ServiceDescriptorProto) string { |
||||
return utils.CamelCase(service.GetName()) |
||||
} |
||||
|
||||
// MethodName ...
|
||||
func MethodName(method *descriptor.MethodDescriptorProto) string { |
||||
return utils.CamelCase(method.GetName()) |
||||
} |
||||
|
||||
// GetGoImportPathForPb 得到 proto 文件对应的 go import路径
|
||||
// protoFilename is the proto file name
|
||||
// 可能根本无法得到proto文件的具体路径, 只能假设 proto 的filename 是相对当前目录的
|
||||
// 假设 protoAbsolutePath = wd/protoFilename
|
||||
func GetGoImportPathForPb(protoFilename string, moduleImportPath string, moduleDirName string) (importPath string, err error) { |
||||
wd, err := os.Getwd() |
||||
if err != nil { |
||||
panic("cannot get working directory") |
||||
} |
||||
absPath := wd + "/" + protoFilename |
||||
if !ioutil2.FileExists(absPath) { |
||||
err = errors.New("Cannot find proto file path of " + protoFilename) |
||||
return "", err |
||||
} |
||||
index := strings.Index(absPath, moduleDirName) |
||||
if index == -1 { |
||||
return "", errors.Errorf("proto file %s is not inside project %s", protoFilename, moduleDirName) |
||||
} |
||||
relativePath := absPath[index:] |
||||
importPath = filepath.Dir(relativePath) |
||||
return importPath, nil |
||||
} |
||||
|
||||
// GoPackageNameForProtoFile returns the Go package name to use in the generated Go file.
|
||||
// The result explicitly reports whether the name came from an option go_package
|
||||
// statement. If explicit is false, the name was derived from the protocol
|
||||
// buffer's package statement or the input file name.
|
||||
func GoPackageName(f *descriptor.FileDescriptorProto) (name string, explicit bool) { |
||||
// Does the file have a "go_package" option?
|
||||
if _, pkg, ok := goPackageOption(f); ok { |
||||
return pkg, true |
||||
} |
||||
|
||||
// Does the file have a package clause?
|
||||
if pkg := f.GetPackage(); pkg != "" { |
||||
return pkg, false |
||||
} |
||||
// Use the file base name.
|
||||
return utils.BaseName(f.GetName()), false |
||||
} |
||||
|
||||
// goPackageOption interprets the file's go_package option.
|
||||
// If there is no go_package, it returns ("", "", false).
|
||||
// If there's a simple name, it returns ("", pkg, true).
|
||||
// If the option implies an import path, it returns (impPath, pkg, true).
|
||||
func goPackageOption(f *descriptor.FileDescriptorProto) (impPath, pkg string, ok bool) { |
||||
pkg = f.GetOptions().GetGoPackage() |
||||
if pkg == "" { |
||||
return |
||||
} |
||||
ok = true |
||||
// The presence of a slash implies there's an import path.
|
||||
slash := strings.LastIndex(pkg, "/") |
||||
if slash < 0 { |
||||
return |
||||
} |
||||
impPath, pkg = pkg, pkg[slash+1:] |
||||
// A semicolon-delimited suffix overrides the package name.
|
||||
sc := strings.IndexByte(impPath, ';') |
||||
if sc < 0 { |
||||
return |
||||
} |
||||
impPath, pkg = impPath[:sc], impPath[sc+1:] |
||||
return |
||||
} |
@ -0,0 +1,119 @@ |
||||
package project |
||||
|
||||
import ( |
||||
"os" |
||||
"path/filepath" |
||||
"strings" |
||||
|
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/utils" |
||||
"github.com/pkg/errors" |
||||
"github.com/siddontang/go/ioutil2" |
||||
) |
||||
|
||||
// if proto file is inside a project (that has a /api directory)
|
||||
// this present a project info
|
||||
// 必须假设proto文件的路径就是相对work-dir的路径,否则无法找到proto文件以及对应的project
|
||||
type ProjectInfo struct { |
||||
// AbsolutePath of the project
|
||||
AbsolutePath string |
||||
// ImportPath of project
|
||||
ImportPath string |
||||
// dir name of project
|
||||
Name string |
||||
// parent dir of project, maybe empty
|
||||
Department string |
||||
// grandma dir of project , maybe empty
|
||||
Typ string |
||||
HasInternalPkg bool |
||||
// 从工作目录(working directory)到project目录的相对路径 比如a/b .. ../a
|
||||
// 作用是什么?
|
||||
// 假设目录结构是
|
||||
// -project
|
||||
// - api/api.proto
|
||||
// - internal/service
|
||||
// 我想在 internal/service下生成一个文件 service.go
|
||||
// work-dir 为 project/api
|
||||
// proto 生成命令为 protoc --xx_out=. api.proto
|
||||
// 那么在 protoc plugin 中的文件输出路径就得是 ../internal/service/ => {pathRefToProj}internal/service
|
||||
//
|
||||
PathRefToProj string |
||||
} |
||||
|
||||
func NewProjInfo(file string, modDirName string, modImportPath string) (projInfo *ProjectInfo, err error) { |
||||
projInfo = &ProjectInfo{} |
||||
wd, err := os.Getwd() |
||||
if err != nil { |
||||
panic("cannot get working directory") |
||||
} |
||||
protoAbs := wd + "/" + file |
||||
protoAbs, _ = filepath.Abs(protoAbs) |
||||
|
||||
if !ioutil2.FileExists(protoAbs) { |
||||
return nil, errors.Errorf("Cannot find proto file in current dir %s, file: %s ", wd, file) |
||||
} |
||||
//appIndex := strings.Index(wd, modDirName)
|
||||
//if appIndex == -1 {
|
||||
// err = errors.New("not in " + modDirName)
|
||||
// return nil, err
|
||||
//}
|
||||
|
||||
projPath := LookupProjPath(protoAbs) |
||||
|
||||
if projPath == "" { |
||||
err = errors.New("not in project") |
||||
return nil, err |
||||
} |
||||
rel, _ := filepath.Rel(wd, projPath) |
||||
projInfo.PathRefToProj = rel |
||||
projInfo.AbsolutePath = projPath |
||||
if ioutil2.FileExists(projPath + "/internal") { |
||||
projInfo.HasInternalPkg = true |
||||
} |
||||
|
||||
i := strings.Index(projInfo.AbsolutePath, modDirName) |
||||
if i == -1 { |
||||
err = errors.Errorf("project is not inside module, project=%s, module=%s", projPath, modDirName) |
||||
} |
||||
relativePath := projInfo.AbsolutePath[i+len(modDirName):] |
||||
projInfo.ImportPath = modImportPath + relativePath |
||||
projInfo.Name = filepath.Base(projPath) |
||||
if p := filepath.Dir(projPath); p != "/" { |
||||
projInfo.Department = filepath.Base(p) |
||||
if p = filepath.Dir(p); p != "/" { |
||||
projInfo.Typ = filepath.Base(p) |
||||
} |
||||
} |
||||
return projInfo, nil |
||||
} |
||||
|
||||
// LookupProjPath get project path by proto absolute path
|
||||
// assume that proto is in the project's api directory
|
||||
func LookupProjPath(protoAbs string) (result string) { |
||||
f := func(protoAbs string, dirs []string) string { |
||||
lastIndex := len(protoAbs) |
||||
curPath := protoAbs |
||||
|
||||
for lastIndex > 0 { |
||||
found := true |
||||
for _, d := range dirs { |
||||
if !utils.IsDir(curPath + "/" + d) { |
||||
found = false |
||||
break |
||||
} |
||||
} |
||||
if found { |
||||
return curPath |
||||
} |
||||
lastIndex = strings.LastIndex(curPath, string(os.PathSeparator)) |
||||
curPath = protoAbs[:lastIndex] |
||||
} |
||||
result = "" |
||||
return result |
||||
} |
||||
|
||||
firstStep := f(protoAbs, []string{"cmd", "api"}) |
||||
if firstStep != "" { |
||||
return firstStep |
||||
} |
||||
return f(protoAbs, []string{"api"}) |
||||
} |
@ -0,0 +1,20 @@ |
||||
package tag |
||||
|
||||
import ( |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/extensions/gogoproto" |
||||
"github.com/golang/protobuf/proto" |
||||
"github.com/golang/protobuf/protoc-gen-go/descriptor" |
||||
) |
||||
|
||||
func GetMoreTags(field *descriptor.FieldDescriptorProto) *string { |
||||
if field == nil { |
||||
return nil |
||||
} |
||||
if field.Options != nil { |
||||
v, err := proto.GetExtension(field.Options, gogoproto.E_Moretags) |
||||
if err == nil && v.(*string) != nil { |
||||
return v.(*string) |
||||
} |
||||
} |
||||
return nil |
||||
} |
@ -0,0 +1,55 @@ |
||||
package tag |
||||
|
||||
import ( |
||||
"reflect" |
||||
"strings" |
||||
) |
||||
|
||||
// GetCommentWithoutTag strip tags in comment
|
||||
func GetCommentWithoutTag(comment string) []string { |
||||
var lines []string |
||||
if comment == "" { |
||||
return lines |
||||
} |
||||
split := strings.Split(strings.TrimRight(comment, "\n\r"), "\n") |
||||
for _, line := range split { |
||||
tag, _, _ := GetLineTag(line) |
||||
if tag == "" { |
||||
lines = append(lines, line) |
||||
} |
||||
} |
||||
return lines |
||||
} |
||||
|
||||
func GetTagsInComment(comment string) []reflect.StructTag { |
||||
split := strings.Split(comment, "\n") |
||||
var tagsInComment []reflect.StructTag |
||||
for _, line := range split { |
||||
tag, _, _ := GetLineTag(line) |
||||
if tag != "" { |
||||
tagsInComment = append(tagsInComment, tag) |
||||
} |
||||
} |
||||
return tagsInComment |
||||
} |
||||
|
||||
func GetTagValue(key string, tags []reflect.StructTag) string { |
||||
for _, t := range tags { |
||||
val := t.Get(key) |
||||
if val != "" { |
||||
return val |
||||
} |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
// find tag between backtick, start & end is the position of backtick
|
||||
func GetLineTag(line string) (tag reflect.StructTag, start int, end int) { |
||||
start = strings.Index(line, "`") |
||||
end = strings.LastIndex(line, "`") |
||||
if end <= start { |
||||
return |
||||
} |
||||
tag = reflect.StructTag(line[start+1 : end]) |
||||
return |
||||
} |
@ -0,0 +1,277 @@ |
||||
package typemap |
||||
|
||||
// Copyright 2018 Twitch Interactive, Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"). You may not
|
||||
// use this file except in compliance with the License. A copy of the License is
|
||||
// located at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// or in the "license" file accompanying this file. This file is distributed on
|
||||
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
// express or implied. See the License for the specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
import ( |
||||
"strings" |
||||
|
||||
"github.com/golang/protobuf/protoc-gen-go/descriptor" |
||||
"github.com/pkg/errors" |
||||
) |
||||
|
||||
// Registry is the place of descriptors resolving
|
||||
type Registry struct { |
||||
allFiles []*descriptor.FileDescriptorProto |
||||
filesByName map[string]*descriptor.FileDescriptorProto |
||||
|
||||
// Mapping of fully-qualified names to their definitions
|
||||
messagesByProtoName map[string]*MessageDefinition |
||||
} |
||||
|
||||
// New Registry
|
||||
func New(files []*descriptor.FileDescriptorProto) *Registry { |
||||
r := &Registry{ |
||||
allFiles: files, |
||||
filesByName: make(map[string]*descriptor.FileDescriptorProto), |
||||
messagesByProtoName: make(map[string]*MessageDefinition), |
||||
} |
||||
|
||||
// First, index the file descriptors by name. We need this so
|
||||
// messageDefsForFile can correctly scan imports.
|
||||
for _, f := range files { |
||||
r.filesByName[f.GetName()] = f |
||||
} |
||||
|
||||
// Next, index all the message definitions by their fully-qualified proto
|
||||
// names.
|
||||
for _, f := range files { |
||||
defs := messageDefsForFile(f, r.filesByName) |
||||
for name, def := range defs { |
||||
r.messagesByProtoName[name] = def |
||||
} |
||||
} |
||||
return r |
||||
} |
||||
|
||||
// FileComments comment of file
|
||||
func (r *Registry) FileComments(file *descriptor.FileDescriptorProto) (DefinitionComments, error) { |
||||
return commentsAtPath([]int32{packagePath}, file), nil |
||||
} |
||||
|
||||
// ServiceComments comments of service
|
||||
func (r *Registry) ServiceComments(file *descriptor.FileDescriptorProto, svc *descriptor.ServiceDescriptorProto) (DefinitionComments, error) { |
||||
for i, s := range file.Service { |
||||
if s == svc { |
||||
path := []int32{servicePath, int32(i)} |
||||
return commentsAtPath(path, file), nil |
||||
} |
||||
} |
||||
return DefinitionComments{}, errors.Errorf("service not found in file") |
||||
} |
||||
|
||||
// FieldComments ...
|
||||
func (r *Registry) FieldComments(message *MessageDefinition, field *descriptor.FieldDescriptorProto) (DefinitionComments, error) { |
||||
file := message.File |
||||
mpath := message.path |
||||
for i, f := range message.Descriptor.Field { |
||||
if f == field { |
||||
path := append(mpath, messageFieldPath, int32(i)) |
||||
return commentsAtPath(path, file), nil |
||||
} |
||||
} |
||||
return DefinitionComments{}, errors.Errorf("field not found in msg") |
||||
} |
||||
|
||||
// MethodComments comment of method
|
||||
func (r *Registry) MethodComments(file *descriptor.FileDescriptorProto, svc *descriptor.ServiceDescriptorProto, method *descriptor.MethodDescriptorProto) (DefinitionComments, error) { |
||||
for i, s := range file.Service { |
||||
if s == svc { |
||||
path := []int32{servicePath, int32(i)} |
||||
for j, m := range s.Method { |
||||
if m == method { |
||||
path = append(path, serviceMethodPath, int32(j)) |
||||
return commentsAtPath(path, file), nil |
||||
} |
||||
} |
||||
} |
||||
} |
||||
return DefinitionComments{}, errors.Errorf("service not found in file") |
||||
} |
||||
|
||||
// MethodInputDefinition returns MethodInputDefinition
|
||||
func (r *Registry) MethodInputDefinition(method *descriptor.MethodDescriptorProto) *MessageDefinition { |
||||
return r.messagesByProtoName[method.GetInputType()] |
||||
} |
||||
|
||||
// MethodOutputDefinition returns MethodOutputDefinition
|
||||
func (r *Registry) MethodOutputDefinition(method *descriptor.MethodDescriptorProto) *MessageDefinition { |
||||
return r.messagesByProtoName[method.GetOutputType()] |
||||
} |
||||
|
||||
// MessageDefinition by name
|
||||
func (r *Registry) MessageDefinition(name string) *MessageDefinition { |
||||
return r.messagesByProtoName[name] |
||||
} |
||||
|
||||
// MessageDefinition msg info
|
||||
type MessageDefinition struct { |
||||
// Descriptor is is the DescriptorProto defining the message.
|
||||
Descriptor *descriptor.DescriptorProto |
||||
// File is the File that the message was defined in. Or, if it has been
|
||||
// publicly imported, what File was that import performed in?
|
||||
File *descriptor.FileDescriptorProto |
||||
// Parent is the parent message, if this was defined as a nested message. If
|
||||
// this was defiend at the top level, parent is nil.
|
||||
Parent *MessageDefinition |
||||
// Comments describes the comments surrounding a message's definition. If it
|
||||
// was publicly imported, then these comments are from the actual source file,
|
||||
// not the file that the import was performed in.
|
||||
Comments DefinitionComments |
||||
|
||||
// path is the 'SourceCodeInfo' path. See the documentation for
|
||||
// github.com/golang/protobuf/protoc-gen-go/descriptor.SourceCodeInfo for an
|
||||
// explanation of its format.
|
||||
path []int32 |
||||
} |
||||
|
||||
// ProtoName returns the dot-delimited, fully-qualified protobuf name of the
|
||||
// message.
|
||||
func (m *MessageDefinition) ProtoName() string { |
||||
prefix := "." |
||||
if pkg := m.File.GetPackage(); pkg != "" { |
||||
prefix += pkg + "." |
||||
} |
||||
|
||||
if lineage := m.Lineage(); len(lineage) > 0 { |
||||
for _, parent := range lineage { |
||||
prefix += parent.Descriptor.GetName() + "." |
||||
} |
||||
} |
||||
|
||||
return prefix + m.Descriptor.GetName() |
||||
} |
||||
|
||||
// Lineage returns m's parental chain all the way back up to a top-level message
|
||||
// definition. The first element of the returned slice is the highest-level
|
||||
// parent.
|
||||
func (m *MessageDefinition) Lineage() []*MessageDefinition { |
||||
var parents []*MessageDefinition |
||||
for p := m.Parent; p != nil; p = p.Parent { |
||||
parents = append([]*MessageDefinition{p}, parents...) |
||||
} |
||||
return parents |
||||
} |
||||
|
||||
// descendants returns all the submessages defined within m, and all the
|
||||
// descendants of those, recursively.
|
||||
func (m *MessageDefinition) descendants() []*MessageDefinition { |
||||
descendants := make([]*MessageDefinition, 0) |
||||
for i, child := range m.Descriptor.NestedType { |
||||
path := append(m.path, []int32{messageMessagePath, int32(i)}...) |
||||
childDef := &MessageDefinition{ |
||||
Descriptor: child, |
||||
File: m.File, |
||||
Parent: m, |
||||
Comments: commentsAtPath(path, m.File), |
||||
path: path, |
||||
} |
||||
descendants = append(descendants, childDef) |
||||
descendants = append(descendants, childDef.descendants()...) |
||||
} |
||||
return descendants |
||||
} |
||||
|
||||
// messageDefsForFile gathers a mapping of fully-qualified protobuf names to
|
||||
// their definitions. It scans a singles file at a time. It requires a mapping
|
||||
// of .proto file names to their definitions in order to correctly handle
|
||||
// 'import public' declarations; this mapping should include all files
|
||||
// transitively imported by f.
|
||||
func messageDefsForFile(f *descriptor.FileDescriptorProto, filesByName map[string]*descriptor.FileDescriptorProto) map[string]*MessageDefinition { |
||||
byProtoName := make(map[string]*MessageDefinition) |
||||
// First, gather all the messages defined at the top level.
|
||||
for i, d := range f.MessageType { |
||||
path := []int32{messagePath, int32(i)} |
||||
def := &MessageDefinition{ |
||||
Descriptor: d, |
||||
File: f, |
||||
Parent: nil, |
||||
Comments: commentsAtPath(path, f), |
||||
path: path, |
||||
} |
||||
|
||||
byProtoName[def.ProtoName()] = def |
||||
// Next, all nested message definitions.
|
||||
for _, child := range def.descendants() { |
||||
byProtoName[child.ProtoName()] = child |
||||
} |
||||
} |
||||
|
||||
// Finally, all messages imported publicly.
|
||||
for _, depIdx := range f.PublicDependency { |
||||
depFileName := f.Dependency[depIdx] |
||||
depFile := filesByName[depFileName] |
||||
depDefs := messageDefsForFile(depFile, filesByName) |
||||
for _, def := range depDefs { |
||||
imported := &MessageDefinition{ |
||||
Descriptor: def.Descriptor, |
||||
File: f, |
||||
Parent: def.Parent, |
||||
Comments: commentsAtPath(def.path, depFile), |
||||
path: def.path, |
||||
} |
||||
byProtoName[imported.ProtoName()] = imported |
||||
} |
||||
} |
||||
|
||||
return byProtoName |
||||
} |
||||
|
||||
// // ignored detached comments.
|
||||
type DefinitionComments struct { |
||||
Leading string |
||||
Trailing string |
||||
LeadingDetached []string |
||||
} |
||||
|
||||
func commentsAtPath(path []int32, sourceFile *descriptor.FileDescriptorProto) DefinitionComments { |
||||
if sourceFile.SourceCodeInfo == nil { |
||||
// The compiler didn't provide us with comments.
|
||||
return DefinitionComments{} |
||||
} |
||||
|
||||
for _, loc := range sourceFile.SourceCodeInfo.Location { |
||||
if pathEqual(path, loc.Path) { |
||||
return DefinitionComments{ |
||||
Leading: strings.TrimSuffix(loc.GetLeadingComments(), "\n"), |
||||
LeadingDetached: loc.GetLeadingDetachedComments(), |
||||
Trailing: loc.GetTrailingComments(), |
||||
} |
||||
} |
||||
} |
||||
return DefinitionComments{} |
||||
} |
||||
|
||||
func pathEqual(path1, path2 []int32) bool { |
||||
if len(path1) != len(path2) { |
||||
return false |
||||
} |
||||
for i, v := range path1 { |
||||
if path2[i] != v { |
||||
return false |
||||
} |
||||
} |
||||
return true |
||||
} |
||||
|
||||
const ( |
||||
// tag numbers in FileDescriptorProto
|
||||
packagePath = 2 // package
|
||||
messagePath = 4 // message_type
|
||||
servicePath = 6 // service
|
||||
// tag numbers in DescriptorProto
|
||||
messageFieldPath = 2 // field
|
||||
messageMessagePath = 3 // nested_type
|
||||
// tag numbers in ServiceDescriptorProto
|
||||
serviceMethodPath = 2 // method
|
||||
) |
@ -0,0 +1,98 @@ |
||||
|
||||
package utils |
||||
|
||||
import ( |
||||
"strings" |
||||
"unicode" |
||||
) |
||||
|
||||
// Is c an ASCII lower-case letter?
|
||||
func isASCIILower(c byte) bool { |
||||
return 'a' <= c && c <= 'z' |
||||
} |
||||
|
||||
// Is c an ASCII digit?
|
||||
func isASCIIDigit(c byte) bool { |
||||
return '0' <= c && c <= '9' |
||||
} |
||||
|
||||
// CamelCase converts a string from snake_case to CamelCased.
|
||||
//
|
||||
// If there is an interior underscore followed by a lower case letter, drop the
|
||||
// underscore and convert the letter to upper case. There is a remote
|
||||
// possibility of this rewrite causing a name collision, but it's so remote
|
||||
// we're prepared to pretend it's nonexistent - since the C++ generator
|
||||
// lowercases names, it's extremely unlikely to have two fields with different
|
||||
// capitalizations. In short, _my_field_name_2 becomes XMyFieldName_2.
|
||||
func CamelCase(s string) string { |
||||
if s == "" { |
||||
return "" |
||||
} |
||||
t := make([]byte, 0, 32) |
||||
i := 0 |
||||
if s[0] == '_' { |
||||
// Need a capital letter; drop the '_'.
|
||||
t = append(t, 'X') |
||||
i++ |
||||
} |
||||
// Invariant: if the next letter is lower case, it must be converted
|
||||
// to upper case.
|
||||
//
|
||||
// That is, we process a word at a time, where words are marked by _ or upper
|
||||
// case letter. Digits are treated as words.
|
||||
for ; i < len(s); i++ { |
||||
c := s[i] |
||||
if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) { |
||||
continue // Skip the underscore in s.
|
||||
} |
||||
if isASCIIDigit(c) { |
||||
t = append(t, c) |
||||
continue |
||||
} |
||||
// Assume we have a letter now - if not, it's a bogus identifier. The next
|
||||
// word is a sequence of characters that must start upper case.
|
||||
if isASCIILower(c) { |
||||
c ^= ' ' // Make it a capital letter.
|
||||
} |
||||
t = append(t, c) // Guaranteed not lower case.
|
||||
// Accept lower case sequence that follows.
|
||||
for i+1 < len(s) && isASCIILower(s[i+1]) { |
||||
i++ |
||||
t = append(t, s[i]) |
||||
} |
||||
} |
||||
return string(t) |
||||
} |
||||
|
||||
// CamelCaseSlice is like CamelCase, but the argument is a slice of strings to
|
||||
// be joined with "_" and then camelcased.
|
||||
func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) } |
||||
|
||||
// BaseName the last path element of a slash-delimited name, with the last
|
||||
// dotted suffix removed.
|
||||
func BaseName(name string) string { |
||||
// First, find the last element
|
||||
if i := strings.LastIndex(name, "/"); i >= 0 { |
||||
name = name[i+1:] |
||||
} |
||||
// Now drop the suffix
|
||||
if i := strings.LastIndex(name, "."); i >= 0 { |
||||
name = name[0:i] |
||||
} |
||||
return name |
||||
} |
||||
|
||||
// AlphaDigitize replaces non-letter, non-digit, non-underscore characters with
|
||||
// underscore.
|
||||
func AlphaDigitize(r rune) rune { |
||||
if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' { |
||||
return r |
||||
} |
||||
return '_' |
||||
} |
||||
|
||||
// CleanIdentifier makes sure s is a valid 'identifier' string: it contains only
|
||||
// letters, numbers, and underscore.
|
||||
func CleanIdentifier(s string) string { |
||||
return strings.Map(AlphaDigitize, s) |
||||
} |
@ -0,0 +1,29 @@ |
||||
package utils |
||||
|
||||
import ( |
||||
"os" |
||||
"unicode" |
||||
) |
||||
|
||||
// LcFirst lower the first letter
|
||||
func LcFirst(str string) string { |
||||
for i, v := range str { |
||||
return string(unicode.ToLower(v)) + str[i+1:] |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func IsDir(name string) bool { |
||||
file, err := os.Open(name) |
||||
|
||||
if err != nil { |
||||
return false |
||||
} |
||||
defer file.Close() |
||||
|
||||
fi, err := file.Stat() |
||||
if err != nil { |
||||
return false |
||||
} |
||||
return fi.IsDir() |
||||
} |
@ -0,0 +1,355 @@ |
||||
package generator |
||||
|
||||
import ( |
||||
"fmt" |
||||
"reflect" |
||||
"sort" |
||||
"strings" |
||||
|
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/generator" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/naming" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/tag" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/typemap" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/utils" |
||||
"github.com/golang/protobuf/proto" |
||||
"github.com/golang/protobuf/protoc-gen-go/descriptor" |
||||
plugin "github.com/golang/protobuf/protoc-gen-go/plugin" |
||||
) |
||||
|
||||
type bm struct { |
||||
generator.Base |
||||
filesHandled int |
||||
} |
||||
|
||||
// BmGenerator BM generator.
|
||||
func BmGenerator() *bm { |
||||
t := &bm{} |
||||
return t |
||||
} |
||||
|
||||
// Generate ...
|
||||
func (t *bm) 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 *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) |
||||
t.generatePathConstants(file) |
||||
count := 0 |
||||
for i, service := range file.Service { |
||||
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.Content = proto.String(t.FormattedOutput()) |
||||
t.Output.Reset() |
||||
|
||||
t.filesHandled++ |
||||
return resp |
||||
} |
||||
|
||||
func (t *bm) generatePathConstants(file *descriptor.FileDescriptorProto) { |
||||
t.P() |
||||
for _, service := range file.Service { |
||||
name := naming.ServiceName(service) |
||||
for _, method := range service.Method { |
||||
if !t.ShouldGenForMethod(file, service, method) { |
||||
continue |
||||
} |
||||
apiInfo := t.GetHttpInfoCached(file, service, method) |
||||
t.P(`var Path`, name, naming.MethodName(method), ` = "`, apiInfo.Path, `"`) |
||||
} |
||||
t.P() |
||||
} |
||||
} |
||||
|
||||
func (t *bm) generateFileHeader(file *descriptor.FileDescriptorProto, pkgName string) { |
||||
t.P("// Code generated by protoc-gen-bm ", generator.Version, ", DO NOT EDIT.") |
||||
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/bmgen/protoc-gen-bm ", generator.Version, ".") |
||||
t.P() |
||||
comment, err := t.Reg.FileComments(file) |
||||
if err == nil && comment.Leading != "" { |
||||
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 *bm) generateImports(file *descriptor.FileDescriptorProto) { |
||||
//if len(file.Service) == 0 {
|
||||
// return
|
||||
//}
|
||||
t.P(`import (`) |
||||
//t.P(` `,t.pkgs["context"], ` "context"`)
|
||||
t.P(` "context"`) |
||||
t.P() |
||||
t.P(` bm "github.com/bilibili/kratos/pkg/net/http/blademaster"`) |
||||
t.P(` "github.com/bilibili/kratos/pkg/net/http/blademaster/binding"`) |
||||
|
||||
t.P(`)`) |
||||
// It's legal to import a message and use it as an input or output for a
|
||||
// method. Make sure to import the package of any such message. First, dedupe
|
||||
// them.
|
||||
deps := make(map[string]string) // Map of package name to quoted import path.
|
||||
deps = t.DeduceDeps(file) |
||||
for pkg, importPath := range deps { |
||||
for _, service := range file.Service { |
||||
for _, method := range service.Method { |
||||
inputType := t.GoTypeName(method.GetInputType()) |
||||
outputType := t.GoTypeName(method.GetOutputType()) |
||||
if strings.HasPrefix(pkg, outputType) || strings.HasPrefix(pkg, inputType) { |
||||
t.P(`import `, pkg, ` `, importPath) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
if len(deps) > 0 { |
||||
t.P() |
||||
} |
||||
t.P() |
||||
t.P(`// to suppressed 'imported but not used warning'`) |
||||
t.P(`var _ *bm.Context`) |
||||
t.P(`var _ context.Context`) |
||||
t.P(`var _ binding.StructValidator`) |
||||
|
||||
} |
||||
|
||||
// Big header comments to makes it easier to visually parse a generated file.
|
||||
func (t *bm) sectionComment(sectionTitle string) { |
||||
t.P() |
||||
t.P(`// `, strings.Repeat("=", len(sectionTitle))) |
||||
t.P(`// `, sectionTitle) |
||||
t.P(`// `, strings.Repeat("=", len(sectionTitle))) |
||||
t.P() |
||||
} |
||||
|
||||
func (t *bm) generateBMRoute( |
||||
file *descriptor.FileDescriptorProto, |
||||
service *descriptor.ServiceDescriptorProto, |
||||
index int) { |
||||
// old mode is generate xx.route.go in the http pkg
|
||||
// new mode is generate route code in the same .bm.go
|
||||
// route rule /x{department}/{project-name}/{path_prefix}/method_name
|
||||
// generate each route method
|
||||
servName := naming.ServiceName(service) |
||||
versionPrefix := naming.GetVersionPrefix(t.GenPkgName) |
||||
svcName := utils.LcFirst(utils.CamelCase(versionPrefix)) + servName + "Svc" |
||||
t.P(`var `, svcName, ` `, servName, `BMServer`) |
||||
|
||||
type methodInfo struct { |
||||
midwares []string |
||||
routeFuncName string |
||||
apiInfo *generator.HTTPInfo |
||||
methodName string |
||||
} |
||||
var methList []methodInfo |
||||
var allMidwareMap = make(map[string]bool) |
||||
var isLegacyPkg = false |
||||
for _, method := range service.Method { |
||||
if !t.ShouldGenForMethod(file, service, method) { |
||||
continue |
||||
} |
||||
var midwares []string |
||||
comments, _ := t.Reg.MethodComments(file, service, method) |
||||
tags := tag.GetTagsInComment(comments.Leading) |
||||
if tag.GetTagValue("dynamic", tags) == "true" { |
||||
continue |
||||
} |
||||
apiInfo := t.GetHttpInfoCached(file, service, method) |
||||
isLegacyPkg = apiInfo.IsLegacyPath |
||||
//httpMethod, legacyPath, path := getHttpInfo(file, service, method, t.reg)
|
||||
//if legacyPath != "" {
|
||||
// isLegacyPkg = true
|
||||
//}
|
||||
|
||||
midStr := tag.GetTagValue("midware", tags) |
||||
if midStr != "" { |
||||
midwares = strings.Split(midStr, ",") |
||||
for _, m := range midwares { |
||||
allMidwareMap[m] = true |
||||
} |
||||
} |
||||
|
||||
methName := naming.MethodName(method) |
||||
inputType := t.GoTypeName(method.GetInputType()) |
||||
|
||||
routeName := utils.LcFirst(utils.CamelCase(servName) + |
||||
utils.CamelCase(methName)) |
||||
|
||||
methList = append(methList, methodInfo{ |
||||
apiInfo: apiInfo, |
||||
midwares: midwares, |
||||
routeFuncName: routeName, |
||||
methodName: method.GetName(), |
||||
}) |
||||
|
||||
t.P(fmt.Sprintf("func %s (c *bm.Context) {", routeName)) |
||||
t.P(` p := new(`, inputType, `)`) |
||||
requestBinding := "" |
||||
if t.hasHeaderTag(t.Reg.MessageDefinition(method.GetInputType())) { |
||||
requestBinding = ", binding.Request" |
||||
} |
||||
t.P(` if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))` + |
||||
requestBinding + `); err != nil {`) |
||||
t.P(` return`) |
||||
t.P(` }`) |
||||
t.P(` resp, err := `, svcName, `.`, methName, `(c, p)`) |
||||
t.P(` c.JSON(resp, err)`) |
||||
t.P(`}`) |
||||
t.P(``) |
||||
} |
||||
|
||||
// generate route group
|
||||
var midList []string |
||||
for m := range allMidwareMap { |
||||
midList = append(midList, m+" bm.HandlerFunc") |
||||
} |
||||
|
||||
sort.Strings(midList) |
||||
|
||||
// 注册老的路由的方法
|
||||
if isLegacyPkg { |
||||
funcName := `Register` + utils.CamelCase(versionPrefix) + servName + `Service` |
||||
t.P(`// `, funcName, ` Register the blademaster route with middleware map`) |
||||
t.P(`// midMap is the middleware map, the key is defined in proto`) |
||||
t.P(`func `, funcName, `(e *bm.Engine, svc `, servName, "BMServer, midMap map[string]bm.HandlerFunc)", ` {`) |
||||
var keys []string |
||||
for m := range allMidwareMap { |
||||
keys = append(keys, m) |
||||
} |
||||
// to keep generated code consistent
|
||||
sort.Strings(keys) |
||||
for _, m := range keys { |
||||
t.P(m, ` := midMap["`, m, `"]`) |
||||
} |
||||
|
||||
t.P(svcName, ` = svc`) |
||||
for _, methInfo := range methList { |
||||
var midArgStr string |
||||
if len(methInfo.midwares) == 0 { |
||||
midArgStr = "" |
||||
} else { |
||||
midArgStr = strings.Join(methInfo.midwares, ", ") + ", " |
||||
} |
||||
t.P(`e.`, methInfo.apiInfo.HttpMethod, `("`, methInfo.apiInfo.LegacyPath, `", `, midArgStr, methInfo.routeFuncName, `)`) |
||||
} |
||||
t.P(` }`) |
||||
} else { |
||||
// 新的注册路由的方法
|
||||
var bmFuncName = fmt.Sprintf("Register%sBMServer", servName) |
||||
t.P(`// `, bmFuncName, ` Register the blademaster route`) |
||||
t.P(`func `, bmFuncName, `(e *bm.Engine, server `, servName, `BMServer) {`) |
||||
t.P(svcName, ` = server`) |
||||
for _, methInfo := range methList { |
||||
t.P(`e.`, methInfo.apiInfo.HttpMethod, `("`, methInfo.apiInfo.NewPath, `",`, methInfo.routeFuncName, ` )`) |
||||
} |
||||
t.P(` }`) |
||||
} |
||||
} |
||||
|
||||
func (t *bm) hasHeaderTag(md *typemap.MessageDefinition) bool { |
||||
if md.Descriptor.Field == nil { |
||||
return false |
||||
} |
||||
for _, f := range md.Descriptor.Field { |
||||
t := tag.GetMoreTags(f) |
||||
if t != nil { |
||||
st := reflect.StructTag(*t) |
||||
if st.Get("request") != "" { |
||||
return true |
||||
} |
||||
if st.Get("header") != "" { |
||||
return true |
||||
} |
||||
} |
||||
} |
||||
return false |
||||
} |
||||
|
||||
func (t *bm) generateBMInterface(file *descriptor.FileDescriptorProto, service *descriptor.ServiceDescriptorProto) int { |
||||
count := 0 |
||||
servName := naming.ServiceName(service) |
||||
t.P("// " + servName + "BMServer is the server API for " + servName + " service.") |
||||
|
||||
comments, err := t.Reg.ServiceComments(file, service) |
||||
if err == nil { |
||||
t.PrintComments(comments) |
||||
} |
||||
t.P(`type `, servName, `BMServer interface {`) |
||||
for _, method := range service.Method { |
||||
if !t.ShouldGenForMethod(file, service, method) { |
||||
continue |
||||
} |
||||
count++ |
||||
t.generateInterfaceMethod(file, service, method, comments) |
||||
t.P() |
||||
} |
||||
t.P(`}`) |
||||
return count |
||||
} |
||||
|
||||
func (t *bm) generateInterfaceMethod(file *descriptor.FileDescriptorProto, |
||||
service *descriptor.ServiceDescriptorProto, |
||||
method *descriptor.MethodDescriptorProto, |
||||
comments typemap.DefinitionComments) { |
||||
comments, err := t.Reg.MethodComments(file, service, method) |
||||
|
||||
methName := naming.MethodName(method) |
||||
outputType := t.GoTypeName(method.GetOutputType()) |
||||
inputType := t.GoTypeName(method.GetInputType()) |
||||
tags := tag.GetTagsInComment(comments.Leading) |
||||
if tag.GetTagValue("dynamic", tags) == "true" { |
||||
return |
||||
} |
||||
|
||||
if err == nil { |
||||
t.PrintComments(comments) |
||||
} |
||||
|
||||
respDynamic := tag.GetTagValue("dynamic_resp", tags) == "true" |
||||
if respDynamic { |
||||
t.P(fmt.Sprintf(` %s(ctx context.Context, req *%s) (resp interface{}, err error)`, |
||||
methName, inputType)) |
||||
} else { |
||||
t.P(fmt.Sprintf(` %s(ctx context.Context, req *%s) (resp *%s, err error)`, |
||||
methName, inputType, outputType)) |
||||
} |
||||
} |
@ -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 := &bm{} |
||||
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" |
||||
bmgen "github.com/bilibili/kratos/tool/protobuf/protoc-gen-bm/generator" |
||||
) |
||||
|
||||
func main() { |
||||
versionFlag := flag.Bool("version", false, "print version and exit") |
||||
flag.Parse() |
||||
if *versionFlag { |
||||
fmt.Println(generator.Version) |
||||
os.Exit(0) |
||||
} |
||||
|
||||
g := bmgen.BmGenerator() |
||||
gen.Main(g) |
||||
} |
@ -0,0 +1,303 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"net/http" |
||||
"regexp" |
||||
"strings" |
||||
|
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/gen" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/generator" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/naming" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/tag" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/typemap" |
||||
"github.com/golang/protobuf/protoc-gen-go/descriptor" |
||||
plugin "github.com/golang/protobuf/protoc-gen-go/plugin" |
||||
) |
||||
|
||||
type swaggerGen struct { |
||||
generator.Base |
||||
// defsMap will fill into swagger's definitions
|
||||
// key is full qualified proto name
|
||||
defsMap map[string]*typemap.MessageDefinition |
||||
} |
||||
|
||||
// NewSwaggerGenerator a swagger generator
|
||||
func NewSwaggerGenerator() *swaggerGen { |
||||
return &swaggerGen{} |
||||
} |
||||
|
||||
func (t *swaggerGen) Generate(in *plugin.CodeGeneratorRequest) *plugin.CodeGeneratorResponse { |
||||
t.Setup(in) |
||||
resp := &plugin.CodeGeneratorResponse{} |
||||
for _, f := range t.GenFiles { |
||||
if len(f.Service) == 0 { |
||||
continue |
||||
} |
||||
respFile := t.generateSwagger(f) |
||||
if respFile != nil { |
||||
resp.File = append(resp.File, respFile) |
||||
} |
||||
} |
||||
return resp |
||||
} |
||||
|
||||
func (t *swaggerGen) generateSwagger(file *descriptor.FileDescriptorProto) *plugin.CodeGeneratorResponse_File { |
||||
var pkg = file.GetPackage() |
||||
r := regexp.MustCompile("v(\\d+)$") |
||||
strs := r.FindStringSubmatch(pkg) |
||||
var vStr string |
||||
if len(strs) >= 2 { |
||||
vStr = strs[1] |
||||
} else { |
||||
vStr = "" |
||||
} |
||||
var swaggerObj = &swaggerObject{ |
||||
Paths: swaggerPathsObject{}, |
||||
Swagger: "2.0", |
||||
Info: swaggerInfoObject{ |
||||
Title: file.GetName(), |
||||
Version: vStr, |
||||
}, |
||||
Schemes: []string{"http", "https"}, |
||||
Consumes: []string{"application/json", "multipart/form-data"}, |
||||
Produces: []string{"application/json"}, |
||||
} |
||||
t.defsMap = map[string]*typemap.MessageDefinition{} |
||||
|
||||
out := &plugin.CodeGeneratorResponse_File{} |
||||
name := naming.GoFileName(file, ".swagger.json") |
||||
for _, svc := range file.Service { |
||||
for _, meth := range svc.Method { |
||||
if !t.ShouldGenForMethod(file, svc, meth) { |
||||
continue |
||||
} |
||||
apiInfo := t.GetHttpInfoCached(file, svc, meth) |
||||
pathItem := swaggerPathItemObject{} |
||||
|
||||
op := t.getOperationByHTTPMethod(apiInfo.HttpMethod, &pathItem) |
||||
op.Summary = apiInfo.Title |
||||
op.Description = apiInfo.Description |
||||
swaggerObj.Paths[apiInfo.Path] = pathItem |
||||
op.Tags = []string{pkg + "." + svc.GetName()} |
||||
|
||||
// request
|
||||
request := t.Reg.MessageDefinition(meth.GetInputType()) |
||||
// request cannot represent by simple form
|
||||
isComplexRequest := false |
||||
for _, field := range request.Descriptor.Field { |
||||
if !generator.IsScalar(field) { |
||||
isComplexRequest = true |
||||
break |
||||
} |
||||
} |
||||
if !isComplexRequest && apiInfo.HttpMethod == "GET" { |
||||
for _, field := range request.Descriptor.Field { |
||||
if !generator.IsScalar(field) { |
||||
continue |
||||
} |
||||
p := t.getQueryParameter(file, request, field) |
||||
op.Parameters = append(op.Parameters, p) |
||||
} |
||||
} else { |
||||
p := swaggerParameterObject{} |
||||
p.In = "body" |
||||
p.Required = true |
||||
p.Name = "body" |
||||
p.Schema = &swaggerSchemaObject{} |
||||
p.Schema.Ref = "#/definitions/" + meth.GetInputType() |
||||
op.Parameters = []swaggerParameterObject{p} |
||||
} |
||||
|
||||
// response
|
||||
resp := swaggerResponseObject{} |
||||
resp.Description = "A successful response." |
||||
|
||||
// proto 里面的response只定义data里面的
|
||||
// 所以需要把code msg data 这一级加上
|
||||
resp.Schema.Type = "object" |
||||
resp.Schema.Properties = &swaggerSchemaObjectProperties{} |
||||
p := keyVal{Key: "code", Value: &schemaCore{Type: "integer"}} |
||||
*resp.Schema.Properties = append(*resp.Schema.Properties, p) |
||||
p = keyVal{Key: "message", Value: &schemaCore{Type: "string"}} |
||||
*resp.Schema.Properties = append(*resp.Schema.Properties, p) |
||||
p = keyVal{Key: "data", Value: schemaCore{Ref: "#/definitions/" + meth.GetOutputType()}} |
||||
*resp.Schema.Properties = append(*resp.Schema.Properties, p) |
||||
op.Responses = swaggerResponsesObject{"200": resp} |
||||
} |
||||
} |
||||
|
||||
// walk though definitions
|
||||
t.walkThroughFileDefinition(file) |
||||
defs := swaggerDefinitionsObject{} |
||||
swaggerObj.Definitions = defs |
||||
for typ, msg := range t.defsMap { |
||||
def := swaggerSchemaObject{} |
||||
def.Properties = new(swaggerSchemaObjectProperties) |
||||
def.Description = strings.Trim(msg.Comments.Leading, "\n\r ") |
||||
for _, field := range msg.Descriptor.Field { |
||||
p := keyVal{Key: generator.GetFormOrJSONName(field)} |
||||
schema := t.schemaForField(file, msg, field) |
||||
if generator.GetFieldRequired(field, t.Reg, msg) { |
||||
def.Required = append(def.Required, p.Key) |
||||
} |
||||
p.Value = schema |
||||
*def.Properties = append(*def.Properties, p) |
||||
} |
||||
def.Type = "object" |
||||
defs[typ] = def |
||||
} |
||||
b, _ := json.MarshalIndent(swaggerObj, "", " ") |
||||
str := string(b) |
||||
out.Name = &name |
||||
out.Content = &str |
||||
return out |
||||
} |
||||
|
||||
func (t *swaggerGen) getOperationByHTTPMethod(httpMethod string, pathItem *swaggerPathItemObject) *swaggerOperationObject { |
||||
var op = &swaggerOperationObject{} |
||||
switch httpMethod { |
||||
case http.MethodGet: |
||||
pathItem.Get = op |
||||
case http.MethodPost: |
||||
pathItem.Post = op |
||||
case http.MethodPut: |
||||
pathItem.Put = op |
||||
case http.MethodDelete: |
||||
pathItem.Put = op |
||||
case http.MethodPatch: |
||||
pathItem.Patch = op |
||||
default: |
||||
pathItem.Get = op |
||||
} |
||||
return op |
||||
} |
||||
|
||||
func (t *swaggerGen) getQueryParameter(file *descriptor.FileDescriptorProto, |
||||
input *typemap.MessageDefinition, |
||||
field *descriptor.FieldDescriptorProto) swaggerParameterObject { |
||||
p := swaggerParameterObject{} |
||||
p.Name = generator.GetFormOrJSONName(field) |
||||
fComment, _ := t.Reg.FieldComments(input, field) |
||||
cleanComment := tag.GetCommentWithoutTag(fComment.Leading) |
||||
|
||||
p.Description = strings.Trim(strings.Join(cleanComment, "\n"), "\n\r ") |
||||
p.In = "query" |
||||
p.Required = generator.GetFieldRequired(field, t.Reg, input) |
||||
typ, isArray, format := getFieldSwaggerType(field) |
||||
if isArray { |
||||
p.Items = &swaggerItemsObject{} |
||||
p.Type = "array" |
||||
p.Items.Type = typ |
||||
p.Items.Format = format |
||||
} else { |
||||
p.Type = typ |
||||
p.Format = format |
||||
} |
||||
return p |
||||
} |
||||
|
||||
func (t *swaggerGen) schemaForField(file *descriptor.FileDescriptorProto, |
||||
msg *typemap.MessageDefinition, |
||||
field *descriptor.FieldDescriptorProto) swaggerSchemaObject { |
||||
schema := swaggerSchemaObject{} |
||||
fComment, err := t.Reg.FieldComments(msg, field) |
||||
if err != nil { |
||||
gen.Error(err, "comment not found err %+v") |
||||
} |
||||
schema.Description = strings.Trim(fComment.Leading, "\n\r ") |
||||
typ, isArray, format := getFieldSwaggerType(field) |
||||
if !generator.IsScalar(field) { |
||||
if generator.IsMap(field, t.Reg) { |
||||
schema.Type = "object" |
||||
mapMsg := t.Reg.MessageDefinition(field.GetTypeName()) |
||||
mapValueField := mapMsg.Descriptor.Field[1] |
||||
valSchema := t.schemaForField(file, mapMsg, mapValueField) |
||||
schema.AdditionalProperties = &valSchema |
||||
} else { |
||||
if isArray { |
||||
schema.Items = &swaggerItemsObject{} |
||||
schema.Type = "array" |
||||
schema.Items.Ref = "#/definitions/" + field.GetTypeName() |
||||
} else { |
||||
schema.Ref = "#/definitions/" + field.GetTypeName() |
||||
} |
||||
} |
||||
} else { |
||||
if isArray { |
||||
schema.Items = &swaggerItemsObject{} |
||||
schema.Type = "array" |
||||
schema.Items.Type = typ |
||||
schema.Items.Format = format |
||||
} else { |
||||
schema.Type = typ |
||||
schema.Format = format |
||||
} |
||||
} |
||||
return schema |
||||
} |
||||
|
||||
func (t *swaggerGen) walkThroughFileDefinition(file *descriptor.FileDescriptorProto) { |
||||
for _, svc := range file.Service { |
||||
for _, meth := range svc.Method { |
||||
shouldGen := t.ShouldGenForMethod(file, svc, meth) |
||||
if !shouldGen { |
||||
continue |
||||
} |
||||
t.walkThroughMessages(t.Reg.MessageDefinition(meth.GetOutputType())) |
||||
t.walkThroughMessages(t.Reg.MessageDefinition(meth.GetInputType())) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (t *swaggerGen) walkThroughMessages(msg *typemap.MessageDefinition) { |
||||
_, ok := t.defsMap[msg.ProtoName()] |
||||
if ok { |
||||
return |
||||
} |
||||
if !msg.Descriptor.GetOptions().GetMapEntry() { |
||||
t.defsMap[msg.ProtoName()] = msg |
||||
} |
||||
for _, field := range msg.Descriptor.Field { |
||||
if field.GetType() == descriptor.FieldDescriptorProto_TYPE_MESSAGE { |
||||
t.walkThroughMessages(t.Reg.MessageDefinition(field.GetTypeName())) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func getFieldSwaggerType(field *descriptor.FieldDescriptorProto) (typeName string, isArray bool, formatName string) { |
||||
typeName = "unknown" |
||||
switch field.GetType() { |
||||
case descriptor.FieldDescriptorProto_TYPE_BOOL: |
||||
typeName = "boolean" |
||||
case descriptor.FieldDescriptorProto_TYPE_DOUBLE: |
||||
typeName = "number" |
||||
formatName = "double" |
||||
case descriptor.FieldDescriptorProto_TYPE_FLOAT: |
||||
typeName = "number" |
||||
formatName = "float" |
||||
case |
||||
descriptor.FieldDescriptorProto_TYPE_INT64, |
||||
descriptor.FieldDescriptorProto_TYPE_UINT64, |
||||
descriptor.FieldDescriptorProto_TYPE_INT32, |
||||
descriptor.FieldDescriptorProto_TYPE_FIXED64, |
||||
descriptor.FieldDescriptorProto_TYPE_FIXED32, |
||||
descriptor.FieldDescriptorProto_TYPE_ENUM, |
||||
descriptor.FieldDescriptorProto_TYPE_UINT32, |
||||
descriptor.FieldDescriptorProto_TYPE_SFIXED32, |
||||
descriptor.FieldDescriptorProto_TYPE_SFIXED64, |
||||
descriptor.FieldDescriptorProto_TYPE_SINT32, |
||||
descriptor.FieldDescriptorProto_TYPE_SINT64: |
||||
typeName = "integer" |
||||
case |
||||
descriptor.FieldDescriptorProto_TYPE_STRING, |
||||
descriptor.FieldDescriptorProto_TYPE_BYTES: |
||||
typeName = "string" |
||||
case descriptor.FieldDescriptorProto_TYPE_MESSAGE: |
||||
typeName = "object" |
||||
} |
||||
if field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { |
||||
isArray = true |
||||
} |
||||
return |
||||
} |
@ -0,0 +1,22 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"flag" |
||||
"fmt" |
||||
"os" |
||||
|
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/gen" |
||||
"github.com/bilibili/kratos/tool/protobuf/pkg/generator" |
||||
) |
||||
|
||||
func main() { |
||||
versionFlag := flag.Bool("version", false, "print version and exit") |
||||
flag.Parse() |
||||
if *versionFlag { |
||||
fmt.Println(generator.Version) |
||||
os.Exit(0) |
||||
} |
||||
|
||||
g := NewSwaggerGenerator() |
||||
gen.Main(g) |
||||
} |
@ -0,0 +1,218 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
) |
||||
|
||||
// http://swagger.io/specification/#infoObject
|
||||
type swaggerInfoObject struct { |
||||
Title string `json:"title"` |
||||
Description string `json:"description,omitempty"` |
||||
TermsOfService string `json:"termsOfService,omitempty"` |
||||
Version string `json:"version"` |
||||
|
||||
Contact *swaggerContactObject `json:"contact,omitempty"` |
||||
License *swaggerLicenseObject `json:"license,omitempty"` |
||||
} |
||||
|
||||
// http://swagger.io/specification/#contactObject
|
||||
type swaggerContactObject struct { |
||||
Name string `json:"name,omitempty"` |
||||
URL string `json:"url,omitempty"` |
||||
Email string `json:"email,omitempty"` |
||||
} |
||||
|
||||
// http://swagger.io/specification/#licenseObject
|
||||
type swaggerLicenseObject struct { |
||||
Name string `json:"name,omitempty"` |
||||
URL string `json:"url,omitempty"` |
||||
} |
||||
|
||||
// http://swagger.io/specification/#externalDocumentationObject
|
||||
type swaggerExternalDocumentationObject struct { |
||||
Description string `json:"description,omitempty"` |
||||
URL string `json:"url,omitempty"` |
||||
} |
||||
|
||||
// http://swagger.io/specification/#swaggerObject
|
||||
type swaggerObject struct { |
||||
Swagger string `json:"swagger"` |
||||
Info swaggerInfoObject `json:"info"` |
||||
Host string `json:"host,omitempty"` |
||||
BasePath string `json:"basePath,omitempty"` |
||||
Schemes []string `json:"schemes"` |
||||
Consumes []string `json:"consumes"` |
||||
Produces []string `json:"produces"` |
||||
Paths swaggerPathsObject `json:"paths"` |
||||
Definitions swaggerDefinitionsObject `json:"definitions"` |
||||
StreamDefinitions swaggerDefinitionsObject `json:"x-stream-definitions,omitempty"` |
||||
SecurityDefinitions swaggerSecurityDefinitionsObject `json:"securityDefinitions,omitempty"` |
||||
Security []swaggerSecurityRequirementObject `json:"security,omitempty"` |
||||
ExternalDocs *swaggerExternalDocumentationObject `json:"externalDocs,omitempty"` |
||||
} |
||||
|
||||
// http://swagger.io/specification/#securityDefinitionsObject
|
||||
type swaggerSecurityDefinitionsObject map[string]swaggerSecuritySchemeObject |
||||
|
||||
// http://swagger.io/specification/#securitySchemeObject
|
||||
type swaggerSecuritySchemeObject struct { |
||||
Type string `json:"type"` |
||||
Description string `json:"description,omitempty"` |
||||
Name string `json:"name,omitempty"` |
||||
In string `json:"in,omitempty"` |
||||
Flow string `json:"flow,omitempty"` |
||||
AuthorizationURL string `json:"authorizationUrl,omitempty"` |
||||
TokenURL string `json:"tokenUrl,omitempty"` |
||||
Scopes swaggerScopesObject `json:"scopes,omitempty"` |
||||
} |
||||
|
||||
// http://swagger.io/specification/#scopesObject
|
||||
type swaggerScopesObject map[string]string |
||||
|
||||
// http://swagger.io/specification/#securityRequirementObject
|
||||
type swaggerSecurityRequirementObject map[string][]string |
||||
|
||||
// http://swagger.io/specification/#pathsObject
|
||||
type swaggerPathsObject map[string]swaggerPathItemObject |
||||
|
||||
// http://swagger.io/specification/#pathItemObject
|
||||
type swaggerPathItemObject struct { |
||||
Get *swaggerOperationObject `json:"get,omitempty"` |
||||
Delete *swaggerOperationObject `json:"delete,omitempty"` |
||||
Post *swaggerOperationObject `json:"post,omitempty"` |
||||
Put *swaggerOperationObject `json:"put,omitempty"` |
||||
Patch *swaggerOperationObject `json:"patch,omitempty"` |
||||
} |
||||
|
||||
// http://swagger.io/specification/#operationObject
|
||||
type swaggerOperationObject struct { |
||||
Summary string `json:"summary,omitempty"` |
||||
Description string `json:"description,omitempty"` |
||||
OperationID string `json:"operationId,omitempty"` |
||||
Responses swaggerResponsesObject `json:"responses"` |
||||
Parameters swaggerParametersObject `json:"parameters,omitempty"` |
||||
Tags []string `json:"tags,omitempty"` |
||||
Deprecated bool `json:"deprecated,omitempty"` |
||||
|
||||
Security *[]swaggerSecurityRequirementObject `json:"security,omitempty"` |
||||
ExternalDocs *swaggerExternalDocumentationObject `json:"externalDocs,omitempty"` |
||||
} |
||||
|
||||
type swaggerParametersObject []swaggerParameterObject |
||||
|
||||
// http://swagger.io/specification/#parameterObject
|
||||
type swaggerParameterObject struct { |
||||
Name string `json:"name"` |
||||
Description string `json:"description,omitempty"` |
||||
In string `json:"in,omitempty"` |
||||
Required bool `json:"required"` |
||||
Type string `json:"type,omitempty"` |
||||
Format string `json:"format,omitempty"` |
||||
Items *swaggerItemsObject `json:"items,omitempty"` |
||||
Enum []string `json:"enum,omitempty"` |
||||
CollectionFormat string `json:"collectionFormat,omitempty"` |
||||
Default string `json:"default,omitempty"` |
||||
MinItems *int `json:"minItems,omitempty"` |
||||
|
||||
// Or you can explicitly refer to another type. If this is defined all
|
||||
// other fields should be empty
|
||||
Schema *swaggerSchemaObject `json:"schema,omitempty"` |
||||
} |
||||
|
||||
// core part of schema, which is common to itemsObject and schemaObject.
|
||||
// http://swagger.io/specification/#itemsObject
|
||||
type schemaCore struct { |
||||
Type string `json:"type,omitempty"` |
||||
Format string `json:"format,omitempty"` |
||||
Ref string `json:"$ref,omitempty"` |
||||
Example json.RawMessage `json:"example,omitempty"` |
||||
|
||||
Items *swaggerItemsObject `json:"items,omitempty"` |
||||
|
||||
// If the item is an enumeration include a list of all the *NAMES* of the
|
||||
// enum values. I'm not sure how well this will work but assuming all enums
|
||||
// start from 0 index it will be great. I don't think that is a good assumption.
|
||||
Enum []string `json:"enum,omitempty"` |
||||
Default string `json:"default,omitempty"` |
||||
} |
||||
|
||||
type swaggerItemsObject schemaCore |
||||
|
||||
func (o *swaggerItemsObject) getType() string { |
||||
if o == nil { |
||||
return "" |
||||
} |
||||
return o.Type |
||||
} |
||||
|
||||
// http://swagger.io/specification/#responsesObject
|
||||
type swaggerResponsesObject map[string]swaggerResponseObject |
||||
|
||||
// http://swagger.io/specification/#responseObject
|
||||
type swaggerResponseObject struct { |
||||
Description string `json:"description"` |
||||
Schema swaggerSchemaObject `json:"schema"` |
||||
} |
||||
|
||||
type keyVal struct { |
||||
Key string |
||||
Value interface{} |
||||
} |
||||
|
||||
type swaggerSchemaObjectProperties []keyVal |
||||
|
||||
func (op swaggerSchemaObjectProperties) MarshalJSON() ([]byte, error) { |
||||
var buf bytes.Buffer |
||||
buf.WriteString("{") |
||||
for i, kv := range op { |
||||
if i != 0 { |
||||
buf.WriteString(",") |
||||
} |
||||
key, err := json.Marshal(kv.Key) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
buf.Write(key) |
||||
buf.WriteString(":") |
||||
val, err := json.Marshal(kv.Value) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
buf.Write(val) |
||||
} |
||||
|
||||
buf.WriteString("}") |
||||
return buf.Bytes(), nil |
||||
} |
||||
|
||||
// http://swagger.io/specification/#schemaObject
|
||||
type swaggerSchemaObject struct { |
||||
schemaCore |
||||
// Properties can be recursively defined
|
||||
Properties *swaggerSchemaObjectProperties `json:"properties,omitempty"` |
||||
AdditionalProperties *swaggerSchemaObject `json:"additionalProperties,omitempty"` |
||||
|
||||
Description string `json:"description,omitempty"` |
||||
Title string `json:"title,omitempty"` |
||||
|
||||
ExternalDocs *swaggerExternalDocumentationObject `json:"externalDocs,omitempty"` |
||||
|
||||
MultipleOf float64 `json:"multipleOf,omitempty"` |
||||
Maximum float64 `json:"maximum,omitempty"` |
||||
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"` |
||||
Minimum float64 `json:"minimum,omitempty"` |
||||
ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"` |
||||
MaxLength uint64 `json:"maxLength,omitempty"` |
||||
MinLength uint64 `json:"minLength,omitempty"` |
||||
Pattern string `json:"pattern,omitempty"` |
||||
MaxItems uint64 `json:"maxItems,omitempty"` |
||||
MinItems uint64 `json:"minItems,omitempty"` |
||||
UniqueItems bool `json:"uniqueItems,omitempty"` |
||||
MaxProperties uint64 `json:"maxProperties,omitempty"` |
||||
MinProperties uint64 `json:"minProperties,omitempty"` |
||||
Required []string `json:"required,omitempty"` |
||||
} |
||||
|
||||
// http://swagger.io/specification/#definitionsObject
|
||||
type swaggerDefinitionsObject map[string]swaggerSchemaObject |
Loading…
Reference in new issue