Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

41
app/tool/BUILD Normal file
View File

@@ -0,0 +1,41 @@
package(default_visibility = ["//visibility:public"])
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/tool/bgr:all-srcs",
"//app/tool/bmproto/bmgen:all-srcs",
"//app/tool/bmproto/protoc-gen-bm:all-srcs",
"//app/tool/cache:all-srcs",
"//app/tool/ci:all-srcs",
"//app/tool/creator:all-srcs",
"//app/tool/gdoc:all-srcs",
"//app/tool/gengo/args:all-srcs",
"//app/tool/gengo/cmd/deepcopy-gen:all-srcs",
"//app/tool/gengo/generator:all-srcs",
"//app/tool/gengo/namer:all-srcs",
"//app/tool/gengo/parser:all-srcs",
"//app/tool/gengo/testdata/a:all-srcs",
"//app/tool/gengo/testdata/fake/dep:all-srcs",
"//app/tool/gengo/types:all-srcs",
"//app/tool/gorpc:all-srcs",
"//app/tool/grpc-http-proxy:all-srcs",
"//app/tool/kratos:all-srcs",
"//app/tool/liverpc/liverpcgen:all-srcs",
"//app/tool/liverpc/protoc-gen-liverpc:all-srcs",
"//app/tool/mkprow:all-srcs",
"//app/tool/owner:all-srcs",
"//app/tool/protoc-gen-bm:all-srcs",
"//app/tool/saga:all-srcs",
"//app/tool/warden:all-srcs",
],
tags = ["automanaged"],
)

10
app/tool/OWNERS Normal file
View File

@@ -0,0 +1,10 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- haoguanwei
- maojian
labels:
- new-project
- tool
options:
no_parent_owners: true

58
app/tool/bgr/BUILD Normal file
View File

@@ -0,0 +1,58 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
"go_binary",
)
go_test(
name = "go_default_test",
srcs = ["bgl_test.go"],
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = [
"ast_inspect.go",
"cache.go",
"file_filter.go",
"lint_register.go",
"main.go",
"model.go",
"script_parser.go",
],
importpath = "go-common/app/tool/bgr",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/tool/bgr/log:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/tool/bgr/log:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_binary(
name = "bgr",
embed = [":go_default_library"],
tags = ["automanaged"],
)

View File

@@ -0,0 +1,5 @@
# v1.0.1
1. 修复depend package寻址失败的问题
# v1.0.0
1. golang syntax 检查规则解释器

View File

@@ -0,0 +1,8 @@
# Owner
muyang
# Author
muyang
# Reviewer
muyang

10
app/tool/bgr/OWNERS Normal file
View File

@@ -0,0 +1,10 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- muyang
labels:
- tool
options:
no_parent_owners: true
reviewers:
- muyang

14
app/tool/bgr/README.md Normal file
View File

@@ -0,0 +1,14 @@
# bgr (bili golang rule)
## 项目简介
golang syntax 检查规则解释器
## 编译环境
golang >= 1.8
## 依赖包
github.com/pkg/errors
go stdlib
## 编译执行
go build

16
app/tool/bgr/RULE.bgl Normal file
View File

@@ -0,0 +1,16 @@
// 请填写禁止规则
T expr.call.decl.comment
V (?im)^\s*deprecated
L e
D 禁止调用Deprecated方法
T stmt.label
V .*
L w
D 请谨慎使用Label
//T decl.func.comment
//V Deprecated
//L w
//D 禁止声明Deprecated方法

View File

@@ -0,0 +1,91 @@
package main
import (
"fmt"
"go/ast"
"go/build"
"go/parser"
"go/token"
"path/filepath"
"github.com/pkg/errors"
)
var (
_defaultFileFilter = FilterOnlyCodeFile
_errors = make([]string, 0)
_warns = make([]string, 0)
)
// AstInspect .
func AstInspect(dir string) (err error) {
var (
files []*ast.File
fset *token.FileSet
)
if dir, err = filepath.Abs(dir); err != nil {
err = errors.WithStack(err)
return
}
if files, fset, err = parsePackageFiles(dir); err != nil {
return
}
for _, f := range files {
handler := defaultNodeHandler(f, dir, fset)
ast.Inspect(f, handler)
}
return
}
func defaultNodeHandler(f *ast.File, dir string, fileset *token.FileSet) func(ast.Node) bool {
return func(node ast.Node) bool {
if node == nil {
return false
}
for _, l := range _lints {
if !l.fn(dir, f, node) {
switch l.s.l {
case "e":
_errors = append(_errors, fmt.Sprintf("%s --> %s", fileset.PositionFor(node.Pos(), true), l.s.d))
case "w":
_warns = append(_warns, fmt.Sprintf("%s --> %s", fileset.PositionFor(node.Pos(), true), l.s.d))
}
}
}
return true
}
}
func parsePackageFilesByPath(dir string, importPath string) (files []*ast.File, fset *token.FileSet, err error) {
var pkg *build.Package
if pkg, err = build.Import(importPath, dir, build.FindOnly); err != nil {
return
}
return parsePackageFiles(pkg.Dir)
}
func parsePackageFiles(absDir string) (files []*ast.File, fset *token.FileSet, err error) {
var ok bool
if files, fset, ok = packageCache(absDir); ok {
return
}
defer func() {
setPackageCache(absDir, fset, files)
}()
fset = token.NewFileSet()
var (
pkgMap map[string]*ast.Package
)
if pkgMap, err = parser.ParseDir(fset, absDir, _defaultFileFilter, parser.ParseComments); err != nil {
err = errors.WithStack(err)
return
}
for _, v := range pkgMap {
for _, f := range v.Files {
files = append(files, f)
}
}
return
}

9
app/tool/bgr/bgl_test.go Normal file
View File

@@ -0,0 +1,9 @@
package main
import (
"testing"
)
func TestComment(t *testing.T) {
}

28
app/tool/bgr/cache.go Normal file
View File

@@ -0,0 +1,28 @@
package main
import (
"go/ast"
"go/token"
)
var (
_packageCache = make(map[string]*pkgC)
)
type pkgC struct {
files []*ast.File
fset *token.FileSet
}
func packageCache(dir string) (files []*ast.File, fset *token.FileSet, ok bool) {
c, ok := _packageCache[dir]
if ok {
files = c.files
fset = c.fset
}
return
}
func setPackageCache(dir string, fset *token.FileSet, files []*ast.File) {
_packageCache[dir] = &pkgC{fset: fset, files: files}
}

View File

@@ -0,0 +1,22 @@
package main
import (
"os"
"strings"
)
// FilterOnlyCodeFile .
var FilterOnlyCodeFile = func(f os.FileInfo) bool {
if strings.HasSuffix(f.Name(), "_test.go") {
return false
}
if strings.HasSuffix(f.Name(), ".go") {
return true
}
return false
}
// FilterOnlyTestFile .
var FilterOnlyTestFile = func(f os.FileInfo) bool {
return strings.HasSuffix(f.Name(), "_test.go")
}

View File

@@ -0,0 +1,132 @@
package main
import (
"fmt"
"go/ast"
"strings"
)
var (
_parsers = make(map[string]func(curDir string, f *ast.File, n ast.Node) (v string, hit bool))
)
func init() {
// 函数定义注释
_parsers["decl.func.comment"] = func(curDir string, f *ast.File, n ast.Node) (v string, hit bool) {
var ele *ast.FuncDecl
if ele, hit = n.(*ast.FuncDecl); !hit {
return
}
v = ele.Doc.Text()
return
}
// 标签语句
_parsers["stmt.label"] = func(curDir string, f *ast.File, n ast.Node) (v string, hit bool) {
var ele *ast.LabeledStmt
if ele, hit = n.(*ast.LabeledStmt); !hit {
return
}
v = ele.Label.Name
return
}
// 调用函数的定义注释
_parsers["expr.call.decl.comment"] = func(curDir string, f *ast.File, n ast.Node) (v string, hit bool) {
var ele *ast.CallExpr
if ele, hit = n.(*ast.CallExpr); !hit {
return
}
var (
files []*ast.File
declName string
err error
doc *ast.CommentGroup
)
switch ele2 := ele.Fun.(type) {
case *ast.SelectorExpr: // like a.b()
for _, impt := range f.Imports {
if fmt.Sprintf("%s", ele2.X) == importName(impt) {
var imptPath = strings.Trim(impt.Path.Value, `"`)
if files, _, err = parsePackageFilesByPath(curDir, imptPath); err != nil {
_log.Debugf("parsePackageFiles err: %+v", err)
continue
}
declName = ele2.Sel.Name
}
}
case *ast.Ident: // like a()
if files, _, err = parsePackageFiles(curDir); err != nil {
_log.Debugf("parsePackageFiles err: %+v", err)
return
}
declName = ele2.Name
}
doc = declDocFromFiles(files, declName)
if doc != nil {
v = doc.Text()
}
return
}
// struct定义方法列表
// _parsers["decl.gen.decl.method"] = func(curDir string, f *ast.File, n ast.Node) (v string, hit bool) {
// var ele *ast.GenDecl
// if ele, hit = n.(*ast.GenDecl); !hit {
// return
// }
// switch ele.Tok {
// case token.DEFINE, token.VAR:
// for _, spec := range ele.Specs {
// ele2, ok := spec.(*ast.ValueSpec)
// if !ok {
// _log.Debugf("spec: %T %+v can't convert to *ast.ValueSpec")
// continue
// }
// switch ele3 := ele2.Type.(type) {
// case *ast.CallExpr:
// ele3.Fun.()
// }
// }
// default:
// hit = false
// return
// }
// }
}
func importName(impt *ast.ImportSpec) string {
if impt.Name != nil {
return impt.Name.Name
}
sep := strings.Split(strings.Trim(impt.Path.Value, `"`), "/")
return sep[len(sep)-1]
}
func declDocFromFiles(files []*ast.File, declName string) (doc *ast.CommentGroup) {
for _, f := range files {
for _, fd := range f.Decls {
switch decl := fd.(type) {
case *ast.FuncDecl: // like func a(){}
if decl.Name.Name == declName {
return decl.Doc
}
case *ast.GenDecl: // like var a int = 0
for _, s := range decl.Specs {
switch spec := s.(type) {
case *ast.ValueSpec:
for _, specName := range spec.Names {
if specName.Name == declName {
return spec.Doc
}
}
}
}
default:
_log.Debugf("decl(%+v,%s) unknown fDecl.(type): %T %+v", files, declName, decl, decl)
}
}
}
return
}

35
app/tool/bgr/log/BUILD Normal file
View File

@@ -0,0 +1,35 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["log.go"],
importpath = "go-common/app/tool/bgr/log",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/tool/bgr/log/color:go_default_library",
"//vendor/golang.org/x/crypto/ssh/terminal:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/tool/bgr/log/color:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,28 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["color.go"],
importpath = "go-common/app/tool/bgr/log/color",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,51 @@
package colorful
const (
colorOff = string("\033[0m")
colorRed = string("\033[0;31m")
colorGreen = string("\033[0;32m")
colorOrange = string("\033[0;33m")
colorBlue = string("\033[0;34m")
colorPurple = string("\033[0;35m")
colorCyan = string("\033[0;36m")
colorGray = string("\033[0;37m")
)
func paint(data string, color string) string {
return color + data + colorOff
}
// Red draw red on data
func Red(data string) string {
return paint(data, colorRed)
}
// Green draw Green on data
func Green(data string) string {
return paint(data, colorGreen)
}
// Orange draw Orange on data
func Orange(data string) string {
return paint(data, colorOrange)
}
// Blue draw Blue on data
func Blue(data string) string {
return paint(data, colorBlue)
}
// Purple draw Purple on data
func Purple(data string) string {
return paint(data, colorPurple)
}
// Cyan draw Cyan on data
func Cyan(data string) string {
return paint(data, colorCyan)
}
// Gray draw Gray on data
func Gray(data string) string {
return paint(data, colorGray)
}

160
app/tool/bgr/log/log.go Normal file
View File

@@ -0,0 +1,160 @@
package log
import (
"fmt"
"io"
"os"
"strings"
"sync"
"go-common/app/tool/bgr/log/color"
"golang.org/x/crypto/ssh/terminal"
)
// FDWriter interface extends io.Writer with file descriptor function
type FDWriter interface {
io.Writer
Fd() uintptr
}
// Logger struct definition
type Logger struct {
mu sync.RWMutex
out FDWriter
color bool
debug bool
buf strings.Builder
}
type prefix struct {
Plain string
Color string
}
const (
_plainError = "[ ERROR ] "
_plainWarn = "[ WARN ] "
_plainInfo = "[ INFO ] "
_plainDebug = "[ DEBUG ] "
_plainFatal = "[ FATAL ] "
)
var (
_prefixError = prefix{
Plain: _plainError,
Color: colorful.Red(_plainError),
}
_prefixWarn = prefix{
Plain: _plainWarn,
Color: colorful.Orange(_plainWarn),
}
_prefixInfo = prefix{
Plain: _plainInfo,
Color: colorful.Green(_plainInfo),
}
_prefixDebug = prefix{
Plain: _plainDebug,
Color: colorful.Purple(_plainDebug),
}
_prefixFatal = prefix{
Plain: _plainFatal,
Color: colorful.Gray(_plainFatal),
}
)
// New returns new Logger instance with predefined writer output and
// automatically detect terminal coloring support
func New(out FDWriter, debug bool) *Logger {
return &Logger{
color: terminal.IsTerminal(int(out.Fd())),
out: out,
debug: debug,
buf: strings.Builder{},
}
}
func (l *Logger) output(prefix prefix, data string) (err error) {
l.mu.Lock()
defer l.mu.Unlock()
l.buf.Reset()
if l.color {
if _, err = l.buf.WriteString(prefix.Color); err != nil {
return
}
} else {
if _, err = l.buf.WriteString(prefix.Plain); err != nil {
return
}
}
if _, err = l.buf.WriteString(data); err != nil {
return
}
if data[len(data)-1] != '\n' {
l.buf.WriteString("\n")
}
_, err = l.out.Write([]byte(l.buf.String()))
return
}
// Error print error message to output
func (l *Logger) Error(v ...interface{}) {
l.output(_prefixError, fmt.Sprintln(v...))
}
// Errorf print formatted error message to output
func (l *Logger) Errorf(format string, v ...interface{}) {
l.output(_prefixError, fmt.Sprintf(format, v...))
}
// Warn print warning message to output
func (l *Logger) Warn(v ...interface{}) {
l.output(_prefixWarn, fmt.Sprintln(v...))
}
// Warnf print formatted warning message to output
func (l *Logger) Warnf(format string, v ...interface{}) {
l.output(_prefixWarn, fmt.Sprintf(format, v...))
}
// Info print informational message to output
func (l *Logger) Info(v ...interface{}) {
l.output(_prefixInfo, fmt.Sprintln(v...))
}
// Infof print formatted informational message to output
func (l *Logger) Infof(format string, v ...interface{}) {
l.output(_prefixInfo, fmt.Sprintf(format, v...))
}
// Debug print debug message to output if debug output enabled
func (l *Logger) Debug(v ...interface{}) {
if l.debug {
l.output(_prefixDebug, fmt.Sprintln(v...))
}
}
// Debugf print formatted debug message to output if debug output enabled
func (l *Logger) Debugf(format string, v ...interface{}) {
if l.debug {
l.output(_prefixDebug, fmt.Sprintf(format, v...))
}
}
// Fatal print fatal message to output and then exit(1)
func (l *Logger) Fatal(v ...interface{}) {
l.output(_prefixFatal, fmt.Sprintln(v...))
os.Exit(1)
}
// Fatalf print formatted fatal message to output and then exit(1)
func (l *Logger) Fatalf(format string, v ...interface{}) {
l.output(_prefixFatal, fmt.Sprintf(format, v...))
os.Exit(1)
}

103
app/tool/bgr/main.go Normal file
View File

@@ -0,0 +1,103 @@
package main
import (
"flag"
"os"
"path/filepath"
"strings"
"go-common/app/tool/bgr/log"
)
var (
_flagType string
_flagScript string
_flagDebug bool
_flagHit string
_log *log.Logger
)
func init() {
flag.StringVar(&_flagType, "type", "file", "args type, file or dir")
flag.StringVar(&_flagScript, "script", defaultDir(), "input script dir")
flag.BoolVar(&_flagDebug, "debug", false, "set true, if need print debug info")
flag.StringVar(&_flagHit, "hit", "", "filter hit key")
flag.Parse()
_log = log.New(os.Stdout, _flagDebug)
}
func defaultDir() string {
dir, err := os.Getwd()
if err != nil {
panic(err)
}
return dir
}
func main() {
targets := flag.Args()
switch _flagType {
case "file":
targets = filterFiles(targets)
targets = combineDirs(targets)
}
_log.Debugf("check targets: %+v", targets)
walkScript(_flagScript)
for _, dir := range targets {
if strings.HasSuffix(dir, "...") {
walkDir(strings.TrimRight(dir, "..."))
} else {
if err := AstInspect(dir); err != nil {
_log.Fatalf("%+v", err)
}
}
}
for _, desc := range _warns {
_log.Warn(desc)
}
for _, desc := range _errors {
_log.Error(desc)
}
if len(_errors) > 0 {
os.Exit(1)
}
}
func walkDir(dir string) {
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
if err := AstInspect(path); err != nil {
_log.Fatalf("%+v", err)
}
}
return nil
})
}
func combineDirs(files []string) (fs []string) {
fmap := make(map[string]struct{})
for _, f := range files {
index := strings.LastIndex(f, "/")
if index > 0 {
fmap[f[:index]] = struct{}{}
}
}
for k := range fmap {
fs = append(fs, k)
}
return
}
func filterFiles(files []string) (fs []string) {
for _, f := range files {
if strings.Contains(f, _flagHit) {
fs = append(fs, f)
}
}
return
}

24
app/tool/bgr/model.go Normal file
View File

@@ -0,0 +1,24 @@
package main
import (
"fmt"
"go/ast"
"strings"
)
type lint struct {
s *script
fn func(curDir string, f *ast.File, node ast.Node) bool
}
type script struct {
dir string
ts []string // type slice
v string
l string
d string
}
func (s script) String() string {
return fmt.Sprintf("script path: %s, type: %s, value: %s, level: %s", s.dir, strings.Join(s.ts, "."), s.v, s.l)
}

View File

@@ -0,0 +1,137 @@
package main
import (
"bufio"
"fmt"
"go/ast"
"io"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/pkg/errors"
)
var (
_lints = make([]*lint, 0)
)
func walkScript(dir string) {
fn := func(path string, info os.FileInfo, err error) error {
if err != nil {
_log.Debugf("%+v", err)
return err
}
if !strings.HasSuffix(info.Name(), ".bgl") {
return nil
}
var (
file *os.File
newErr error
scripts []*script
)
if file, newErr = os.Open(path); newErr != nil {
newErr = errors.WithStack(newErr)
return newErr
}
if scripts, newErr = fileToScript(file, path); newErr != nil {
newErr = errors.WithStack(newErr)
return newErr
}
for _, s := range scripts {
registerLints(s)
}
return nil
}
if err := filepath.Walk(dir, fn); err != nil {
panic(err)
}
}
func fileToScript(file *os.File, path string) (scripts []*script, err error) {
var (
br = bufio.NewReader(file)
curScript *script
line []byte
isPrefix bool
)
for line, isPrefix, err = br.ReadLine(); err != io.EOF; line, isPrefix, err = br.ReadLine() {
if err != nil {
err = errors.WithStack(err)
return
}
if isPrefix {
_log.Fatalf("parseScript file: %s/%s err: some line too long", path, file.Name())
}
strs := strings.Split(strings.TrimSpace(string(line)), " ")
if len(strs) != 2 {
continue
}
k, v := strs[0], strs[1]
switch k {
case "T":
ts := strings.Split(strings.TrimSpace(v), ".")
curScript = &script{
dir: filepath.Dir(path),
ts: ts,
l: "e",
d: fmt.Sprintf("{%s : %s}", strings.Join(ts, "."), v),
}
case "V":
if curScript != nil {
curScript.v = v
}
scripts = append(scripts, curScript)
case "L":
if curScript != nil {
curScript.l = v
}
case "D":
if curScript != nil {
curScript.d = v
}
}
}
err = nil
return
}
func registerLints(script *script) {
_lints = append(_lints, &lint{
s: script,
fn: assembleLint(script),
})
}
func assembleLint(script *script) func(curDir string, f *ast.File, node ast.Node) bool {
var (
reg *regexp.Regexp
err error
)
_log.Debugf("assembleLint script: %+v", script)
if reg, err = regexp.Compile(script.v); err != nil {
_log.Fatalf("assembleLint script: %s, v compile error: %+v", script, err)
return nil
}
return func(curDir string, f *ast.File, n ast.Node) bool {
// if !strings.HasPrefix(curDir, script.dir) {
// return true
// }
var (
parse func(curDir string, f *ast.File, n ast.Node) (v string, hit bool)
ok bool
k = strings.Join(script.ts, ".")
)
if parse, ok = _parsers[k]; !ok {
return true
}
content, hit := parse(curDir, f, n)
if !hit {
return true
}
return !reg.MatchString(content) // 返回是否是正常node未命中lint
}
}

2
app/tool/bgr/test.sh Normal file
View File

@@ -0,0 +1,2 @@
go install
bgr -debug=true -type=dir ../../...

View File

@@ -0,0 +1,25 @@
### bmproto
### v1.0.7
- 路径加入双引号,兼容路径含空格的情况
### v1.0.6
- md文档 json改成javascript
### v1.0.0
- generate code for blademaster
### v1.0.1
- 支持 option (google.api.http)
### v1.0.2
- 支持 project 里的internal
### v1.0.2
- autodoc 支持 jsontag
### v1.0.3
- 使用proto.sh脚本生成grpc代码和主站保持一直
### v1.0.5
- 请求参数可以是Json

View File

@@ -0,0 +1,8 @@
# Owner
liugang
# Author
all
# Reviewer
all

8
app/tool/bmproto/OWNERS Normal file
View File

@@ -0,0 +1,8 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- liugang
labels:
- tool
options:
no_parent_owners: true

275
app/tool/bmproto/README.md Normal file
View File

@@ -0,0 +1,275 @@
# 目录
<!-- vim-markdown-toc GitLab -->
* [简介](#简介)
* [HTTP访问](#http访问)
* [grpc](#grpc)
* [安装](#安装)
* [用法](#用法)
* [生成结果](#生成结果)
* [命名规范](#命名规范)
* [proto包名与版本号](#proto包名与版本号)
* [生成的go文件的包名](#生成的go文件的包名)
* [多个proto文件](#多个proto文件)
* [其他特性](#其他特性)
* [添加http框架的Middleware](#添加http框架的middleware)
* [自定义Url或者指定http方法为post](#自定义url或者指定http方法为post)
* [生成service模板](#生成service模板)
* [form tag和json tag](#form-tag和json-tag)
* [指定输入参数的约束条件](#指定输入参数的约束条件)
* [同步Markdown文档到live-doc仓库直播Only](#同步markdown文档到live-doc仓库直播only)
* [支持json做为输入](#支持json做为输入)
* [直播部门老的用法](#直播部门老的用法)
* [兼容直播服务列表按照discovery id](#兼容直播服务列表按照discovery-id)
<!-- vim-markdown-toc -->
## 简介
根据protobuf文件生成grpc和blademaster框架http代码及文档
```protobuf
syntax = "proto3";
package department.app;
option go_package = "api";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
service Greeter{
// api 标题
// api 说明
rpc SayHello(HelloRequest) returns (HelloResponse);
}
message HelloRequest {
// 请求参数说明
string param1 = 1 [(gogoproto.moretags) = 'form:"param1"'];
}
message HelloResponse {
// 返回字段说明
string ret_string = 1 [(gogoproto.jsontag) = 'ret_string'];
}
```
#### HTTP访问
```
GET /department.app.Greeter/SayHello?param1=p1
响应
{
"code": 0,
"message": "ok",
"data": {
"ret_string": "anything"
}
}
```
#### grpc
路径 /department.app.Greeter/SayHello
## 安装
```shell
go install go-common/app/tool/bmproto/...
```
## 用法
- cd 项目目录
- 在 api目录下新建api.proto文件(参见上面的例子) 例如 api/api.proto
- 运行 bmgen在项目的任意位置
- 创建 internal/service/greeter.go(这是写业务代码的地方)也可以通过bmgen -t直接生成
```go
import pb "path-to-project/api"
....
// 实现 pb.GreeterBMServer 和 grpc的 pb.GreeterServer
type GreeterService struct {
}
func (s *GreeterService) SayHello(ctx context.Context, req *pb.SayHelloRequest)
(resp *pb.SayHelloResp, err error) {
}
```
- 在server/http.go 初始化代码(一般是`route`方法)里加入代码
```go
import pb "path-to-project/api"
import svc "path-to-project/internal/service"
......
pb.RegisterGreeterBMServer(engine, &svc.GreeterService{})
```
- 如果是grpc 在server/grpc/server.go 初始化里面加入代码
`pb.RegisterGreeterServer(grpcServer, &svc.GreeterService{})`
- 启动服务
- 访问接口 `curl 127.0.0.1:8000/department.app.Greeter/SayHello` (默认路由规则为 `/package.service/method`)
### 生成结果
```
project-
|------|--internal/service/greeter.go (使用bmgen -t 会生成如果proto新增加方法会自动往这里面添加模板代码
|--api/
|--api.greeter.md (HTTP API文档)
|--api.bm.go
|--api.pb.go
|--api.proto
```
## 命名规范
### proto包名与版本号
- DISCOVERY_ID 或者 DISCOVERY_ID.v*
- DISCOVERY_ID的构成为 `部门.服务` 并且去掉中划线
- 第一个版本不用加版本号从第二个版本加v2
- **示例** 部门 department 服务 hello-world 则 package为`department.helloworld`, 文件目录为api/
- 第二个版本package `department.helloworld.v2", 目录为api/v2
### 生成的go文件的包名
- golang一般原则上保持包名和目录名一致
- proto 可以指定`option go_package = "xxx"; `
比如对于api/api.proto `option go_package = "api"; `
对于api/v2/api.proto `option go_package = "v2"; `
### 多个proto文件
一个文件夹下面可以有多个proto文件但是要满足以下约束
- 同目录下的proto package 一致
- message service 等定义不能重复因为是在统一package下面
## 其他特性
### 添加http框架的Middleware
在RegisterXXBMServer之前加入代码
```
bm.Inject(pb.PathGreeterSayHello, middleware1, middleware2)
```
### 自定义Url或者指定http方法为post
```protobuf
.....
package department.app;
....
import "google/api/annotations.proto";
....
service Greeter{
rpc SayHelloCustomUrl(HelloRequest) returns (HelloResponse) {
option (google.api.http) = {
get:"/say_hello" // GET /say_hello
};
};
rpc SayHelloPost(HelloRequest) returns (HelloResponse) {
option (google.api.http) = {
post:"" // POST /department.app.Greeter/SayHelloPost
};
};
}
```
### 生成service模板
`bmgen -t` 生成service模板代码在 internal/service/serviceName.go
### form tag和json tag
```
对于HTTP接口
现在请求字段需要加上form tag以解析请求参数
响应参数需要加上json tag 以避免 字段为0或者空字符串时不显示
这两个tag都建议和字段名保持一致
现在是必须加将来考虑维护一个自己的proto仓库以移除这个多余的tag
```
### 指定输入参数的约束条件
```protobuf
...
import "github.com/gogo/protobuf/gogoproto/gogo.proto"
...
message Request {
int param1 = 1 [(gogoproto.moretags) = 'validate:"required"')]; // 参数必传不能等于0
}
```
### 同步Markdown文档到live-doc仓库直播Only
`bmgen -l`
### 支持json做为输入
```
curl 127.0.0.1:8000/department.app.Greeter/SayHello -H "Content-Type: application/json" -d "{"param1":"p1"}" -X POST
```
## 直播部门老的用法
**对于以下"兼容直播服务列表中的服务"有效**
- URL/xlive/项目名/v*/service开头小写/method
- 注册路由使用RegisterXXXService而不是 RegisterXXBMServer
- middleware不支持RegisterXXXMiddleware 而是 使用注解
```go
api/api.proto
service Greeter {
// `method:"POST"` // 表示请求方法为POST
// `midware:"user"`
rpc SayHello(A) returns (B);
}
// server/http/http.go
import bm "go-common/library/net/http/blademaster"
....
userAuthMiddleware := xxxxx
pb.RegisterXXService(e, svc, map[string]bm.HandlerFunc{"user":userAuthMiddleware})
```
- 注解,在方法或者字段上方的注视添加和 go的tag格式一样的注解实现一定的功能
注解列表:
| key | 位置 | 说明 |
| ------------ | --------------------- | ------------------------------------------------------------ |
| midware | rpc method上方 | midware:"auth,verify" 中间件auth 是验证登录态verify是校验签名 |
| method | rpc method上方 | method:"POST" 指定http请求方法 |
| mock | 响应message的字段上方 | mock:"mockdata" mock数据生成文档的时候有用 |
| internal | 不建议继续使用 | 不建议继续使用 |
| dynamic | 不建议继续使用 | 不建议继续使用 |
| dynamic_resp | 不建议继续使用 | 不建议继续使用 |
### 兼容直播服务列表按照discovery id
- "live.webucenter"
- "live.webroom"
- "live.appucenter"
- "live.appblink"
- "live.approom"
- "live.appinterface"
- "live.liveadmin"
- "live.resource"
- "live.livedemo"
- "live.lotteryinterface"

View File

@@ -0,0 +1,39 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "bmgen",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
importpath = "go-common/app/tool/bmproto/bmgen",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/github.com/urfave/cli:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,420 @@
package main
import (
"bufio"
"fmt"
"io/ioutil"
"log"
"net/url"
"os"
"os/exec"
"os/user"
"path"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
var tplFlag = false
var grpcFlag = false
// 使用app/tool/warden/protoc.sh 生成grpc .pb.go
var protocShRunned = false
var syncLiveDoc = false
func main() {
app := cli.NewApp()
app.Name = "bmgen"
app.Usage = "根据proto文件生成bm框架或者grpc代码: \n" +
"用法1在项目的任何一个位置运行bmgen会自动找到proto文件\n" +
"用法2bmgen proto文件(文件必须在一个项目的api中项目包含cmd和api目录)\n"
app.Version = "1.0.0"
app.Commands = []cli.Command{
{
Name: "update",
Usage: "更新工具本身",
Action: actionUpdate,
},
{
Name: "clean-live-doc",
Usage: "清除live-doc已经失效的分支的文档",
Action: actionCleanLiveDoc,
},
}
app.Action = actionGenerate
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "interface, i",
Value: "",
Usage: "generate for the interface project `RELATIVE-PATH`, eg. live/live-demo",
},
cli.BoolFlag{
Name: "grpc, g",
Destination: &grpcFlag,
Usage: "废弃会自动检测是否需要grpc",
},
cli.BoolFlag{
Name: "tpl, t",
Destination: &tplFlag,
Usage: "是否生成service模板代码",
},
cli.BoolFlag{
Name: "live-doc, l",
Destination: &syncLiveDoc,
Usage: "同步该项目的文档到live-doc https://git.bilibili.co/live-dev/live-doc/tree/doc/proto/$branch/$package/$filename.$Service.md",
},
}
err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}
func autoUpdate(ctx *cli.Context) (err error) {
tfile, e := ioutil.ReadFile("/tmp/bmgentime")
if e != nil {
tfile = []byte{'0'}
}
ts, _ := strconv.ParseInt(string(tfile), 0, 64)
current := time.Now().Unix()
if (current - int64(ts)) > 3600*12 { // 12 hours old
ioutil.WriteFile("/tmp/bmgentime", []byte(strconv.FormatInt(current, 10)), 0777)
err = actionUpdate(ctx)
if err != nil {
return
}
}
return
}
func actionCleanLiveDoc(ctx *cli.Context) (err error) {
fmt.Println("暂未实现,敬请期待")
return
}
func installDependencies() (err error) {
// 检查protoc
//
e := runCmd("which protoc")
if e != nil {
var uname string
uname, err = runCmdRet("uname")
if err != nil {
return
}
if uname == "Darwin" {
err = runCmd("brew install protobuf")
if err != nil {
return
}
} else {
fmt.Println("找不到protoc请于 https://github.com/protocolbuffers/protobuf/releases 下载里面的protoc-$VERSION-$OS.zip 安装, 注意把文件拷贝到正确的未知")
return errors.New("找不到protoc")
}
}
err = runCmd("which protoc-gen-gogofast || go get github.com/gogo/protobuf/protoc-gen-gogofast")
return
}
// actionGenerate invokes protoc to generate files
func actionGenerate(ctx *cli.Context) (err error) {
if err = autoUpdate(ctx); err != nil {
return
}
err = installDependencies()
if err != nil {
return
}
f := ctx.Args().Get(0)
goPath := initGopath()
if !fileExist(goPath) {
return cli.NewExitError(fmt.Sprintf("GOPATH not exist: "+goPath), 1)
}
filesToGenerate := []string{f}
iPath := ctx.String("i")
if iPath != "" {
iPath = goPath + "/src/go-common/app/interface/" + iPath
if !fileExist(iPath) {
return cli.NewExitError(fmt.Sprintf("interface project not found: "+iPath), 1)
}
pbs := filesWithSuffix(iPath+"/api", ".pb", ".proto")
if len(pbs) == 0 {
return cli.NewExitError(fmt.Sprintf("no pbs found in path: "+iPath+"/api"), 1)
}
filesToGenerate = pbs
fmt.Printf(".pb files found %v\n", pbs)
} else {
if f == "" {
// if is is empty, look up project that contains current dir
abs, _ := filepath.Abs(".")
proj := lookupProjPath(abs)
if proj == "" {
return cli.NewExitError("current dir is not in any project : "+abs, 1)
}
if proj != "" {
pbs := filesWithSuffix(proj+"/api", ".pb", ".proto")
if len(pbs) == 0 {
return cli.NewExitError(fmt.Sprintf("no pbs found in path: "+proj+"/api"), 1)
}
filesToGenerate = pbs
fmt.Printf(".pb files found %v\n", pbs)
}
}
}
for _, p := range filesToGenerate {
if !fileExist(p) {
return cli.NewExitError(fmt.Sprintf("file not exist: "+p), 1)
}
generateForFile(p, goPath)
}
if syncLiveDoc {
err = actionSyncLiveDoc(ctx)
}
return
}
func generateForFile(f string, goPath string) {
absPath, _ := filepath.Abs(f)
base := filepath.Base(f)
projPath := lookupProjPath(absPath)
fileFolder := filepath.Dir(absPath)
var relativePath string
if projPath != "" {
relativePath = absPath[len(projPath)+1:]
}
var cmd string
if strings.Index(relativePath, "api/liverpc") == 0 {
// need not generate for liverpc
fmt.Printf("skip for liverpc \n")
return
}
genTpl := 0
if tplFlag {
genTpl = 1
}
if !strings.Contains(relativePath, "api/http") {
//非http 生成grpc和http的代码
isInsideGoCommon := strings.Contains(fileFolder, "go-common")
if !protocShRunned && isInsideGoCommon {
//protoc.sh 只能在大仓库中使用
protocShRunned = true
cmd = fmt.Sprintf(`cd "%s" && "%s/src/go-common/app/tool/warden/protoc.sh"`, fileFolder, goPath)
runCmd(cmd)
}
genGrpcArg := "--gogofast_out=plugins=grpc:."
if isInsideGoCommon {
// go-common中已经用上述命令生成过了
genGrpcArg = ""
}
cmd = fmt.Sprintf(`cd "%s" && protoc --bm_out=tpl=%d:. `+
`%s -I. -I%s/src -I"%s/src/go-common" -I"%s/src/go-common/vendor" "%s"`,
fileFolder, genTpl, genGrpcArg, goPath, goPath, goPath, base)
} else {
// 只生成http的代码
var pbOutArg string
if strings.LastIndex(f, ".pb") == len(f)-3 {
// ends with .pb
log.Printf("\n\033[0;33m======WARNING========\n" +
".pb文件生成代码的功能已经不再维护请尽快迁移到.proto, 详情:\nhttp://info.bilibili.co/pages/viewpage.action?pageId=11864735#proto文件格式-.pb迁移到.proto\n" +
"======WARNING========\033[0m\n")
pbOutArg = "--gogofasterg_out=json_emitdefault=1,suffix=.pbg.go:."
} else {
pbOutArg = "--gogofast_out=."
}
cmd = fmt.Sprintf(`cd "%s" && protoc --bm_out=tpl=%d:. `+
pbOutArg+` -I. -I"%s/src" -I"%s/src/go-common" -I"%s/src/go-common/vendor" "%s"`,
fileFolder, genTpl, goPath, goPath, goPath, base)
}
err := runCmd(cmd)
if err == nil {
fmt.Println("ok")
}
}
// files all files with suffix
func filesWithSuffix(dir string, suffixes ...string) (result []string) {
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
for _, suffix := range suffixes {
if strings.HasSuffix(info.Name(), suffix) {
result = append(result, path)
break
}
}
}
return nil
})
return
}
// 扫描md文档并且同步到live-doc
func actionSyncLiveDoc(ctx *cli.Context) (err error) {
//mdFiles := filesWithSuffix(
// if is is empty, look up project that contains current dir
abs, _ := filepath.Abs(".")
proj := lookupProjPath(abs)
if proj == "" {
err = cli.NewExitError("current dir is not in any project : "+abs, 1)
return
}
var branch string
branch, err = runCmdRet("git rev-parse --abbrev-ref HEAD")
if err != nil {
return
}
branch = url.QueryEscape(branch)
err = runCmd("[ -d ~/.brpc ] || mkdir ~/.brpc")
if err != nil {
return
}
var liveDocUrl = "git@git.bilibili.co:live-dev/live-doc.git"
err = runCmd("cd ~/.brpc && [ -d ~/.brpc/live-doc ] || git clone " + liveDocUrl)
if err != nil {
return
}
err = runCmd("cd ~/.brpc/live-doc && git checkout doc && git pull origin doc")
if err != nil {
return
}
mdFiles := filesWithSuffix(proj+"/api", ".md")
var u *user.User
u, err = user.Current()
if err != nil {
return err
}
var liveDocDir = u.HomeDir + "/.brpc/live-doc"
for _, file := range mdFiles {
fileHandle, _ := os.Open(file)
fileScanner := bufio.NewScanner(fileHandle)
for fileScanner.Scan() {
var text = fileScanner.Text()
var reg = regexp.MustCompile(`package=([\w\.]+)`)
matches := reg.FindStringSubmatch(text)
if len(matches) >= 2 {
pkg := matches[1]
relativeDir := strings.Replace(pkg, ".", "/", -1)
var destDir = liveDocDir + "/protodoc/" + branch + "/" + relativeDir
runCmd("mkdir -p " + destDir)
err = runCmd(fmt.Sprintf("cp %s %s", file, destDir))
if err != nil {
return
}
} else {
fmt.Println("package not found", file)
}
break
}
fileHandle.Close()
}
err = runCmd(`cd "` + liveDocDir + `" && git add -A`)
if err != nil {
return
}
var gitStatus string
gitStatus, _ = runCmdRet(`cd "` + liveDocDir + `" && git status --porcelain`)
if gitStatus != "" {
err = runCmd(`cd "` + liveDocDir + `" && git commit -m 'update doc from proto' && git push origin doc`)
if err != nil {
return
}
}
fmt.Printf("文档已经生成至 %s%s\n", "https://git.bilibili.co/live-dev/live-doc/tree/doc/protodoc/", url.QueryEscape(branch))
return
}
// actionUpdate update the tools its self
func actionUpdate(ctx *cli.Context) (err error) {
log.Print("Updating bmgen.....")
goPath := initGopath()
goCommonPath := goPath + "/src/go-common"
if !fileExist(goCommonPath) {
return cli.NewExitError("go-common not exist : "+goCommonPath, 1)
}
cmd := fmt.Sprintf(`go install "go-common/app/tool/bmproto/..."`)
if err = runCmd(cmd); err != nil {
err = cli.NewExitError(err.Error(), 1)
return
}
log.Print("Updated!")
return
}
// runCmd runs the cmd & print output (both stdout & stderr)
func runCmd(cmd string) (err error) {
fmt.Printf("CMD: %s \n", cmd)
out, err := exec.Command("/bin/bash", "-c", cmd).CombinedOutput()
fmt.Print(string(out))
return
}
func runCmdRet(cmd string) (out string, err error) {
fmt.Printf("CMD: %s \n", cmd)
outBytes, err := exec.Command("/bin/bash", "-c", cmd).CombinedOutput()
out = strings.Trim(string(outBytes), "\n\r\t ")
return
}
// lookupProjPath get project path by proto absolute path
// assume that proto is in the project's model directory
func lookupProjPath(protoAbs string) (result string) {
lastIndex := len(protoAbs)
curPath := protoAbs
for lastIndex > 0 {
if fileExist(curPath+"/cmd") && fileExist(curPath+"/api") {
result = curPath
return
}
lastIndex = strings.LastIndex(curPath, string(os.PathSeparator))
curPath = protoAbs[:lastIndex]
}
result = ""
return
}
func fileExist(file string) bool {
_, err := os.Stat(file)
return err == nil
}
func initGopath() string {
root, err := goPath()
if err != nil || root == "" {
log.Printf("can not read GOPATH, use ~/go as default GOPATH")
root = path.Join(os.Getenv("HOME"), "go")
}
return root
}
func goPath() (string, error) {
gopaths := strings.Split(os.Getenv("GOPATH"), ":")
if len(gopaths) == 1 {
return gopaths[0], nil
}
for _, gp := range gopaths {
absgp, err := filepath.Abs(gp)
if err != nil {
return "", err
}
if fileExist(absgp + "/src/go-common") {
return absgp, nil
}
}
return "", fmt.Errorf("can't found current gopath")
}

View File

@@ -0,0 +1,73 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_test",
"go_library",
)
go_binary(
name = "protoc-gen-bm",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_test(
name = "go_default_test",
srcs = [
"command_line_test.go",
"generator_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"@com_github_golang_protobuf//proto:go_default_library",
"@com_github_golang_protobuf//protoc-gen-go/plugin:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"command_line.go",
"generator.go",
"go_naming.go",
"helper.go",
"main.go",
],
importpath = "go-common/app/tool/bmproto/protoc-gen-bm",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/tool/bmproto/protoc-gen-bm/extensions/gogoproto:go_default_library",
"//app/tool/liverpc/protoc-gen-liverpc/gen:go_default_library",
"//app/tool/liverpc/protoc-gen-liverpc/gen/stringutils:go_default_library",
"//app/tool/liverpc/protoc-gen-liverpc/gen/typemap:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
"//vendor/github.com/siddontang/go/ioutil2:go_default_library",
"//vendor/google.golang.org/genproto/googleapis/api/annotations:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
"@com_github_golang_protobuf//protoc-gen-go/descriptor:go_default_library",
"@com_github_golang_protobuf//protoc-gen-go/plugin:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/tool/bmproto/protoc-gen-bm/example:all-srcs",
"//app/tool/bmproto/protoc-gen-bm/extensions/gogoproto:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,3 @@
# this Makefile is for old users, for new users, just go install in the 2 directories
install:
go install ; cd ../bmgen && go install ; if [ -f /usr/local/bin/bmgen ]; then rm /usr/local/bin/bmgen; fi

View File

@@ -0,0 +1,69 @@
// 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.
package main
import (
"fmt"
"strings"
)
type commandLineParams 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 grpc compatible interface
}
// parseCommandLineParams breaks the comma-separated list of key=value pairs
// in the parameter (a member of the request protobuf) into a key/value map.
// It then sets command line parameter mappings defined by those entries.
func parseCommandLineParams(parameter string) (*commandLineParams, error) {
ps := make(map[string]string)
for _, p := range strings.Split(parameter, ",") {
if p == "" {
continue
}
i := strings.Index(p, "=")
if i < 0 {
return nil, 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 nil, fmt.Errorf("invalid parameter %q: expected format of parameter to be k=v", k)
}
ps[k] = v
}
clp := &commandLineParams{
importMap: make(map[string]string),
}
for k, v := range ps {
switch {
case k == "tpl":
if v == "true" || v == "1" {
clp.tpl = true
}
case k == "import_prefix":
clp.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':
clp.importMap[k[1:]] = v // 1 is the length of 'M'.
case len(k) > 0 && strings.HasPrefix(k, "go_import_mapping@"):
clp.importMap[k[18:]] = v // 18 is the length of 'go_import_mapping@'.
default:
return nil, fmt.Errorf("unknown parameter %q", k)
}
}
return clp, nil
}

View File

@@ -0,0 +1,128 @@
// 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.
package main
import (
"errors"
"reflect"
"testing"
)
func TestParseCommandLineParams(t *testing.T) {
tests := []struct {
name string
parameter string
params *commandLineParams
err error
}{
{
"no parameters",
"",
&commandLineParams{
importMap: map[string]string{},
},
nil,
},
{
"unknown parameter",
"k=v",
nil,
errors.New(`unknown parameter "k"`),
},
{
"empty parameter value - no equals sign",
"import_prefix",
nil,
errors.New(`invalid parameter "import_prefix": expected format of parameter to be k=v`),
},
{
"empty parameter value - no value",
"import_prefix=",
nil,
errors.New(`invalid parameter "import_prefix": expected format of parameter to be k=v`),
},
{
"import_prefix parameter",
"import_prefix=github.com/example/repo",
&commandLineParams{
importMap: map[string]string{},
importPrefix: "github.com/example/repo",
},
nil,
},
{
"single import parameter starting with 'M'",
"Mrpcutil/empty.proto=github.com/example/rpcutil",
&commandLineParams{
importMap: map[string]string{
"rpcutil/empty.proto": "github.com/example/rpcutil",
},
},
nil,
},
{
"multiple import parameters starting with 'M'",
"Mrpcutil/empty.proto=github.com/example/rpcutil,Mrpc/haberdasher/service.proto=github.com/example/rpc/haberdasher",
&commandLineParams{
importMap: map[string]string{
"rpcutil/empty.proto": "github.com/example/rpcutil",
"rpc/haberdasher/service.proto": "github.com/example/rpc/haberdasher",
},
},
nil,
},
{
"single import parameter starting with 'go_import_mapping@'",
"go_import_mapping@rpcutil/empty.proto=github.com/example/rpcutil",
&commandLineParams{
importMap: map[string]string{
"rpcutil/empty.proto": "github.com/example/rpcutil",
},
},
nil,
},
{
"multiple import parameters starting with 'go_import_mapping@'",
"go_import_mapping@rpcutil/empty.proto=github.com/example/rpcutil,go_import_mapping@rpc/haberdasher/service.proto=github.com/example/rpc/haberdasher",
&commandLineParams{
importMap: map[string]string{
"rpcutil/empty.proto": "github.com/example/rpcutil",
"rpc/haberdasher/service.proto": "github.com/example/rpc/haberdasher",
},
},
nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
params, err := parseCommandLineParams(tt.parameter)
switch {
case err != nil:
if tt.err == nil {
t.Fatal(err)
}
if err.Error() != tt.err.Error() {
t.Errorf("got error = %v, want %v", err, tt.err)
}
case err == nil:
if tt.err != nil {
t.Errorf("got error = %v, want %v", err, tt.err)
}
}
if !reflect.DeepEqual(params, tt.params) {
t.Errorf("got params = %v, want %v", params, tt.params)
}
})
}
}

View File

@@ -0,0 +1,65 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
proto_library(
name = "v1_proto",
srcs = ["demo.proto"],
tags = ["automanaged"],
deps = [
"@go_googleapis//google/api:annotations_proto",
"@gogo_special_proto//github.com/gogo/protobuf/gogoproto",
],
)
go_proto_library(
name = "v1_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_grpc"],
importpath = "go-common/app/tool/bmproto/protoc-gen-bm/example",
proto = ":v1_proto",
tags = ["automanaged"],
deps = [
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@go_googleapis//google/api:annotations_go_proto",
],
)
go_library(
name = "go_default_library",
srcs = ["demo.bm.go"],
embed = [":v1_go_proto"],
importpath = "go-common/app/tool/bmproto/protoc-gen-bm/example",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/binding:go_default_library",
"//vendor/google.golang.org/genproto/googleapis/api/annotations:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@org_golang_google_grpc//:go_default_library",
"@org_golang_x_net//context:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,2 @@
generate:
protoc -I. -I${GOPATH}/src/go-common/vendor -I${GOPATH}/src --bm_out=. --gogofast_out=plugins=grpc:. demo.proto

View File

@@ -0,0 +1,166 @@
// Code generated by protoc-gen-bm v0.1, DO NOT EDIT.
// source: demo.proto
/*
Package v1 is a generated blademaster stub package.
This code was generated with go-common/app/tool/bmgen/protoc-gen-bm v0.1.
It is generated from these files:
demo.proto
*/
package v1
import (
"context"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/binding"
)
// to suppressed 'imported but not used warning'
var _ *bm.Context
var _ context.Context
var _ binding.StructValidator
var PathFooUnameByUid = "/xlive/demo/v1/foo/uname_by_uid_custom_route"
var PathFooGetInfo = "/live.livedemo.v1.Foo/get_info"
var PathFooUnameByUid3 = "/live.livedemo.v1.Foo/uname_by_uid3"
var PathFooUnameByUid4 = "/live.livedemo.v1.Foo/uname_by_uid4"
var PathFooGetDynamic = "/live.livedemo.v1.Foo/get_dynamic"
var PathFooNointerface = "/live.livedemo.v1.Foo/nointerface"
var PathFoo2Hello = "/live.livedemo.v1.Foo2/hello"
// =============
// Foo Interface
// =============
// Foo 相关服务
type FooBMServer interface {
// 根据uid得到uname
// `method:"post" midware:"auth,verify"`
//
// 这是详细说明
UnameByUid(ctx context.Context, req *Bar1Req) (resp *Bar1Resp, err error)
// 获取房间信息
// `midware:"guest"`
GetInfo(ctx context.Context, req *GetInfoReq) (resp *GetInfoResp, err error)
// 根据uid得到uname v3
UnameByUid3(ctx context.Context, req *Bar1Req) (resp *Bar1Resp, err error)
// test comment
// `internal:"true"`
UnameByUid4(ctx context.Context, req *Bar1Req) (resp *Bar1Resp, err error)
// `dynamic_resp:"true"`
GetDynamic(ctx context.Context, req *Bar1Req) (resp interface{}, err error)
}
var v1FooSvc FooBMServer
func fooUnameByUid(c *bm.Context) {
p := new(Bar1Req)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1FooSvc.UnameByUid(c, p)
c.JSON(resp, err)
}
func fooGetInfo(c *bm.Context) {
p := new(GetInfoReq)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1FooSvc.GetInfo(c, p)
c.JSON(resp, err)
}
func fooUnameByUid3(c *bm.Context) {
p := new(Bar1Req)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1FooSvc.UnameByUid3(c, p)
c.JSON(resp, err)
}
func fooUnameByUid4(c *bm.Context) {
p := new(Bar1Req)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1FooSvc.UnameByUid4(c, p)
c.JSON(resp, err)
}
func fooGetDynamic(c *bm.Context) {
p := new(Bar1Req)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1FooSvc.GetDynamic(c, p)
c.JSON(resp, err)
}
// RegisterV1FooService Register the blademaster route with middleware map
// midMap is the middleware map, the key is defined in proto
func RegisterV1FooService(e *bm.Engine, svc FooBMServer, midMap map[string]bm.HandlerFunc) {
auth := midMap["auth"]
guest := midMap["guest"]
verify := midMap["verify"]
v1FooSvc = svc
e.GET("/xlive/demo/v1/foo/uname_by_uid_custom_route", auth, verify, fooUnameByUid)
e.GET("/xlive/live-demo/v1/foo/get_info", guest, fooGetInfo)
e.GET("/xlive/live-demo/v1/foo/uname_by_uid3", fooUnameByUid3)
e.GET("/xlive/internal/live-demo/v1/foo/uname_by_uid4", fooUnameByUid4)
e.GET("/xlive/live-demo/v1/foo/get_dynamic", fooGetDynamic)
}
// RegisterFooBMServer Register the blademaster route
func RegisterFooBMServer(e *bm.Engine, server FooBMServer) {
e.GET("/xlive/demo/v1/foo/uname_by_uid_custom_route", fooUnameByUid)
e.GET("/live.livedemo.v1.Foo/get_info", fooGetInfo)
e.GET("/live.livedemo.v1.Foo/uname_by_uid3", fooUnameByUid3)
e.GET("/live.livedemo.v1.Foo/uname_by_uid4", fooUnameByUid4)
e.GET("/live.livedemo.v1.Foo/get_dynamic", fooGetDynamic)
}
// ==============
// Foo2 Interface
// ==============
type Foo2BMServer interface {
Hello(ctx context.Context, req *Bar1Req) (resp *Bar1Resp, err error)
}
var v1Foo2Svc Foo2BMServer
func foo2Hello(c *bm.Context) {
p := new(Bar1Req)
if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil {
return
}
resp, err := v1Foo2Svc.Hello(c, p)
c.JSON(resp, err)
}
// RegisterV1Foo2Service Register the blademaster route with middleware map
// midMap is the middleware map, the key is defined in proto
func RegisterV1Foo2Service(e *bm.Engine, svc Foo2BMServer, midMap map[string]bm.HandlerFunc) {
v1Foo2Svc = svc
e.GET("/xlive/live-demo/v1/foo2/hello", foo2Hello)
}
// RegisterFoo2BMServer Register the blademaster route
func RegisterFoo2BMServer(e *bm.Engine, server Foo2BMServer) {
e.GET("/live.livedemo.v1.Foo2/hello", foo2Hello)
}

View File

@@ -0,0 +1,272 @@
<!-- package=live.livedemo.v1 -->
- [/xlive/demo/v1/foo/uname_by_uid_custom_route](#xlivedemov1foouname_by_uid_custom_route) 根据uid得到uname
- [/xlive/live-demo/v1/foo/get_info](#xlivelive-demov1fooget_info) 获取房间信息
- [/xlive/live-demo/v1/foo/uname_by_uid3](#xlivelive-demov1foouname_by_uid3) 根据uid得到uname v3
- [/xlive/internal/live-demo/v1/foo/uname_by_uid4](#xliveinternallive-demov1foouname_by_uid4) test comment
- [/xlive/live-demo/v1/foo/get_dynamic](#xlivelive-demov1fooget_dynamic)
- [/xlive/live-demo/v1/foo/nointerface](#xlivelive-demov1foonointerface)
## /xlive/demo/v1/foo/uname_by_uid_custom_route
### 根据uid得到uname
这是详细说明
> 需要登录
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|uid|否|integer| 用户uid aaa|
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
// 用户名
"uname": "hello",
// idshaha
"ids": [
343242
],
"list": [
{
"hello": "\"withquote",
"world": ""
}
],
"alist": {
"hello": "\"withquote",
"world": ""
},
"amap": {
"mapKey": {
"hello": "\"withquote",
"world": ""
}
}
}
}
```
## /xlive/live-demo/v1/foo/get_info
### 获取房间信息
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|room_id|是|integer| 房间id `mock:"123"|
|many_ids|否|多个integer||
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
// 房间id 注释貌似只有放在前面才能被识别,放到字段声明后面是没用的
"roomid": 0,
// 用户名
"uname": "",
// 开播时间
"live_time": "",
"amap": {
"1": ""
},
"rate": 6.02214129e23,
// 用户mid
"mid": 0
}
}
```
## /xlive/live-demo/v1/foo/uname_by_uid3
### 根据uid得到uname v3
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|uid|否|integer| 用户uid aaa|
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
// 用户名
"uname": "hello",
// idshaha
"ids": [
343242
],
"list": [
{
"hello": "\"withquote",
"world": ""
}
],
"alist": {
"hello": "\"withquote",
"world": ""
},
"amap": {
"mapKey": {
"hello": "\"withquote",
"world": ""
}
}
}
}
```
## /xlive/internal/live-demo/v1/foo/uname_by_uid4
### test comment
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|uid|否|integer| 用户uid aaa|
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
// 用户名
"uname": "hello",
// idshaha
"ids": [
343242
],
"list": [
{
"hello": "\"withquote",
"world": ""
}
],
"alist": {
"hello": "\"withquote",
"world": ""
},
"amap": {
"mapKey": {
"hello": "\"withquote",
"world": ""
}
}
}
}
```
## /xlive/live-demo/v1/foo/get_dynamic
### 无标题
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|uid|否|integer| 用户uid aaa|
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
// 用户名
"uname": "hello",
// idshaha
"ids": [
343242
],
"list": [
{
"hello": "\"withquote",
"world": ""
}
],
"alist": {
"hello": "\"withquote",
"world": ""
},
"amap": {
"mapKey": {
"hello": "\"withquote",
"world": ""
}
}
}
}
```
## /xlive/live-demo/v1/foo/nointerface
### 无标题
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|uid|否|integer| 用户uid aaa|
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
// 用户名
"uname": "hello",
// idshaha
"ids": [
343242
],
"list": [
{
"hello": "\"withquote",
"world": ""
}
],
"alist": {
"hello": "\"withquote",
"world": ""
},
"amap": {
"mapKey": {
"hello": "\"withquote",
"world": ""
}
}
}
}
```

View File

@@ -0,0 +1,47 @@
<!-- package=live.livedemo.v1 -->
- [/xlive/live-demo/v1/foo2/hello](#xlivelive-demov1foo2hello)
## /xlive/live-demo/v1/foo2/hello
### 无标题
#### 方法GET
#### 请求参数
|参数名|必选|类型|描述|
|:---|:---|:---|:---|
|uid|否|integer| 用户uid aaa|
#### 响应
```javascript
{
"code": 0,
"message": "ok",
"data": {
// 用户名
"uname": "hello",
// idshaha
"ids": [
343242
],
"list": [
{
"hello": "\"withquote",
"world": ""
}
],
"alist": {
"hello": "\"withquote",
"world": ""
},
"amap": {
"mapKey": {
"hello": "\"withquote",
"world": ""
}
}
}
}
```

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,87 @@
syntax = "proto3";
package live.livedemo.v1;
option go_package = "v1";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "google/api/annotations.proto";
// Foo 相关服务
service Foo {
// 根据uid得到uname
// `method:"post" midware:"auth,verify"`
//
// 这是详细说明
rpc uname_by_uid (Bar1Req) returns (Bar1Resp) {
option (google.api.http) = {
get:"/xlive/demo/v1/foo/uname_by_uid_custom_route"
};
};
// 获取房间信息
// `midware:"guest"`
rpc get_info (GetInfoReq) returns (GetInfoResp);
// 根据uid得到uname v3
rpc uname_by_uid3 (Bar1Req) returns (Bar1Resp);
// test comment
// `internal:"true"`
rpc uname_by_uid4 (Bar1Req) returns (Bar1Resp);
// `dynamic_resp:"true"`
rpc get_dynamic (Bar1Req) returns (Bar1Resp);
// `dynamic:"true"`
rpc nointerface (Bar1Req) returns (Bar1Resp);
}
service Foo2 {
rpc hello (Bar1Req) returns (Bar1Resp);
}
// Bar请求
message Bar1Req {
// 用户uid
//
// aaa
int32 uid = 1 [(gogoproto.moretags) = 'form:"uid"'];
}
// Bar 相应
message Bar1Resp {
// 用户名
// `mock:"hello"`
string uname = 2 [(gogoproto.jsontag) = "uname"];
// idshaha
// `mock:"343242"`
repeated int32 ids = 3 [(gogoproto.jsontag) = "ids"];
repeated List list = 4 [(gogoproto.jsontag) = "list"];
List alist = 5 [(gogoproto.jsontag) = "alist"];
message List {
// `mock:"\"withquote"`
string hello = 1 [(gogoproto.jsontag) = "hello"];
string world = 2 [(gogoproto.jsontag) = "world"];
}
map<string, List> amap = 6 [(gogoproto.jsontag) = "amap"];
}
// 获取房间信息请求
message GetInfoReq {
// 房间id
// `mock:"123"
int64 room_id = 1 [(gogoproto.moretags) = 'form:"room_id" validate:"required"'];
repeated int64 many_ids = 2 [(gogoproto.moretags) = 'form:"many_ids"'];
}
// 获取房间信息响应
message GetInfoResp {
// 房间id 注释貌似只有放在前面才能被识别,放到字段声明后面是没用的
int64 roomid = 1 [(gogoproto.jsontag) = "roomid"]; // 这段注释不会被理会
// 用户名
string uname = 2 [(gogoproto.jsontag) = "uname"];
// 开播时间
string live_time = 3 [(gogoproto.jsontag) = "live_time"];
map<int32, string> amap = 4 [(gogoproto.jsontag) = "amap"];
// `mock:"6.02214129e23"`
float rate = 5 [(gogoproto.jsontag) = "rate"];
// 用户mid
int64 mid = 6 [(gogoproto.jsontag) = "mid"];
}

View File

@@ -0,0 +1,54 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
proto_library(
name = "gogoproto_proto",
srcs = ["gogo.proto"],
tags = ["automanaged"],
deps = ["@com_google_protobuf//:descriptor_proto"],
)
go_proto_library(
name = "gogoproto_go_proto",
compilers = ["@io_bazel_rules_go//proto:go_proto"],
importpath = "go-common/app/tool/bmproto/protoc-gen-bm/extensions/gogoproto",
proto = ":gogoproto_proto",
tags = ["automanaged"],
deps = ["@io_bazel_rules_go//proto/wkt:descriptor_go_proto"],
)
go_library(
name = "go_default_library",
srcs = [],
embed = [":gogoproto_go_proto"],
importpath = "go-common/app/tool/bmproto/protoc-gen-bm/extensions/gogoproto",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"@com_github_golang_protobuf//proto:go_default_library",
"@com_github_golang_protobuf//protoc-gen-go/descriptor:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,37 @@
# 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.
regenerate:
go install 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

View File

@@ -0,0 +1,818 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: gogo.proto
package gogoproto // import "go-common/app/tool/bmproto/protoc-gen-bm/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_035fd4fcfeb21e86) }
var fileDescriptor_gogo_035fd4fcfeb21e86 = []byte{
// 1264 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x98, 0x49, 0x6f, 0x1c, 0x45,
0x14, 0x80, 0x85, 0x70, 0x64, 0xcf, 0xf3, 0x86, 0xc7, 0xc6, 0x84, 0x08, 0x44, 0xb8, 0x71, 0xb1,
0xe7, 0x14, 0xa1, 0x94, 0x65, 0x59, 0x8e, 0xe5, 0x58, 0x41, 0x18, 0x8c, 0x89, 0xc3, 0x76, 0x18,
0x7a, 0x66, 0xca, 0x9d, 0x81, 0xee, 0xae, 0xa6, 0x97, 0x28, 0xce, 0x0d, 0x85, 0x45, 0x08, 0xb1,
0x23, 0x41, 0x42, 0x12, 0xc8, 0x81, 0x7d, 0x0d, 0x3b, 0x37, 0x2e, 0x2c, 0x57, 0xfe, 0x03, 0x17,
0xc0, 0xec, 0xbe, 0xf9, 0x12, 0xbd, 0xee, 0xf7, 0x7a, 0xaa, 0xc7, 0x23, 0x55, 0xcd, 0xad, 0x6d,
0xd7, 0xf7, 0xb9, 0xfa, 0xbd, 0xaa, 0xf7, 0xde, 0x0c, 0x80, 0xab, 0x5c, 0x35, 0x1b, 0x46, 0x2a,
0x51, 0xd5, 0x0a, 0x3e, 0x67, 0x8f, 0x07, 0x0e, 0xba, 0x4a, 0xb9, 0x9e, 0xac, 0x65, 0x3f, 0x35,
0xd2, 0xcd, 0x5a, 0x4b, 0xc6, 0xcd, 0xa8, 0x1d, 0x26, 0x2a, 0xca, 0x17, 0x8b, 0xbb, 0x60, 0x92,
0x16, 0xd7, 0x65, 0x90, 0xfa, 0xf5, 0x30, 0x92, 0x9b, 0xed, 0xd3, 0xd5, 0x9b, 0x66, 0x73, 0x72,
0x96, 0xc9, 0xd9, 0xe5, 0x20, 0xf5, 0xef, 0x0e, 0x93, 0xb6, 0x0a, 0xe2, 0xfd, 0x57, 0x7e, 0xbd,
0xf6, 0xe0, 0x35, 0xb7, 0x0d, 0xad, 0x4f, 0x10, 0x8a, 0x7f, 0x5b, 0xcb, 0x40, 0xb1, 0x0e, 0xd7,
0x97, 0x7c, 0x71, 0x12, 0xb5, 0x03, 0x57, 0x46, 0x06, 0xe3, 0x0f, 0x64, 0x9c, 0xd4, 0x8c, 0xf7,
0x12, 0x2a, 0x96, 0x60, 0xb4, 0x1f, 0xd7, 0x8f, 0xe4, 0x1a, 0x91, 0xba, 0x64, 0x05, 0xc6, 0x33,
0x49, 0x33, 0x8d, 0x13, 0xe5, 0x07, 0x8e, 0x2f, 0x0d, 0x9a, 0x9f, 0x32, 0x4d, 0x65, 0x7d, 0x0c,
0xb1, 0xa5, 0x82, 0x12, 0x02, 0x86, 0xf0, 0x37, 0x2d, 0xd9, 0xf4, 0x0c, 0x86, 0x9f, 0x69, 0x23,
0xc5, 0x7a, 0x71, 0x02, 0xa6, 0xf0, 0xf9, 0x94, 0xe3, 0xa5, 0x52, 0xdf, 0xc9, 0xad, 0x3d, 0x3d,
0x27, 0x70, 0x19, 0xcb, 0x7e, 0x39, 0x3b, 0x90, 0x6d, 0x67, 0xb2, 0x10, 0x68, 0x7b, 0xd2, 0xb2,
0xe8, 0xca, 0x24, 0x91, 0x51, 0x5c, 0x77, 0xbc, 0x5e, 0xdb, 0x3b, 0xda, 0xf6, 0x0a, 0xe3, 0xb9,
0xed, 0x72, 0x16, 0x57, 0x72, 0x72, 0xd1, 0xf3, 0xc4, 0x06, 0xdc, 0xd0, 0xe3, 0x54, 0x58, 0x38,
0xcf, 0x93, 0x73, 0x6a, 0xcf, 0xc9, 0x40, 0xed, 0x1a, 0xf0, 0xef, 0x8b, 0x5c, 0x5a, 0x38, 0xdf,
0x20, 0x67, 0x95, 0x58, 0x4e, 0x29, 0x1a, 0xef, 0x80, 0x89, 0x53, 0x32, 0x6a, 0xa8, 0x58, 0xd6,
0xe5, 0x63, 0xa9, 0xe3, 0x59, 0xe8, 0x2e, 0x90, 0x6e, 0x9c, 0xc0, 0x65, 0xe4, 0xd0, 0x75, 0x18,
0x86, 0x36, 0x9d, 0xa6, 0xb4, 0x50, 0x5c, 0x24, 0xc5, 0x20, 0xae, 0x47, 0x74, 0x11, 0x46, 0x5c,
0x95, 0xbf, 0x92, 0x05, 0x7e, 0x89, 0xf0, 0x61, 0x66, 0x48, 0x11, 0xaa, 0x30, 0xf5, 0x9c, 0xc4,
0x66, 0x07, 0x6f, 0xb2, 0x82, 0x19, 0x52, 0xf4, 0x11, 0xd6, 0xb7, 0x58, 0x11, 0x6b, 0xf1, 0x5c,
0x80, 0x61, 0x15, 0x78, 0x5b, 0x2a, 0xb0, 0xd9, 0xc4, 0x65, 0x32, 0x00, 0x21, 0x28, 0x98, 0x83,
0x8a, 0x6d, 0x22, 0xde, 0xde, 0xe6, 0xeb, 0xc1, 0x19, 0x58, 0x81, 0x71, 0x2e, 0x50, 0x6d, 0x15,
0x58, 0x28, 0xde, 0x21, 0xc5, 0x98, 0x86, 0xd1, 0x6b, 0x24, 0x32, 0x4e, 0x5c, 0x69, 0x23, 0x79,
0x97, 0x5f, 0x83, 0x10, 0x0a, 0x65, 0x43, 0x06, 0xcd, 0x93, 0x76, 0x86, 0xf7, 0x38, 0x94, 0xcc,
0xa0, 0x62, 0x09, 0x46, 0x7d, 0x27, 0x8a, 0x4f, 0x3a, 0x9e, 0x55, 0x3a, 0xde, 0x27, 0xc7, 0x48,
0x01, 0x51, 0x44, 0xd2, 0xa0, 0x1f, 0xcd, 0x07, 0x1c, 0x11, 0x0d, 0xa3, 0xab, 0x17, 0x27, 0x4e,
0xc3, 0x93, 0xf5, 0x7e, 0x6c, 0x1f, 0xf2, 0xd5, 0xcb, 0xd9, 0x55, 0xdd, 0x38, 0x07, 0x95, 0xb8,
0x7d, 0xc6, 0x4a, 0xf3, 0x11, 0x67, 0x3a, 0x03, 0x10, 0x7e, 0x00, 0x6e, 0xec, 0xd9, 0x26, 0x2c,
0x64, 0x1f, 0x93, 0x6c, 0xba, 0x47, 0xab, 0xa0, 0x92, 0xd0, 0xaf, 0xf2, 0x13, 0x2e, 0x09, 0xb2,
0xcb, 0xb5, 0x06, 0x53, 0x69, 0x10, 0x3b, 0x9b, 0xfd, 0x45, 0xed, 0x53, 0x8e, 0x5a, 0xce, 0x96,
0xa2, 0x76, 0x1c, 0xa6, 0xc9, 0xd8, 0x5f, 0x5e, 0x3f, 0xe3, 0xc2, 0x9a, 0xd3, 0x1b, 0xe5, 0xec,
0x3e, 0x04, 0x07, 0x8a, 0x70, 0x9e, 0x4e, 0x64, 0x10, 0x23, 0x53, 0xf7, 0x9d, 0xd0, 0xc2, 0x7c,
0x85, 0xcc, 0x5c, 0xf1, 0x97, 0x0b, 0xc1, 0xaa, 0x13, 0xa2, 0xfc, 0x7e, 0xd8, 0xcf, 0xf2, 0x34,
0x88, 0x64, 0x53, 0xb9, 0x41, 0xfb, 0x8c, 0x6c, 0x59, 0xa8, 0x3f, 0xef, 0x4a, 0xd5, 0x86, 0x86,
0xa3, 0xf9, 0x18, 0x5c, 0x57, 0xcc, 0x2a, 0xf5, 0xb6, 0x1f, 0xaa, 0x28, 0x31, 0x18, 0xbf, 0xe0,
0x4c, 0x15, 0xdc, 0xb1, 0x0c, 0x13, 0xcb, 0x30, 0x96, 0xfd, 0x68, 0x7b, 0x24, 0xbf, 0x24, 0xd1,
0x68, 0x87, 0xa2, 0xc2, 0xd1, 0x54, 0x7e, 0xe8, 0x44, 0x36, 0xf5, 0xef, 0x2b, 0x2e, 0x1c, 0x84,
0x50, 0xe1, 0x48, 0xb6, 0x42, 0x89, 0xdd, 0xde, 0xc2, 0xf0, 0x35, 0x17, 0x0e, 0x66, 0x48, 0xc1,
0x03, 0x83, 0x85, 0xe2, 0x1b, 0x56, 0x30, 0x83, 0x8a, 0x7b, 0x3a, 0x8d, 0x36, 0x92, 0x6e, 0x3b,
0x4e, 0x22, 0x07, 0x57, 0x1b, 0x54, 0xdf, 0x6e, 0x97, 0x87, 0xb0, 0x75, 0x0d, 0xc5, 0x4a, 0xe4,
0xcb, 0x38, 0x76, 0x5c, 0x89, 0x13, 0x87, 0xc5, 0xc6, 0xbe, 0xe3, 0x4a, 0xa4, 0x61, 0xf9, 0xfd,
0x1c, 0xef, 0x9a, 0x55, 0xaa, 0xb7, 0xec, 0x11, 0xad, 0xe6, 0x0c, 0xbb, 0x1e, 0xdf, 0x21, 0x57,
0x79, 0x54, 0x11, 0x77, 0xe2, 0x01, 0x2a, 0x0f, 0x14, 0x66, 0xd9, 0xd9, 0x9d, 0xe2, 0x0c, 0x95,
0xe6, 0x09, 0x71, 0x14, 0x46, 0x4b, 0xc3, 0x84, 0x59, 0xf5, 0x04, 0xa9, 0x46, 0xf4, 0x59, 0x42,
0x1c, 0x82, 0x01, 0x1c, 0x0c, 0xcc, 0xf8, 0x93, 0x84, 0x67, 0xcb, 0xc5, 0x3c, 0x0c, 0xf1, 0x40,
0x60, 0x46, 0x9f, 0x22, 0xb4, 0x40, 0x10, 0xe7, 0x61, 0xc0, 0x8c, 0x3f, 0xcd, 0x38, 0x23, 0x88,
0xdb, 0x87, 0xf0, 0xfb, 0x67, 0x07, 0xa8, 0xa0, 0x73, 0xec, 0xe6, 0x60, 0x90, 0xa6, 0x00, 0x33,
0xfd, 0x0c, 0xfd, 0x73, 0x26, 0xc4, 0xed, 0xb0, 0xcf, 0x32, 0xe0, 0xcf, 0x11, 0x9a, 0xaf, 0x17,
0x4b, 0x30, 0xac, 0x75, 0x7e, 0x33, 0xfe, 0x3c, 0xe1, 0x3a, 0x85, 0x5b, 0xa7, 0xce, 0x6f, 0x16,
0xbc, 0xc0, 0x5b, 0x27, 0x02, 0xc3, 0xc6, 0x4d, 0xdf, 0x4c, 0xbf, 0xc8, 0x51, 0x67, 0x44, 0x2c,
0x40, 0xa5, 0x28, 0xe4, 0x66, 0xfe, 0x25, 0xe2, 0x3b, 0x0c, 0x46, 0x40, 0x6b, 0x24, 0x66, 0xc5,
0xcb, 0x1c, 0x01, 0x8d, 0xc2, 0x6b, 0xd4, 0x3d, 0x1c, 0x98, 0x4d, 0xaf, 0xf0, 0x35, 0xea, 0x9a,
0x0d, 0x30, 0x9b, 0x59, 0x3d, 0x35, 0x2b, 0x5e, 0xe5, 0x6c, 0x66, 0xeb, 0x71, 0x1b, 0xdd, 0xdd,
0xd6, 0xec, 0x78, 0x8d, 0xb7, 0xd1, 0xd5, 0x6c, 0xc5, 0x1a, 0x54, 0xf7, 0x76, 0x5a, 0xb3, 0xef,
0x75, 0xf2, 0x4d, 0xec, 0x69, 0xb4, 0xe2, 0x3e, 0x98, 0xee, 0xdd, 0x65, 0xcd, 0xd6, 0x73, 0x3b,
0x5d, 0x9f, 0x8b, 0xf4, 0x26, 0x2b, 0x8e, 0x77, 0xca, 0xb5, 0xde, 0x61, 0xcd, 0xda, 0xf3, 0x3b,
0xe5, 0x8a, 0xad, 0x37, 0x58, 0xb1, 0x08, 0xd0, 0x69, 0x6e, 0x66, 0xd7, 0x05, 0x72, 0x69, 0x10,
0x5e, 0x0d, 0xea, 0x6d, 0x66, 0xfe, 0x22, 0x5f, 0x0d, 0x22, 0xf0, 0x6a, 0x70, 0x5b, 0x33, 0xd3,
0x97, 0xf8, 0x6a, 0x30, 0x82, 0x27, 0x5b, 0xeb, 0x1c, 0x66, 0xc3, 0x65, 0x3e, 0xd9, 0x1a, 0x25,
0xe6, 0x60, 0x28, 0x48, 0x3d, 0x0f, 0x0f, 0x68, 0xf5, 0xe6, 0x1e, 0xed, 0x4a, 0x7a, 0x2d, 0xe6,
0x7f, 0xdb, 0xa5, 0x1d, 0x30, 0x20, 0x0e, 0xc1, 0x3e, 0xe9, 0x37, 0x64, 0xcb, 0x44, 0xfe, 0xbe,
0xcb, 0x45, 0x09, 0x57, 0x8b, 0x05, 0x80, 0xfc, 0xa3, 0x3d, 0xbe, 0x8a, 0x89, 0xfd, 0x63, 0x37,
0xff, 0x96, 0x41, 0x43, 0x3a, 0x82, 0xec, 0xc5, 0x0d, 0x82, 0xed, 0xb2, 0x20, 0x7b, 0xeb, 0xc3,
0x30, 0xf8, 0x48, 0xac, 0x82, 0xc4, 0x71, 0x4d, 0xf4, 0x9f, 0x44, 0xf3, 0x7a, 0x0c, 0x98, 0xaf,
0x22, 0x99, 0x38, 0x6e, 0x6c, 0x62, 0xff, 0x22, 0xb6, 0x00, 0x10, 0x6e, 0x3a, 0x71, 0x62, 0xf3,
0xde, 0x7f, 0x33, 0xcc, 0x00, 0x6e, 0x1a, 0x9f, 0x1f, 0x95, 0x5b, 0x26, 0xf6, 0x1f, 0xde, 0x34,
0xad, 0x17, 0xf3, 0x50, 0xc1, 0xc7, 0xec, 0x5b, 0x11, 0x13, 0xfc, 0x2f, 0xc1, 0x1d, 0x02, 0xff,
0x73, 0x9c, 0xb4, 0x92, 0xb6, 0x39, 0xd8, 0xff, 0x51, 0xa6, 0x79, 0xbd, 0x58, 0x84, 0xe1, 0x38,
0x69, 0xb5, 0x52, 0x9a, 0xaf, 0x0c, 0xf8, 0xff, 0xbb, 0xc5, 0x47, 0xee, 0x82, 0x39, 0xf2, 0x30,
0x4c, 0x36, 0x95, 0xdf, 0x0d, 0x1e, 0x81, 0x15, 0xb5, 0xa2, 0xd6, 0xb2, 0xab, 0xf8, 0xe0, 0xbc,
0xab, 0x66, 0x9a, 0xca, 0xf7, 0x55, 0x50, 0x73, 0xc2, 0xb0, 0x96, 0x28, 0xe5, 0xd5, 0x1a, 0x7e,
0xb6, 0x34, 0xff, 0x6a, 0xaf, 0x39, 0xe3, 0xca, 0x60, 0xa6, 0xe1, 0xd7, 0x3a, 0x75, 0xa9, 0x56,
0x4c, 0xc8, 0x57, 0x03, 0x00, 0x00, 0xff, 0xff, 0x24, 0x56, 0x45, 0x84, 0x1d, 0x14, 0x00, 0x00,
}

View File

@@ -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)
}

View File

@@ -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 = "go-common/app/tool/bmproto/protoc-gen-bm/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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
// 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.
package main
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)
}

View File

@@ -0,0 +1,86 @@
// 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.
package main
import (
"path"
"strings"
"go-common/app/tool/liverpc/protoc-gen-liverpc/gen/stringutils"
"github.com/golang/protobuf/protoc-gen-go/descriptor"
)
// 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
}
// goPackageName 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 stringutils.BaseName(f.GetName()), false
}
// 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
}

View File

@@ -0,0 +1,86 @@
package main
import (
"fmt"
"net/http"
"strings"
"go-common/app/tool/bmproto/protoc-gen-bm/extensions/gogoproto"
"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/protoc-gen-go/descriptor"
"google.golang.org/genproto/googleapis/api/annotations"
)
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
}
func getJsonTag(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()
}
type googleMethodOptionInfo struct {
Method string
PathPattern string
HTTPRule *annotations.HttpRule
}
// 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
}

View File

@@ -0,0 +1,34 @@
// 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.
package main
import (
"flag"
"fmt"
"os"
"go-common/app/tool/liverpc/protoc-gen-liverpc/gen"
)
func main() {
versionFlag := flag.Bool("version", false, "print version and exit")
flag.Parse()
if *versionFlag {
fmt.Println(gen.Version)
os.Exit(0)
}
g := bmGenerator()
gen.Main(g)
}

45
app/tool/cache/BUILD vendored Normal file
View File

@@ -0,0 +1,45 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_binary",
)
go_library(
name = "go_default_library",
srcs = [
"header_template.go",
"main.go",
"multi_template.go",
"none_template.go",
"single_template.go",
],
importpath = "go-common/app/tool/cache",
tags = ["automanaged"],
visibility = ["//visibility:private"],
deps = ["//app/tool/cache/common:go_default_library"],
)
go_binary(
name = "cache",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/tool/cache/common:all-srcs",
"//app/tool/cache/memcached:all-srcs",
"//app/tool/cache/testdata:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

56
app/tool/cache/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,56 @@
### tools/cache
##### Version 1.6.4
1. 修复某些参数下多make一次的问题
##### Version 1.6.3
1. 使用fanout替换cache包
##### Version 1.6.2
1. 改为使用errgroup提供的GOMAXPROCS方法 替换channel
##### Version 1.6.1
1. 弃用errgroup改用channel进行批量操作 防止线程饥饿
##### Version 1.6.0
1. 增加对metadata.WithContext的支持
##### Version 1.5.3
1. 优化gofmt提示
##### Version 1.5.2
1. 补充返回部分数据时的测试
2. 增加两种空缓存错误参数的检测
3. 支持// cache: 这样语法
##### Version 1.5.1
1. 批量模板中分批回源失败时候 返回部分数据
##### Version 1.5.0
1. 批量模板中改增加对数字类型0值返回的支持
##### Version 1.4.2
1. 修复回源失败 缓存数据未返回的问题
##### Version 1.4.1
1. 修复Hit计算问题
2. 由于mc已经有pkg/errors了 因此不再warp
3. 修复变量类型省略解析失败的问题
##### Version 1.4.0
1. 增加自定义注释和忽略参数的支持
##### Version 1.3.0
1. 增加batch_err选项 用于在分批发生错误的时候是否降级
##### Version 1.2.1
1. 回源错误的时候返回部分数据
##### Version 1.2.0
1. 解决saga提示无用代码的问题
##### Version 1.1.0
1. 去掉生成代码中的Cp前缀
##### Version 1.0.0
1. 添加基础模块与测试:
- 代码生成组件

8
app/tool/cache/CONTRIBUTORS.md vendored Normal file
View File

@@ -0,0 +1,8 @@
# Owner
zhapuyu
# Author
wangxu01
# Reviewer
zhapuyu

12
app/tool/cache/OWNERS vendored Normal file
View File

@@ -0,0 +1,12 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- wangxu01
- zhapuyu
labels:
- tool
options:
no_parent_owners: true
reviewers:
- wangxu01
- zhapuyu

23
app/tool/cache/README.md vendored Normal file
View File

@@ -0,0 +1,23 @@
#### tools/cache
> 缓存代码生成
##### 项目简介
从缓存中获取数据 如果miss则调用回源函数从数据源获取 然后塞入缓存
支持以下功能:
- 单飞限制回源并发 防止打爆数据源
- 空缓存 防止缓存穿透
- 分批获取数据 降低延时
- 默认异步加缓存 可选同步加缓存
- prometheus回源比监控
- 多行注释生成代码
- 支持分页(限单key模板)
- 自定义注释
- 支持忽略参数
##### 使用方式:
代码生成: 使用go generate方式生成 具体参数见[文档](http://info.bilibili.co/pages/viewpage.action?pageId=8462061)

28
app/tool/cache/common/BUILD vendored Normal file
View File

@@ -0,0 +1,28 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["common.go"],
importpath = "go-common/app/tool/cache/common",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

149
app/tool/cache/common/common.go vendored Normal file
View File

@@ -0,0 +1,149 @@
package common
import (
"fmt"
"go/ast"
"go/format"
"go/parser"
"go/token"
"io/ioutil"
"log"
"os"
"regexp"
"strings"
)
// Source source
type Source struct {
Fset *token.FileSet
Src string
F *ast.File
}
// NewSource new source
func NewSource(src string) *Source {
s := &Source{
Fset: token.NewFileSet(),
Src: src,
}
f, err := parser.ParseFile(s.Fset, "", src, 0)
if err != nil {
log.Fatal("无法解析源文件")
}
s.F = f
return s
}
// ExprString expr string
func (s *Source) ExprString(typ ast.Expr) string {
fset := s.Fset
s1 := fset.Position(typ.Pos()).Offset
s2 := fset.Position(typ.End()).Offset
return s.Src[s1:s2]
}
// pkgPath package path
func (s *Source) pkgPath(name string) (res string) {
for _, im := range s.F.Imports {
if im.Name != nil && im.Name.Name == name {
return im.Path.Value
}
}
for _, im := range s.F.Imports {
if strings.HasSuffix(im.Path.Value, name+"\"") {
return im.Path.Value
}
}
return
}
// GetDef get define code
func (s *Source) GetDef(name string) string {
c := s.F.Scope.Lookup(name).Decl.(*ast.TypeSpec).Type.(*ast.InterfaceType)
s1 := s.Fset.Position(c.Pos()).Offset
s2 := s.Fset.Position(c.End()).Offset
line := s.Fset.Position(c.Pos()).Line
lines := []string{strings.Split(s.Src, "\n")[line-1]}
for _, l := range strings.Split(s.Src[s1:s2], "\n")[1:] {
lines = append(lines, "\t"+l)
}
return strings.Join(lines, "\n")
}
// RegexpReplace replace regexp
func RegexpReplace(reg, src, temp string) string {
result := []byte{}
pattern := regexp.MustCompile(reg)
for _, submatches := range pattern.FindAllStringSubmatchIndex(src, -1) {
result = pattern.ExpandString(result, temp, src, submatches)
}
return string(result)
}
// formatPackage format package
func formatPackage(name, path string) (res string) {
if path != "" {
if strings.HasSuffix(path, name+"\"") {
res = path
return
}
res = fmt.Sprintf("%s %s", name, path)
}
return
}
// SourceText get source file text
func SourceText() string {
file := os.Getenv("GOFILE")
data, err := ioutil.ReadFile(file)
if err != nil {
log.Fatal("can't open file", file)
}
return string(data)
}
// FormatCode format code
func FormatCode(source string) string {
src, err := format.Source([]byte(source))
if err != nil {
// Should never happen, but can arise when developing this code.
// The user can compile the output to see the error.
log.Printf("warning: 输出文件不合法: %s", err)
log.Printf("warning: 详细错误请编译查看")
return source
}
return string(src)
}
// Packages get import packages
func (s *Source) Packages(f *ast.Field) (res []string) {
fs := f.Type.(*ast.FuncType).Params.List
fs = append(fs, f.Type.(*ast.FuncType).Results.List...)
var types []string
resMap := make(map[string]bool)
for _, field := range fs {
if p, ok := field.Type.(*ast.MapType); ok {
types = append(types, s.ExprString(p.Key))
types = append(types, s.ExprString(p.Value))
} else if p, ok := field.Type.(*ast.ArrayType); ok {
types = append(types, s.ExprString(p.Elt))
} else {
types = append(types, s.ExprString(field.Type))
}
}
for _, t := range types {
name := RegexpReplace(`(?P<pkg>\w+)\.\w+`, t, "$pkg")
if name == "" {
continue
}
pkg := formatPackage(name, s.pkgPath(name))
if !resMap[pkg] {
resMap[pkg] = true
}
}
for pkg := range resMap {
res = append(res, pkg)
}
return
}

3
app/tool/cache/gen vendored Normal file
View File

@@ -0,0 +1,3 @@
#! /bin/sh
DIR=$(dirname "$0")
go run $DIR/main.go $DIR/single_template.go $DIR/multi_template.go $DIR/none_template.go $DIR/header_template.go $@

31
app/tool/cache/header_template.go vendored Normal file
View File

@@ -0,0 +1,31 @@
package main
var _headerTemplate = `
// Code generated by $GOPATH/src/go-common/app/tool/cache/gen. DO NOT EDIT.
NEWLINE
/*
Package {{.PkgName}} is a generated cache proxy package.
It is generated from:
ARGS
*/
NEWLINE
package {{.PkgName}}
import (
"context"
{{if .EnableBatch }}"sync"{{end}}
NEWLINE
"go-common/library/stat/prom"
{{if .EnableBatch }}"go-common/library/sync/errgroup"{{end}}
{{.ImportPackage}}
NEWLINE
{{if .EnableSingleFlight}} "golang.org/x/sync/singleflight" {{end}}
)
var _ _cache
{{if .EnableSingleFlight}}
var cacheSingleFlights = [SFCOUNT]*singleflight.Group{SFINIT}
{{end }}
`

451
app/tool/cache/main.go vendored Normal file
View File

@@ -0,0 +1,451 @@
package main
import (
"bytes"
"flag"
"fmt"
"go/ast"
"io/ioutil"
"log"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"text/template"
"go-common/app/tool/cache/common"
)
var (
// arguments
singleFlight = flag.Bool("singleflight", false, "enable singleflight")
nullCache = flag.String("nullcache", "", "null cache")
checkNullCode = flag.String("check_null_code", "", "check null code")
batchSize = flag.Int("batch", 0, "batch size")
batchErr = flag.String("batch_err", "break", "batch err to contine or break")
maxGroup = flag.Int("max_group", 0, "max group size")
sync = flag.Bool("sync", false, "add cache in sync way.")
paging = flag.Bool("paging", false, "use paging in single template")
ignores = flag.String("ignores", "", "ignore params")
numberTypes = []string{"int", "int8", "int16", "int32", "int64", "float32", "float64", "uint", "uint8", "uint16", "uint32", "uint64"}
simpleTypes = []string{"int", "int8", "int16", "int32", "int64", "float32", "float64", "uint", "uint8", "uint16", "uint32", "uint64", "bool", "string", "[]byte"}
optionNames = []string{"singleflight", "nullcache", "check_null_code", "batch", "max_group", "sync", "paging", "ignores", "batch_err"}
optionNamesMap = map[string]bool{}
)
const (
_interfaceName = "_cache"
_multiTpl = 1
_singleTpl = 2
_noneTpl = 3
)
func resetFlag() {
*singleFlight = false
*nullCache = ""
*checkNullCode = ""
*batchSize = 0
*maxGroup = 0
*sync = false
*paging = false
*batchErr = "break"
*ignores = ""
}
// options options
type options struct {
name string
keyType string
valueType string
cacheFunc string
rawFunc string
addCacheFunc string
template int
SimpleValue bool
NumberValue bool
GoValue bool
ZeroValue string
ImportPackage string
importPackages []string
Args string
PkgName string
EnableSingleFlight bool
NullCache string
EnableNullCache bool
GroupSize int
MaxGroup int
EnableBatch bool
BatchErrBreak bool
Sync bool
CheckNullCode string
ExtraArgsType string
ExtraArgs string
ExtraCacheArgs string
ExtraRawArgs string
ExtraAddCacheArgs string
EnablePaging bool
Comment string
}
// parse parse options
func parse(s *common.Source) (opts []*options) {
f := s.F
fset := s.Fset
src := s.Src
c := f.Scope.Lookup(_interfaceName)
if (c == nil) || (c.Kind != ast.Typ) {
log.Fatalln("无法找到缓存声明")
}
lines := strings.Split(src, "\n")
lists := c.Decl.(*ast.TypeSpec).Type.(*ast.InterfaceType).Methods.List
for _, list := range lists {
opt := options{Args: s.GetDef(_interfaceName), importPackages: s.Packages(list)}
// get comment
line := fset.Position(list.Pos()).Line - 3
if len(lines)-1 >= line {
comment := lines[line]
opt.Comment = common.RegexpReplace(`\s+//(?P<name>.+)`, comment, "$name")
opt.Comment = strings.TrimSpace(opt.Comment)
}
// get options
line = fset.Position(list.Pos()).Line - 2
comment := lines[line]
os.Args = []string{os.Args[0]}
if regexp.MustCompile(`\s+//\s*cache:.+`).Match([]byte(comment)) {
args := strings.Split(common.RegexpReplace(`//\s*cache:(?P<arg>.+)`, comment, "$arg"), " ")
for _, arg := range args {
arg = strings.TrimSpace(arg)
if arg != "" {
// validate option name
argName := common.RegexpReplace(`-(?P<name>[\w_-]+)=.+`, arg, "$name")
if !optionNamesMap[argName] {
log.Fatalf("选项:%s 不存在 请检查拼写\n", argName)
}
os.Args = append(os.Args, arg)
}
}
}
resetFlag()
flag.Parse()
opt.EnableSingleFlight = *singleFlight
opt.NullCache = *nullCache
opt.EnablePaging = *paging
opt.EnableNullCache = *nullCache != ""
opt.EnableBatch = (*batchSize != 0) && (*maxGroup != 0)
opt.BatchErrBreak = *batchErr == "break"
opt.Sync = *sync
opt.CheckNullCode = *checkNullCode
opt.GroupSize = *batchSize
opt.MaxGroup = *maxGroup
// get func
opt.name = list.Names[0].Name
params := list.Type.(*ast.FuncType).Params.List
if len(params) == 0 {
log.Fatalln(opt.name + "参数不足")
}
if s.ExprString(params[0].Type) != "context.Context" {
log.Fatalln("第一个参数必须为context")
}
if len(params) == 1 {
opt.template = _noneTpl
} else {
if _, ok := params[1].Type.(*ast.ArrayType); ok {
opt.template = _multiTpl
} else {
opt.template = _singleTpl
// get key
opt.keyType = s.ExprString(params[1].Type)
}
}
if len(params) > 2 {
var args []string
var allArgs []string
for _, pa := range params[2:] {
paType := s.ExprString(pa.Type)
if len(pa.Names) == 0 {
args = append(args, paType)
allArgs = append(allArgs, paType)
continue
}
var names []string
for _, name := range pa.Names {
names = append(names, name.Name)
}
allArgs = append(allArgs, strings.Join(names, ",")+" "+paType)
args = append(args, names...)
}
opt.ExtraArgs = strings.Join(args, ",")
opt.ExtraArgsType = strings.Join(allArgs, ",")
argsMap := make(map[string]bool)
for _, arg := range args {
argsMap[arg] = true
}
ignoreCache := make(map[string]bool)
ignoreRaw := make(map[string]bool)
ignoreAddCache := make(map[string]bool)
ignoreArray := [3]map[string]bool{ignoreCache, ignoreRaw, ignoreAddCache}
if *ignores != "" {
is := strings.Split(*ignores, "|")
if len(is) > 3 {
log.Fatalln("ignores参数错误")
}
for i := range is {
if len(is) > i {
for _, s := range strings.Split(is[i], ",") {
ignoreArray[i][s] = true
}
}
}
}
var as []string
for _, arg := range args {
if !ignoreCache[arg] {
as = append(as, arg)
}
}
opt.ExtraCacheArgs = strings.Join(as, ",")
as = []string{}
for _, arg := range args {
if !ignoreRaw[arg] {
as = append(as, arg)
}
}
opt.ExtraRawArgs = strings.Join(as, ",")
as = []string{}
for _, arg := range args {
if !ignoreAddCache[arg] {
as = append(as, arg)
}
}
opt.ExtraAddCacheArgs = strings.Join(as, ",")
if opt.ExtraAddCacheArgs != "" {
opt.ExtraAddCacheArgs = "," + opt.ExtraAddCacheArgs
}
if opt.ExtraRawArgs != "" {
opt.ExtraRawArgs = "," + opt.ExtraRawArgs
}
if opt.ExtraCacheArgs != "" {
opt.ExtraCacheArgs = "," + opt.ExtraCacheArgs
}
if opt.ExtraArgs != "" {
opt.ExtraArgs = "," + opt.ExtraArgs
}
if opt.ExtraArgsType != "" {
opt.ExtraArgsType = "," + opt.ExtraArgsType
}
}
// get k v from results
results := list.Type.(*ast.FuncType).Results.List
if len(results) != 2 {
log.Fatalln(opt.name + ": 参数个数不对")
}
if s.ExprString(results[1].Type) != "error" {
log.Fatalln(opt.name + ": 最后返回值参数需为error")
}
if opt.template == _multiTpl {
p, ok := results[0].Type.(*ast.MapType)
if !ok {
log.Fatalln(opt.name + ": 批量获取方法 返回值类型需为map类型")
}
opt.keyType = s.ExprString(p.Key)
opt.valueType = s.ExprString(p.Value)
} else {
opt.valueType = s.ExprString(results[0].Type)
}
for _, t := range numberTypes {
if t == opt.valueType {
opt.NumberValue = true
break
}
}
opt.ZeroValue = "nil"
for _, t := range simpleTypes {
if t == opt.valueType {
opt.SimpleValue = true
opt.ZeroValue = zeroValue(t)
break
}
}
if !opt.SimpleValue {
for _, t := range []string{"[]", "map"} {
if strings.HasPrefix(opt.valueType, t) {
opt.GoValue = true
break
}
}
}
upperName := strings.ToUpper(opt.name[0:1]) + opt.name[1:]
opt.cacheFunc = fmt.Sprintf("d.Cache%s", upperName)
opt.rawFunc = fmt.Sprintf("d.Raw%s", upperName)
opt.addCacheFunc = fmt.Sprintf("d.AddCache%s", upperName)
opt.Check()
opts = append(opts, &opt)
}
return
}
func (option *options) Check() {
if !option.SimpleValue && !strings.Contains(option.valueType, "*") && !strings.Contains(option.valueType, "[]") && !strings.Contains(option.valueType, "map") {
log.Fatalf("%s: 值类型只能为基本类型/slice/map/指针类型\n", option.name)
}
if option.EnableSingleFlight && option.EnableBatch {
log.Fatalf("%s: 单飞和批量获取不能同时开启\n", option.name)
}
if option.template != _singleTpl && option.EnablePaging {
log.Fatalf("%s: 分页只能用在单key模板中\n", option.name)
}
if option.SimpleValue && !option.EnableNullCache {
if !((option.template == _multiTpl) && option.NumberValue) {
log.Fatalf("%s: 值为基本类型时需开启空缓存 防止缓存零值穿透\n", option.name)
}
}
if option.EnableNullCache {
if !option.SimpleValue && option.CheckNullCode == "" {
log.Fatalf("%s: 缺少-check_null_code参数\n", option.name)
}
if option.SimpleValue && option.NullCache == option.ZeroValue {
log.Fatalf("%s: %s 不能作为空缓存值 \n", option.name, option.NullCache)
}
if strings.Contains(option.NullCache, "{}") {
// -nullcache=[]*model.OrderMain{} 这种无效
log.Fatalf("%s: %s 不能作为空缓存值 会导致空缓存无效 \n", option.name, option.NullCache)
}
if strings.Contains(option.CheckNullCode, "len") && strings.Contains(strings.Replace(option.CheckNullCode, " ", "", -1), "==0") {
// -check_null_code=len($)==0 这种无效
log.Fatalf("%s: -check_null_code=%s 错误 会有无意义的赋值\n", option.name, option.CheckNullCode)
}
}
}
func genHeader(opts []*options) (src string) {
option := options{PkgName: os.Getenv("GOPACKAGE")}
var sfCount int
var packages, sfInit []string
packagesMap := map[string]bool{`"context"`: true}
for _, opt := range opts {
if opt.EnableSingleFlight {
option.EnableSingleFlight = true
sfCount++
}
if opt.EnableBatch {
option.EnableBatch = true
}
if len(opt.importPackages) > 0 {
for _, pkg := range opt.importPackages {
if !packagesMap[pkg] {
packages = append(packages, pkg)
packagesMap[pkg] = true
}
}
}
if opt.Args != "" {
option.Args = opt.Args
}
}
option.ImportPackage = strings.Join(packages, "\n")
for i := 0; i < sfCount; i++ {
sfInit = append(sfInit, "{}")
}
src = _headerTemplate
src = strings.Replace(src, "SFCOUNT", strconv.Itoa(sfCount), -1)
t := template.Must(template.New("header").Parse(src))
var buffer bytes.Buffer
err := t.Execute(&buffer, option)
if err != nil {
log.Fatalf("execute template: %s", err)
}
// Format the output.
src = strings.Replace(buffer.String(), "\t", "", -1)
src = regexp.MustCompile("\n+").ReplaceAllString(src, "\n")
src = strings.Replace(src, "NEWLINE", "", -1)
src = strings.Replace(src, "ARGS", option.Args, -1)
src = strings.Replace(src, "SFINIT", strings.Join(sfInit, ","), -1)
return
}
func genBody(opts []*options) (res string) {
sfnum := -1
for _, option := range opts {
var nullCodeVar, src string
if option.template == _multiTpl {
src = _multiTemplate
nullCodeVar = "v"
} else if option.template == _singleTpl {
src = _singleTemplate
nullCodeVar = "res"
} else {
src = _noneTemplate
nullCodeVar = "res"
}
if option.template != _noneTpl {
src = strings.Replace(src, "KEY", option.keyType, -1)
}
if option.CheckNullCode != "" {
option.CheckNullCode = strings.Replace(option.CheckNullCode, "$", nullCodeVar, -1)
}
if option.EnableSingleFlight {
sfnum++
}
src = strings.Replace(src, "NAME", option.name, -1)
src = strings.Replace(src, "VALUE", option.valueType, -1)
src = strings.Replace(src, "ADDCACHEFUNC", option.addCacheFunc, -1)
src = strings.Replace(src, "CACHEFUNC", option.cacheFunc, -1)
src = strings.Replace(src, "RAWFUNC", option.rawFunc, -1)
src = strings.Replace(src, "GROUPSIZE", strconv.Itoa(option.GroupSize), -1)
src = strings.Replace(src, "MAXGROUP", strconv.Itoa(option.MaxGroup), -1)
src = strings.Replace(src, "SFNUM", strconv.Itoa(sfnum), -1)
t := template.Must(template.New("cache").Parse(src))
var buffer bytes.Buffer
err := t.Execute(&buffer, option)
if err != nil {
log.Fatalf("execute template: %s", err)
}
// Format the output.
src = strings.Replace(buffer.String(), "\t", "", -1)
src = regexp.MustCompile("\n+").ReplaceAllString(src, "\n")
res = res + "\n" + src
}
return
}
func zeroValue(t string) string {
switch t {
case "bool":
return "false"
case "string":
return "\"\""
case "[]byte":
return "nil"
default:
return "0"
}
}
func init() {
for _, name := range optionNames {
optionNamesMap[name] = true
}
}
func main() {
log.SetFlags(0)
defer func() {
if err := recover(); err != nil {
log.Fatalf("程序解析失败, err: %+v 请企业微信联系 @wangxu01", err)
}
}()
options := parse(common.NewSource(common.SourceText()))
header := genHeader(options)
body := genBody(options)
code := common.FormatCode(header + "\n" + body)
// Write to file.
dir := filepath.Dir(".")
outputName := filepath.Join(dir, "dao.cache.go")
err := ioutil.WriteFile(outputName, []byte(code), 0644)
if err != nil {
log.Fatalf("写入文件失败: %s", err)
}
log.Println("dao.cache.go: 生成成功")
}

4
app/tool/cache/mc vendored Normal file
View File

@@ -0,0 +1,4 @@
#! /bin/sh
DIR=$(dirname "$0")
DIR="$DIR/memcached"
go run $DIR/main.go $DIR/header_template.go $DIR/none_template.go $DIR/single_template.go $DIR/multi_template.go $@

45
app/tool/cache/memcached/BUILD vendored Normal file
View File

@@ -0,0 +1,45 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "memcached",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = [
"header_template.go",
"main.go",
"multi_template.go",
"none_template.go",
"single_template.go",
],
importpath = "go-common/app/tool/cache/memcached",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//app/tool/cache/common:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/tool/cache/memcached/testdata:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

11
app/tool/cache/memcached/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,11 @@
### tools/cache/memcached
##### Version 1.1.1
1. 修复返回值为string []byte无法正常生成的问题
##### Version 1.1.0
1. 支持分批获取
##### Version 1.0.0
1. 添加基础模块与测试

24
app/tool/cache/memcached/README.md vendored Normal file
View File

@@ -0,0 +1,24 @@
#### tools/cache/mc
> mc缓存代码生成
##### 项目简介
自动生成memcached缓存代码 和缓存回源工具配合使用 体验更佳
支持以下功能:
- 常用mc命令(get/set/add/replace/delete)
- 多种数据存储格式(json/pb/raw/gob/gzip)
- 常用值类型自动转换(int/bool/float...)
- 自定义缓存名称和过期时间
- 记录pkg/error错误栈
- 记录日志trace id
- prometheus错误监控
- 自定义参数个数
- 自定义注释
##### 使用方式:
代码生成: 使用go generate方式生成 具体参数见[文档](http://info.bilibili.co/pages/viewpage.action?pageId=8471941)

View File

@@ -0,0 +1,30 @@
package main
var _headerTemplate = `
// Code generated by $GOPATH/src/go-common/app/tool/cache/mc. DO NOT EDIT.
NEWLINE
/*
Package {{.PkgName}} is a generated mc cache package.
It is generated from:
ARGS
*/
NEWLINE
package {{.PkgName}}
import (
"context"
"fmt"
{{if .UseStrConv}}"strconv"{{end}}
{{if .EnableBatch }}"sync"{{end}}
NEWLINE
"go-common/library/stat/prom"
{{if .UseMemcached }}"go-common/library/cache/memcache"{{end}}
{{if .EnableBatch }}"go-common/library/sync/errgroup"{{end}}
"go-common/library/log"
{{.ImportPackage}}
)
var _ _mc
`

517
app/tool/cache/memcached/main.go vendored Normal file
View File

@@ -0,0 +1,517 @@
package main
import (
"bytes"
"flag"
"go/ast"
"io/ioutil"
"log"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"text/template"
"go-common/app/tool/cache/common"
)
var (
encode = flag.String("encode", "", "encode type: json/pb/raw/gob/gzip")
mcType = flag.String("type", "", "type: get/set/del/replace/only_add")
key = flag.String("key", "", "key name method")
expire = flag.String("expire", "", "expire time code")
batchSize = flag.Int("batch", 0, "batch size")
batchErr = flag.String("batch_err", "break", "batch err to contine or break")
maxGroup = flag.Int("max_group", 0, "max group size")
mcValidTypes = []string{"set", "replace", "del", "get", "only_add"}
mcValidPrefix = []string{"set", "replace", "del", "get", "cache", "add"}
optionNamesMap = map[string]bool{"batch": true, "max_group": true, "encode": true, "type": true, "key": true, "expire": true, "batch_err": true}
simpleTypes = []string{"int", "int8", "int16", "int32", "int64", "float32", "float64", "uint", "uint8", "uint16", "uint32", "uint64", "bool", "string", "[]byte"}
lenTypes = []string{"[]", "map"}
)
const (
_interfaceName = "_mc"
_multiTpl = 1
_singleTpl = 2
_noneTpl = 3
_typeGet = "get"
_typeSet = "set"
_typeDel = "del"
_typeReplace = "replace"
_typeAdd = "only_add"
)
func resetFlag() {
*encode = ""
*mcType = ""
*batchSize = 0
*maxGroup = 0
*batchErr = "break"
}
// options options
type options struct {
name string
keyType string
ValueType string
template int
SimpleValue bool
// int float 类型
GetSimpleValue bool
// string, []byte类型
GetDirectValue bool
ConvertValue2Bytes string
ConvertBytes2Value string
GoValue bool
ImportPackage string
importPackages []string
Args string
PkgName string
ExtraArgsType string
ExtraArgs string
MCType string
KeyMethod string
ExpireCode string
Encode string
UseMemcached bool
InitValue bool
OriginValueType string
UseStrConv bool
Comment string
GroupSize int
MaxGroup int
EnableBatch bool
BatchErrBreak bool
LenType bool
PointType bool
}
func parse(s *common.Source) (opts []*options) {
f := s.F
fset := s.Fset
src := s.Src
c := f.Scope.Lookup(_interfaceName)
if (c == nil) || (c.Kind != ast.Typ) {
log.Fatalln("无法找到缓存声明")
}
lines := strings.Split(src, "\n")
lists := c.Decl.(*ast.TypeSpec).Type.(*ast.InterfaceType).Methods.List
for _, list := range lists {
opt := options{Args: s.GetDef(_interfaceName), UseMemcached: true, importPackages: s.Packages(list)}
opt.name = list.Names[0].Name
opt.KeyMethod = "key" + opt.name
opt.ExpireCode = "d.mc" + opt.name + "Expire"
// get comment
line := fset.Position(list.Pos()).Line - 3
if len(lines)-1 >= line {
comment := lines[line]
opt.Comment = common.RegexpReplace(`\s+//(?P<name>.+)`, comment, "$name")
opt.Comment = strings.TrimSpace(opt.Comment)
}
// get options
line = fset.Position(list.Pos()).Line - 2
comment := lines[line]
os.Args = []string{os.Args[0]}
if regexp.MustCompile(`\s+//\s*mc:.+`).Match([]byte(comment)) {
args := strings.Split(common.RegexpReplace(`//\s*mc:(?P<arg>.+)`, comment, "$arg"), " ")
for _, arg := range args {
arg = strings.TrimSpace(arg)
if arg != "" {
// validate option name
argName := common.RegexpReplace(`-(?P<name>[\w_-]+)=.+`, arg, "$name")
if !optionNamesMap[argName] {
log.Fatalf("选项:%s 不存在 请检查拼写\n", argName)
}
os.Args = append(os.Args, arg)
}
}
}
resetFlag()
flag.Parse()
if *mcType != "" {
opt.MCType = *mcType
}
if *key != "" {
opt.KeyMethod = *key
}
if *expire != "" {
opt.ExpireCode = *expire
}
opt.EnableBatch = (*batchSize != 0) && (*maxGroup != 0)
opt.BatchErrBreak = *batchErr == "break"
opt.GroupSize = *batchSize
opt.MaxGroup = *maxGroup
// get type from prefix
if opt.MCType == "" {
for _, t := range mcValidPrefix {
if strings.HasPrefix(strings.ToLower(opt.name), t) {
if t == "add" {
t = _typeSet
}
opt.MCType = t
break
}
}
if opt.MCType == "" {
log.Fatalln(opt.name + "请指定方法类型(type=get/set/del...)")
}
}
if opt.MCType == "cache" {
opt.MCType = _typeGet
}
params := list.Type.(*ast.FuncType).Params.List
if len(params) == 0 {
log.Fatalln(opt.name + "参数不足")
}
if s.ExprString(params[0].Type) != "context.Context" {
log.Fatalln(opt.name + "第一个参数必须为context")
}
for _, param := range params {
if len(param.Names) > 1 {
log.Fatalln(opt.name + "不支持省略类型")
}
}
// get template
if len(params) == 1 {
opt.template = _noneTpl
} else if (len(params) == 2) && (opt.MCType == _typeSet || opt.MCType == _typeAdd || opt.MCType == _typeReplace) {
if _, ok := params[1].Type.(*ast.MapType); ok {
opt.template = _multiTpl
} else {
opt.template = _noneTpl
}
} else {
if _, ok := params[1].Type.(*ast.ArrayType); ok {
opt.template = _multiTpl
} else {
opt.template = _singleTpl
}
}
// extra args
if len(params) > 2 {
args := []string{""}
allArgs := []string{""}
var pos = 2
if (opt.MCType == _typeAdd) || (opt.MCType == _typeSet) || (opt.MCType == _typeReplace) {
pos = 3
}
for _, pa := range params[pos:] {
paType := s.ExprString(pa.Type)
if len(pa.Names) == 0 {
args = append(args, paType)
allArgs = append(allArgs, paType)
continue
}
var names []string
for _, name := range pa.Names {
names = append(names, name.Name)
}
allArgs = append(allArgs, strings.Join(names, ",")+" "+paType)
args = append(args, strings.Join(names, ","))
}
if len(args) > 1 {
opt.ExtraArgs = strings.Join(args, ",")
opt.ExtraArgsType = strings.Join(allArgs, ",")
}
}
// get k v from results
results := list.Type.(*ast.FuncType).Results.List
if s.ExprString(results[len(results)-1].Type) != "error" {
log.Fatalln("最后返回值参数需为error")
}
for _, res := range results {
if len(res.Names) > 1 {
log.Fatalln(opt.name + "返回值不支持省略类型")
}
}
if opt.MCType == _typeGet {
if len(results) != 2 {
log.Fatalln("参数个数不对")
}
}
// get key type and value type
if (opt.MCType == _typeAdd) || (opt.MCType == _typeSet) || (opt.MCType == _typeReplace) {
if opt.template == _multiTpl {
p, ok := params[1].Type.(*ast.MapType)
if !ok {
log.Fatalf("%s: 参数类型错误 批量设置数据时类型需为map类型\n", opt.name)
}
opt.keyType = s.ExprString(p.Key)
opt.ValueType = s.ExprString(p.Value)
} else if opt.template == _singleTpl {
opt.keyType = s.ExprString(params[1].Type)
opt.ValueType = s.ExprString(params[2].Type)
} else {
opt.ValueType = s.ExprString(params[1].Type)
}
}
if opt.MCType == _typeGet {
if opt.template == _multiTpl {
if p, ok := results[0].Type.(*ast.MapType); ok {
opt.keyType = s.ExprString(p.Key)
opt.ValueType = s.ExprString(p.Value)
} else {
log.Fatalf("%s: 返回值类型错误 批量获取数据时返回值需为map类型\n", opt.name)
}
} else if opt.template == _singleTpl {
opt.keyType = s.ExprString(params[1].Type)
opt.ValueType = s.ExprString(results[0].Type)
} else {
opt.ValueType = s.ExprString(results[0].Type)
}
}
if opt.MCType == _typeDel {
if opt.template == _multiTpl {
p, ok := params[1].Type.(*ast.ArrayType)
if !ok {
log.Fatalf("%s: 类型错误 参数需为[]类型\n", opt.name)
}
opt.keyType = s.ExprString(p.Elt)
} else if opt.template == _singleTpl {
opt.keyType = s.ExprString(params[1].Type)
}
}
for _, t := range simpleTypes {
if t == opt.ValueType {
opt.SimpleValue = true
opt.GetSimpleValue = true
opt.ConvertValue2Bytes = convertValue2Bytes(t)
opt.ConvertBytes2Value = convertBytes2Value(t)
break
}
}
if opt.ValueType == "string" {
opt.LenType = true
} else {
for _, t := range lenTypes {
if strings.HasPrefix(opt.ValueType, t) {
opt.LenType = true
break
}
}
}
if opt.SimpleValue && (opt.ValueType == "[]byte" || opt.ValueType == "string") {
opt.GetSimpleValue = false
opt.GetDirectValue = true
}
if opt.MCType == _typeGet && opt.template == _multiTpl {
opt.UseMemcached = false
}
if strings.HasPrefix(opt.ValueType, "*") {
opt.InitValue = true
opt.PointType = true
opt.OriginValueType = strings.Replace(opt.ValueType, "*", "", 1)
} else {
opt.OriginValueType = opt.ValueType
}
if *encode != "" {
var flags []string
for _, f := range strings.Split(*encode, "|") {
switch f {
case "gob":
flags = append(flags, "memcache.FlagGOB")
case "json":
flags = append(flags, "memcache.FlagJSON")
case "raw":
flags = append(flags, "memcache.FlagRAW")
case "pb":
flags = append(flags, "memcache.FlagProtobuf")
case "gzip":
flags = append(flags, "memcache.FlagGzip")
default:
log.Fatalf("%s: encode类型无效\n", opt.name)
}
}
opt.Encode = strings.Join(flags, " | ")
} else {
if opt.SimpleValue {
opt.Encode = "memcache.FlagRAW"
} else {
opt.Encode = "memcache.FlagJSON"
}
}
opt.Check()
opts = append(opts, &opt)
}
return
}
func (option *options) Check() {
var valid bool
for _, x := range mcValidTypes {
if x == option.MCType {
valid = true
break
}
}
if !valid {
log.Fatalf("%s: 类型错误 不支持%s类型\n", option.name, option.MCType)
}
if (option.MCType != _typeDel) && !option.SimpleValue && !strings.Contains(option.ValueType, "*") && !strings.Contains(option.ValueType, "[]") && !strings.Contains(option.ValueType, "map") {
log.Fatalf("%s: 值类型只能为基本类型/slice/map/指针类型\n", option.name)
}
}
func genHeader(opts []*options) (src string) {
option := options{PkgName: os.Getenv("GOPACKAGE"), UseMemcached: false}
var packages []string
packagesMap := map[string]bool{`"context"`: true}
for _, opt := range opts {
if len(opt.importPackages) > 0 {
for _, pkg := range opt.importPackages {
if !packagesMap[pkg] {
packages = append(packages, pkg)
packagesMap[pkg] = true
}
}
}
if opt.Args != "" {
option.Args = opt.Args
}
if opt.UseMemcached {
option.UseMemcached = true
}
if opt.SimpleValue && !opt.GetDirectValue {
option.UseStrConv = true
}
if opt.EnableBatch {
option.EnableBatch = true
}
}
option.ImportPackage = strings.Join(packages, "\n")
src = _headerTemplate
t := template.Must(template.New("header").Parse(src))
var buffer bytes.Buffer
err := t.Execute(&buffer, option)
if err != nil {
log.Fatalf("execute template: %s", err)
}
// Format the output.
src = strings.Replace(buffer.String(), "\t", "", -1)
src = regexp.MustCompile("\n+").ReplaceAllString(src, "\n")
src = strings.Replace(src, "NEWLINE", "", -1)
src = strings.Replace(src, "ARGS", option.Args, -1)
return
}
func genBody(opts []*options) (res string) {
for _, option := range opts {
var src string
if option.template == _multiTpl {
switch option.MCType {
case _typeGet:
src = _multiGetTemplate
case _typeSet:
src = _multiSetTemplate
case _typeReplace:
src = _multiReplaceTemplate
case _typeDel:
src = _multiDelTemplate
case _typeAdd:
src = _multiAddTemplate
}
} else if option.template == _singleTpl {
switch option.MCType {
case _typeGet:
src = _singleGetTemplate
case _typeSet:
src = _singleSetTemplate
case _typeReplace:
src = _singleReplaceTemplate
case _typeDel:
src = _singleDelTemplate
case _typeAdd:
src = _singleAddTemplate
}
} else {
switch option.MCType {
case _typeGet:
src = _noneGetTemplate
case _typeSet:
src = _noneSetTemplate
case _typeReplace:
src = _noneReplaceTemplate
case _typeDel:
src = _noneDelTemplate
case _typeAdd:
src = _noneAddTemplate
}
}
src = strings.Replace(src, "KEY", option.keyType, -1)
src = strings.Replace(src, "NAME", option.name, -1)
src = strings.Replace(src, "VALUE", option.ValueType, -1)
src = strings.Replace(src, "GROUPSIZE", strconv.Itoa(option.GroupSize), -1)
src = strings.Replace(src, "MAXGROUP", strconv.Itoa(option.MaxGroup), -1)
t := template.Must(template.New("cache").Parse(src))
var buffer bytes.Buffer
err := t.Execute(&buffer, option)
if err != nil {
log.Fatalf("execute template: %s", err)
}
// Format the output.
src = strings.Replace(buffer.String(), "\t", "", -1)
src = regexp.MustCompile("\n+").ReplaceAllString(src, "\n")
res = res + "\n" + src
}
return
}
func main() {
log.SetFlags(0)
defer func() {
if err := recover(); err != nil {
log.Fatalf("程序解析失败, err: %+v 请企业微信联系 @wangxu01", err)
}
}()
options := parse(common.NewSource(common.SourceText()))
header := genHeader(options)
body := genBody(options)
code := common.FormatCode(header + "\n" + body)
// Write to file.
dir := filepath.Dir(".")
outputName := filepath.Join(dir, "mc.cache.go")
err := ioutil.WriteFile(outputName, []byte(code), 0644)
if err != nil {
log.Fatalf("写入文件失败: %s", err)
}
log.Println("mc.cache.go: 生成成功")
}
func convertValue2Bytes(t string) string {
switch t {
case "int", "int8", "int16", "int32", "int64":
return "[]byte(strconv.FormatInt(int64(val), 10))"
case "uint", "uint8", "uint16", "uint32", "uint64":
return "[]byte(strconv.FormatUInt(val, 10))"
case "bool":
return "[]byte(strconv.FormatBool(val))"
case "float32":
return "[]byte(strconv.FormatFloat(val, 'E', -1, 32))"
case "float64":
return "[]byte(strconv.FormatFloat(val, 'E', -1, 64))"
case "string":
return "[]byte(val)"
case "[]byte":
return "val"
}
return ""
}
func convertBytes2Value(t string) string {
switch t {
case "int", "int8", "int16", "int32", "int64":
return "strconv.ParseInt(v, 10, 64)"
case "uint", "uint8", "uint16", "uint32", "uint64":
return "strconv.ParseUInt(v, 10, 64)"
case "bool":
return "strconv.ParseBool(v)"
case "float32":
return "float32(strconv.ParseFloat(v, 32))"
case "float64":
return "strconv.ParseFloat(v, 64)"
}
return ""
}

View File

@@ -0,0 +1,217 @@
package main
import (
"strings"
)
var _multiGetTemplate = `
// NAME {{or .Comment "get data from mc"}}
func (d *Dao) NAME(c context.Context, ids []KEY {{.ExtraArgsType}}) (res map[KEY]VALUE, err error) {
l := len(ids)
if l == 0 {
return
}
{{if .EnableBatch}}
mutex := sync.Mutex{}
for i:=0;i < l; i+= GROUPSIZE * MAXGROUP {
var subKeys []KEY
{{if .BatchErrBreak}}
group, ctx := errgroup.WithContext(c)
{{else}}
group := &errgroup.Group{}
ctx := c
{{end}}
if (i + GROUPSIZE * MAXGROUP) > l {
subKeys = ids[i:]
} else {
subKeys = ids[i : i+GROUPSIZE * MAXGROUP]
}
subLen := len(subKeys)
for j:=0; j< subLen; j += GROUPSIZE {
var ks []KEY
if (j+GROUPSIZE) > subLen {
ks = subKeys[j:]
} else {
ks = subKeys[j:j+GROUPSIZE]
}
group.Go(func() (err error) {
keysMap := make(map[string]KEY, len(ks))
keys := make([]string, 0, len(ks))
for _, id := range ks {
key := {{.KeyMethod}}(id{{.ExtraArgs}})
keysMap[key] = id
keys = append(keys, key)
}
conn := d.mc.Get(ctx)
defer conn.Close()
replies, err := conn.GetMulti(keys)
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(ctx, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("keys", keys))
return
}
for key, reply := range replies {
{{if .GetSimpleValue}}
var v string
err = conn.Scan(reply, &v)
{{else}}
var v VALUE
{{if .GetDirectValue}}
err = conn.Scan(reply, &v)
{{else}}
{{if .InitValue}}
v = &{{.OriginValueType}}{}
err = conn.Scan(reply, res)
{{else}}
v = {{.OriginValueType}}{}
err = conn.Scan(reply, &res)
{{end}}
{{end}}
{{end}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(ctx, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
{{if .GetSimpleValue}}
r, err := {{.ConvertBytes2Value}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(ctx, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return res, err
}
mutex.Lock()
if res == nil {
res = make(map[KEY]VALUE, len(keys))
}
res[keysMap[key]] = {{.ValueType}}(r)
mutex.Unlock()
{{else}}
mutex.Lock()
if res == nil {
res = make(map[KEY]VALUE, len(keys))
}
res[keysMap[key]] = v
mutex.Unlock()
{{end}}
}
return
})
}
err1 := group.Wait()
if err1 != nil {
err = err1
{{if .BatchErrBreak}}
break
{{end}}
}
}
{{else}}
keysMap := make(map[string]KEY, l)
keys := make([]string, 0, l)
for _, id := range ids {
key := {{.KeyMethod}}(id{{.ExtraArgs}})
keysMap[key] = id
keys = append(keys, key)
}
conn := d.mc.Get(c)
defer conn.Close()
replies, err := conn.GetMulti(keys)
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("keys", keys))
return
}
for key, reply := range replies {
{{if .GetSimpleValue}}
var v string
err = conn.Scan(reply, &v)
{{else}}
var v VALUE
{{if .InitValue}}
v = &{{.OriginValueType}}{}
err = conn.Scan(reply, v)
{{else}}
v = {{.OriginValueType}}{}
err = conn.Scan(reply, &v)
{{end}}
{{end}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
{{if .GetSimpleValue}}
r, err := {{.ConvertBytes2Value}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return res, err
}
if res == nil {
res = make(map[KEY]VALUE, len(keys))
}
res[keysMap[key]] = {{.ValueType}}(r)
{{else}}
if res == nil {
res = make(map[KEY]VALUE, len(keys))
}
res[keysMap[key]] = v
{{end}}
}
{{end}}
return
}
`
var _multiSetTemplate = `
// NAME {{or .Comment "Set data to mc"}}
func (d *Dao) NAME(c context.Context, values map[KEY]VALUE {{.ExtraArgsType}}) (err error) {
if len(values) == 0 {
return
}
conn := d.mc.Get(c)
defer conn.Close()
for id, val := range values {
key := {{.KeyMethod}}(id{{.ExtraArgs}})
{{if .SimpleValue}}
bs := {{.ConvertValue2Bytes}}
item := &memcache.Item{Key: key, Value: bs, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}}
{{else}}
item := &memcache.Item{Key: key, Object: val, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}}
{{end}}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
}
return
}
`
var _multiAddTemplate = strings.Replace(_multiSetTemplate, "Set", "Add", -1)
var _multiReplaceTemplate = strings.Replace(_multiSetTemplate, "Set", "Replace", -1)
var _multiDelTemplate = `
// NAME {{or .Comment "delete data from mc"}}
func (d *Dao) NAME(c context.Context, ids []KEY {{.ExtraArgsType}}) (err error) {
if len(ids) == 0 {
return
}
conn := d.mc.Get(c)
defer conn.Close()
for _, id := range ids {
key := {{.KeyMethod}}(id{{.ExtraArgs}})
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
continue
}
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
}
return
}
`

View File

@@ -0,0 +1,107 @@
package main
import (
"strings"
)
var _noneGetTemplate = `
// NAME {{or .Comment "get data from mc"}}
func (d *Dao) NAME(c context.Context) (res VALUE, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := {{.KeyMethod}}()
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
{{if .GetSimpleValue}}
var v string
err = conn.Scan(reply, &v)
{{else}}
{{if .GetDirectValue}}
err = conn.Scan(reply, &res)
{{else}}
{{if .InitValue}}
res = &{{.OriginValueType}}{}
err = conn.Scan(reply, res)
{{else}}
res = {{.OriginValueType}}{}
err = conn.Scan(reply, &res)
{{end}}
{{end}}
{{end}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
{{if .GetSimpleValue}}
r, err := {{.ConvertBytes2Value}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = {{.ValueType}}(r)
{{end}}
return
}
`
var _noneSetTemplate = `
// NAME {{or .Comment "Set data to mc"}}
func (d *Dao) NAME(c context.Context, val VALUE) (err error) {
{{if .PointType}}
if val == nil {
return
}
{{end}}
{{if .LenType}}
if len(val) == 0 {
return
}
{{end}}
conn := d.mc.Get(c)
defer conn.Close()
key := {{.KeyMethod}}()
{{if .SimpleValue}}
bs := {{.ConvertValue2Bytes}}
item := &memcache.Item{Key: key, Value: bs, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}}
{{else}}
item := &memcache.Item{Key: key, Object: val, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}}
{{end}}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
`
var _noneAddTemplate = strings.Replace(_noneSetTemplate, "Set", "Add", -1)
var _noneReplaceTemplate = strings.Replace(_noneSetTemplate, "Set", "Replace", -1)
var _noneDelTemplate = `
// NAME {{or .Comment "delete data from mc"}}
func (d *Dao) NAME(c context.Context) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := {{.KeyMethod}}()
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
`

View File

@@ -0,0 +1,107 @@
package main
import (
"strings"
)
var _singleGetTemplate = `
// NAME {{or .Comment "get data from mc"}}
func (d *Dao) NAME(c context.Context, id KEY {{.ExtraArgsType}}) (res VALUE, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := {{.KeyMethod}}(id{{.ExtraArgs}})
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
{{if .GetSimpleValue}}
var v string
err = conn.Scan(reply, &v)
{{else}}
{{if .GetDirectValue}}
err = conn.Scan(reply, &res)
{{else}}
{{if .InitValue}}
res = &{{.OriginValueType}}{}
err = conn.Scan(reply, res)
{{else}}
res = {{.OriginValueType}}{}
err = conn.Scan(reply, &res)
{{end}}
{{end}}
{{end}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
{{if .GetSimpleValue}}
r, err := {{.ConvertBytes2Value}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = {{.ValueType}}(r)
{{end}}
return
}
`
var _singleSetTemplate = `
// NAME {{or .Comment "Set data to mc"}}
func (d *Dao) NAME(c context.Context, id KEY, val VALUE {{.ExtraArgsType}}) (err error) {
{{if .PointType}}
if val == nil {
return
}
{{end}}
{{if .LenType}}
if len(val) == 0 {
return
}
{{end}}
conn := d.mc.Get(c)
defer conn.Close()
key := {{.KeyMethod}}(id{{.ExtraArgs}})
{{if .SimpleValue}}
bs := {{.ConvertValue2Bytes}}
item := &memcache.Item{Key: key, Value: bs, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}}
{{else}}
item := &memcache.Item{Key: key, Object: val, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}}
{{end}}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
`
var _singleAddTemplate = strings.Replace(_singleSetTemplate, "Set", "Add", -1)
var _singleReplaceTemplate = strings.Replace(_singleSetTemplate, "Set", "Replace", -1)
var _singleDelTemplate = `
// NAME {{or .Comment "delete data from mc"}}
func (d *Dao) NAME(c context.Context, id KEY {{.ExtraArgsType}}) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := {{.KeyMethod}}(id{{.ExtraArgs}})
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
`

71
app/tool/cache/memcached/testdata/BUILD vendored Normal file
View File

@@ -0,0 +1,71 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
proto_library(
name = "model_proto",
srcs = ["model.proto"],
tags = ["automanaged"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "model_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_proto"],
importpath = "go-common/app/tool/cache/memcached/testdata",
proto = ":model_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)
go_test(
name = "go_default_test",
srcs = ["dao_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"mc.cache.go",
],
embed = [":model_go_proto"],
importpath = "go-common/app/tool/cache/memcached/testdata",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/container/pool:go_default_library",
"//library/log:go_default_library",
"//library/stat/prom:go_default_library",
"//library/time:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,87 @@
package testdata
import (
"context"
"fmt"
"time"
"go-common/library/cache/memcache"
"go-common/library/container/pool"
xtime "go-common/library/time"
)
// Dao .
type Dao struct {
mc *memcache.Pool
articleExpire int32
}
// New new dao
func New() (d *Dao) {
cfg := &memcache.Config{
Config: &pool.Config{
Active: 10,
Idle: 5,
IdleTimeout: xtime.Duration(time.Second),
},
Name: "test",
Proto: "tcp",
// Addr: "172.16.33.54:11214",
Addr: "127.0.0.1:11211",
DialTimeout: xtime.Duration(time.Second),
ReadTimeout: xtime.Duration(time.Second),
WriteTimeout: xtime.Duration(time.Second),
}
d = &Dao{
mc: memcache.NewPool(cfg),
articleExpire: int32(5),
}
return
}
//go:generate $GOPATH/src/go-common/app/tool/cache/mc
type _mc interface {
// mc: -key=articleKey
CacheArticles(c context.Context, keys []int64) (map[int64]*Article, error)
// mc: -key=articleKey
CacheArticle(c context.Context, key int64) (*Article, error)
// mc: -key=keyMid
CacheArticle1(c context.Context, key int64, mid int64) (*Article, error)
// mc: -key=noneKey
CacheNone(c context.Context) (*Article, error)
// mc: -key=articleKey
CacheString(c context.Context, key int64) (string, error)
// mc: -key=articleKey -expire=d.articleExpire -encode=json
AddCacheArticles(c context.Context, values map[int64]*Article) error
// 这里也支持自定义注释 会替换默认的注释
// mc: -key=articleKey -expire=d.articleExpire -encode=json|gzip
AddCacheArticle(c context.Context, key int64, value *Article) error
// mc: -key=keyMid -expire=d.articleExpire -encode=gob
AddCacheArticle1(c context.Context, key int64, value *Article, mid int64) error
// mc: -key=noneKey
AddCacheNone(c context.Context, value *Article) error
// mc: -key=articleKey -expire=d.articleExpire
AddCacheString(c context.Context, key int64, value string) error
// mc: -key=articleKey
DelCacheArticles(c context.Context, keys []int64) error
// mc: -key=articleKey
DelCacheArticle(c context.Context, key int64) error
// mc: -key=keyMid
DelCacheArticle1(c context.Context, key int64, mid int64) error
// mc: -key=noneKey
DelCacheNone(c context.Context) error
}
func articleKey(id int64) string {
return fmt.Sprintf("art_%d", id)
}
func keyMid(id, mid int64) string {
return fmt.Sprintf("art_%d_%d", id, mid)
}
func noneKey() string {
return "none"
}

View File

@@ -0,0 +1,116 @@
package testdata
import (
"context"
"testing"
)
func TestArticle(t *testing.T) {
d := New()
c := context.TODO()
art := &Article{ID: 1, Title: "title"}
err := d.AddCacheArticle(c, art.ID, art)
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
art1, err := d.CacheArticle(c, art.ID)
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
if (art1.ID != art.ID) || (art.Title != art1.Title) {
t.Error("art not equal")
t.FailNow()
}
err = d.DelCacheArticle(c, art.ID)
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
art1, err = d.CacheArticle(c, art.ID)
if (art1 != nil) || (err != nil) {
t.Errorf("art %v, err: %v", art1, err)
t.FailNow()
}
}
func TestNone(t *testing.T) {
d := New()
c := context.TODO()
art := &Article{ID: 1, Title: "title"}
err := d.AddCacheNone(c, art)
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
art1, err := d.CacheNone(c)
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
if (art1.ID != art.ID) || (art.Title != art1.Title) {
t.Error("art not equal")
t.FailNow()
}
err = d.DelCacheNone(c)
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
art1, err = d.CacheNone(c)
if (art1 != nil) || (err != nil) {
t.Errorf("art %v, err: %v", art1, err)
t.FailNow()
}
}
func TestArticles(t *testing.T) {
d := New()
c := context.TODO()
art1 := &Article{ID: 1, Title: "title"}
art2 := &Article{ID: 2, Title: "title"}
err := d.AddCacheArticles(c, map[int64]*Article{1: art1, 2: art2})
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
arts, err := d.CacheArticles(c, []int64{art1.ID, art2.ID})
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
if (arts[1].Title != art1.Title) || (arts[2].Title != art2.Title) {
t.Error("art not equal")
t.FailNow()
}
err = d.DelCacheArticles(c, []int64{art1.ID, art2.ID})
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
arts, err = d.CacheArticles(c, []int64{art1.ID, art2.ID})
if (arts != nil) || (err != nil) {
t.Errorf("art %v, err: %v", art1, err)
t.FailNow()
}
}
func TestString(t *testing.T) {
d := New()
c := context.TODO()
err := d.AddCacheString(c, 1, "abc")
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
res, err := d.CacheString(c, 1)
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
if res != "abc" {
t.Error("res wrong")
t.FailNow()
}
}

View File

@@ -0,0 +1,350 @@
// Code generated by $GOPATH/src/go-common/app/tool/cache/mc. DO NOT EDIT.
/*
Package testdata is a generated mc cache package.
It is generated from:
type _mc interface {
// mc: -key=articleKey
CacheArticles(c context.Context, keys []int64) (map[int64]*Article, error)
// mc: -key=articleKey
CacheArticle(c context.Context, key int64) (*Article, error)
// mc: -key=keyMid
CacheArticle1(c context.Context, key int64, mid int64) (*Article, error)
// mc: -key=noneKey
CacheNone(c context.Context) (*Article, error)
// mc: -key=articleKey
CacheString(c context.Context, key int64) (string, error)
// mc: -key=articleKey -expire=d.articleExpire -encode=json
AddCacheArticles(c context.Context, values map[int64]*Article) error
// 这里也支持自定义注释 会替换默认的注释
// mc: -key=articleKey -expire=d.articleExpire -encode=json|gzip
AddCacheArticle(c context.Context, key int64, value *Article) error
// mc: -key=keyMid -expire=d.articleExpire -encode=gob
AddCacheArticle1(c context.Context, key int64, value *Article, mid int64) error
// mc: -key=noneKey
AddCacheNone(c context.Context, value *Article) error
// mc: -key=articleKey -expire=d.articleExpire
AddCacheString(c context.Context, key int64, value string) error
// mc: -key=articleKey
DelCacheArticles(c context.Context, keys []int64) error
// mc: -key=articleKey
DelCacheArticle(c context.Context, key int64) error
// mc: -key=keyMid
DelCacheArticle1(c context.Context, key int64, mid int64) error
// mc: -key=noneKey
DelCacheNone(c context.Context) error
}
*/
package testdata
import (
"context"
"fmt"
"go-common/library/cache/memcache"
"go-common/library/log"
"go-common/library/stat/prom"
)
var _ _mc
// CacheArticles get data from mc
func (d *Dao) CacheArticles(c context.Context, ids []int64) (res map[int64]*Article, err error) {
l := len(ids)
if l == 0 {
return
}
keysMap := make(map[string]int64, l)
keys := make([]string, 0, l)
for _, id := range ids {
key := articleKey(id)
keysMap[key] = id
keys = append(keys, key)
}
conn := d.mc.Get(c)
defer conn.Close()
replies, err := conn.GetMulti(keys)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheArticles")
log.Errorv(c, log.KV("CacheArticles", fmt.Sprintf("%+v", err)), log.KV("keys", keys))
return
}
for key, reply := range replies {
var v *Article
v = &Article{}
err = conn.Scan(reply, v)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheArticles")
log.Errorv(c, log.KV("CacheArticles", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
if res == nil {
res = make(map[int64]*Article, len(keys))
}
res[keysMap[key]] = v
}
return
}
// CacheArticle get data from mc
func (d *Dao) CacheArticle(c context.Context, id int64) (res *Article, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := articleKey(id)
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheArticle")
log.Errorv(c, log.KV("CacheArticle", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = &Article{}
err = conn.Scan(reply, res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheArticle")
log.Errorv(c, log.KV("CacheArticle", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// CacheArticle1 get data from mc
func (d *Dao) CacheArticle1(c context.Context, id int64, mid int64) (res *Article, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := keyMid(id, mid)
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheArticle1")
log.Errorv(c, log.KV("CacheArticle1", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = &Article{}
err = conn.Scan(reply, res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheArticle1")
log.Errorv(c, log.KV("CacheArticle1", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// CacheNone get data from mc
func (d *Dao) CacheNone(c context.Context) (res *Article, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := noneKey()
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheNone")
log.Errorv(c, log.KV("CacheNone", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = &Article{}
err = conn.Scan(reply, res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheNone")
log.Errorv(c, log.KV("CacheNone", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// CacheString get data from mc
func (d *Dao) CacheString(c context.Context, id int64) (res string, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := articleKey(id)
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheString")
log.Errorv(c, log.KV("CacheString", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
err = conn.Scan(reply, &res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheString")
log.Errorv(c, log.KV("CacheString", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// AddCacheArticles Set data to mc
func (d *Dao) AddCacheArticles(c context.Context, values map[int64]*Article) (err error) {
if len(values) == 0 {
return
}
conn := d.mc.Get(c)
defer conn.Close()
for id, val := range values {
key := articleKey(id)
item := &memcache.Item{Key: key, Object: val, Expiration: d.articleExpire, Flags: memcache.FlagJSON}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCacheArticles")
log.Errorv(c, log.KV("AddCacheArticles", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
}
return
}
// AddCacheArticle 这里也支持自定义注释 会替换默认的注释
func (d *Dao) AddCacheArticle(c context.Context, id int64, val *Article) (err error) {
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := articleKey(id)
item := &memcache.Item{Key: key, Object: val, Expiration: d.articleExpire, Flags: memcache.FlagJSON | memcache.FlagGzip}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCacheArticle")
log.Errorv(c, log.KV("AddCacheArticle", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// AddCacheArticle1 Set data to mc
func (d *Dao) AddCacheArticle1(c context.Context, id int64, val *Article, mid int64) (err error) {
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := keyMid(id, mid)
item := &memcache.Item{Key: key, Object: val, Expiration: d.articleExpire, Flags: memcache.FlagGOB}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCacheArticle1")
log.Errorv(c, log.KV("AddCacheArticle1", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// AddCacheNone Set data to mc
func (d *Dao) AddCacheNone(c context.Context, val *Article) (err error) {
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := noneKey()
item := &memcache.Item{Key: key, Object: val, Expiration: d.articleExpire, Flags: memcache.FlagJSON}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCacheNone")
log.Errorv(c, log.KV("AddCacheNone", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// AddCacheString Set data to mc
func (d *Dao) AddCacheString(c context.Context, id int64, val string) (err error) {
if len(val) == 0 {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := articleKey(id)
bs := []byte(val)
item := &memcache.Item{Key: key, Value: bs, Expiration: d.articleExpire, Flags: memcache.FlagRAW}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCacheString")
log.Errorv(c, log.KV("AddCacheString", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// DelCacheArticles delete data from mc
func (d *Dao) DelCacheArticles(c context.Context, ids []int64) (err error) {
if len(ids) == 0 {
return
}
conn := d.mc.Get(c)
defer conn.Close()
for _, id := range ids {
key := articleKey(id)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
continue
}
prom.BusinessErrCount.Incr("mc:DelCacheArticles")
log.Errorv(c, log.KV("DelCacheArticles", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
}
return
}
// DelCacheArticle delete data from mc
func (d *Dao) DelCacheArticle(c context.Context, id int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := articleKey(id)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:DelCacheArticle")
log.Errorv(c, log.KV("DelCacheArticle", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// DelCacheArticle1 delete data from mc
func (d *Dao) DelCacheArticle1(c context.Context, id int64, mid int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := keyMid(id, mid)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:DelCacheArticle1")
log.Errorv(c, log.KV("DelCacheArticle1", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// DelCacheNone delete data from mc
func (d *Dao) DelCacheNone(c context.Context) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := noneKey()
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:DelCacheNone")
log.Errorv(c, log.KV("DelCacheNone", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}

View File

@@ -0,0 +1,328 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: model.proto
/*
Package model is a generated protocol buffer package.
It is generated from these files:
model.proto
It has these top-level messages:
Article
*/
package testdata
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Article struct {
ID int64 `protobuf:"varint,1,opt,name=ID,proto3" json:"id"`
Title string `protobuf:"bytes,3,opt,name=Title,proto3" json:"title"`
}
func (m *Article) Reset() { *m = Article{} }
func (m *Article) String() string { return proto.CompactTextString(m) }
func (*Article) ProtoMessage() {}
func (*Article) Descriptor() ([]byte, []int) { return fileDescriptorModel, []int{0} }
func init() {
proto.RegisterType((*Article)(nil), "model.Article")
}
func (m *Article) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Article) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.ID != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintModel(dAtA, i, uint64(m.ID))
}
if len(m.Title) > 0 {
dAtA[i] = 0x1a
i++
i = encodeVarintModel(dAtA, i, uint64(len(m.Title)))
i += copy(dAtA[i:], m.Title)
}
return i, nil
}
func encodeVarintModel(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return offset + 1
}
func (m *Article) Size() (n int) {
var l int
_ = l
if m.ID != 0 {
n += 1 + sovModel(uint64(m.ID))
}
l = len(m.Title)
if l > 0 {
n += 1 + l + sovModel(uint64(l))
}
return n
}
func sovModel(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozModel(x uint64) (n int) {
return sovModel(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *Article) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Article: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Article: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
}
m.ID = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ID |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthModel
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Title = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipModel(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthModel
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipModel(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowModel
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowModel
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowModel
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthModel
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowModel
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipModel(dAtA[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthModel = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowModel = fmt.Errorf("proto: integer overflow")
)
func init() { proto.RegisterFile("model.proto", fileDescriptorModel) }
var fileDescriptorModel = []byte{
// 166 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xce, 0xcd, 0x4f, 0x49,
0xcd, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x73, 0xa4, 0x74, 0xd3, 0x33, 0x4b,
0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xf5, 0xd3, 0xf3, 0xd3, 0xf3, 0xf5, 0xc1, 0xb2, 0x49,
0xa5, 0x69, 0x60, 0x1e, 0x98, 0x03, 0x66, 0x41, 0x74, 0x29, 0x39, 0x71, 0xb1, 0x3b, 0x16, 0x95,
0x64, 0x26, 0xe7, 0xa4, 0x0a, 0x89, 0x71, 0x31, 0x79, 0xba, 0x48, 0x30, 0x2a, 0x30, 0x6a, 0x30,
0x3b, 0xb1, 0xbd, 0xba, 0x27, 0xcf, 0x94, 0x99, 0x12, 0xc4, 0xe4, 0xe9, 0x22, 0x24, 0xcf, 0xc5,
0x1a, 0x92, 0x59, 0x92, 0x93, 0x2a, 0xc1, 0xac, 0xc0, 0xa8, 0xc1, 0xe9, 0xc4, 0xf9, 0xea, 0x9e,
0x3c, 0x6b, 0x09, 0x48, 0x20, 0x08, 0x22, 0xee, 0x24, 0x71, 0xe2, 0xa1, 0x1c, 0xc3, 0x85, 0x87,
0x72, 0x0c, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x8c,
0xc7, 0x72, 0x0c, 0x49, 0x6c, 0x60, 0x4b, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x11, 0xa6,
0xfa, 0x1c, 0xa9, 0x00, 0x00, 0x00,
}

View File

@@ -0,0 +1,14 @@
syntax = "proto3";
package model;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option (gogoproto.goproto_enum_prefix_all) = false;
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
message Article {
int64 ID = 1 [(gogoproto.jsontag) = "id"];
string Title = 3 [(gogoproto.jsontag) = "title"];
}

127
app/tool/cache/multi_template.go vendored Normal file
View File

@@ -0,0 +1,127 @@
package main
var _multiTemplate = `
// NAME {{or .Comment "get data from cache if miss will call source method, then add to cache."}}
func (d *Dao) NAME(c context.Context, keys []KEY{{.ExtraArgsType}}) (res map[KEY]VALUE, err error) {
if len(keys) == 0 {
return
}
addCache := true
if res, err = CACHEFUNC(c, keys {{.ExtraCacheArgs}});err != nil {
addCache = false
res = nil
err = nil
}
var miss []KEY
for _, key := range keys {
{{if .GoValue}}
if (res == nil) || (len(res[key]) == 0) {
{{else}}
{{if .NumberValue}}
if _, ok := res[key]; !ok {
{{else}}
if (res == nil) || (res[key] == {{.ZeroValue}}) {
{{end}}
{{end}}
miss = append(miss, key)
}
}
prom.CacheHit.Add("NAME", int64(len(keys) - len(miss)))
{{if .EnableNullCache}}
for k, v := range res {
{{if .SimpleValue}} if v == {{.NullCache}} { {{else}} if {{.CheckNullCode}} { {{end}}
delete(res, k)
}
}
{{end}}
missLen := len(miss)
if missLen == 0 {
return
}
{{if .EnableBatch}}
missData := make(map[KEY]VALUE, missLen)
{{else}}
var missData map[KEY]VALUE
{{end}}
{{if .EnableSingleFlight}}
var rr interface{}
sf := d.cacheSFNAME(keys {{.ExtraArgs}})
rr, err, _ = cacheSingleFlights[SFNUM].Do(sf, func() (r interface{}, e error) {
prom.CacheMiss.Add("NAME", int64(len(miss)))
r, e = RAWFUNC(c, miss {{.ExtraRawArgs}})
return
})
missData = rr.(map[KEY]VALUE)
{{else}}
{{if .EnableBatch}}
prom.CacheMiss.Add("NAME", int64(missLen))
var mutex sync.Mutex
{{if .BatchErrBreak}}
group, ctx := errgroup.WithContext(c)
{{else}}
group := &errgroup.Group{}
ctx := c
{{end}}
if missLen > MAXGROUP {
group.GOMAXPROCS(MAXGROUP)
}
var run = func(ms []KEY) {
group.Go(func() (err error) {
data, err := RAWFUNC(ctx, ms {{.ExtraRawArgs}})
mutex.Lock()
for k, v := range data {
missData[k] = v
}
mutex.Unlock()
return
})
}
var (
i int
n = missLen/GROUPSIZE
)
for i=0; i< n; i++{
run(miss[i*n:(i+1)*n])
}
if len(miss[i*n:]) > 0 {
run(miss[i*n:])
}
err = group.Wait()
{{else}}
prom.CacheMiss.Add("NAME", int64(len(miss)))
missData, err = RAWFUNC(c, miss {{.ExtraRawArgs}})
{{end}}
{{end}}
if res == nil {
res = make(map[KEY]VALUE, len(keys))
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
{{if .EnableNullCache}}
for _, key := range miss {
{{if .GoValue}}
if len(res[key]) == 0 {
{{else}}
if res[key] == {{.ZeroValue}} {
{{end}}
missData[key] = {{.NullCache}}
}
}
{{end}}
if !addCache {
return
}
{{if .Sync}}
ADDCACHEFUNC(c, missData {{.ExtraAddCacheArgs}})
{{else}}
d.cache.Do(c, func(c context.Context) {
ADDCACHEFUNC(c, missData {{.ExtraAddCacheArgs}})
})
{{end}}
return
}
`

65
app/tool/cache/none_template.go vendored Normal file
View File

@@ -0,0 +1,65 @@
package main
var _noneTemplate = `
// NAME {{or .Comment "get data from cache if miss will call source method, then add to cache."}}
func (d *Dao) NAME(c context.Context) (res VALUE, err error) {
addCache := true
res, err = CACHEFUNC(c)
if err != nil {
addCache = false
err = nil
}
{{if .EnableNullCache}}
defer func() {
{{if .SimpleValue}} if res == {{.NullCache}} { {{else}} if {{.CheckNullCode}} { {{end}}
res = {{.ZeroValue}}
}
}()
{{end}}
{{if .GoValue}}
if len(res) != 0 {
{{else}}
if res != {{.ZeroValue}} {
{{end}}
prom.CacheHit.Incr("NAME")
return
}
{{if .EnableSingleFlight}}
var rr interface{}
sf := d.cacheSFNAME()
rr, err, _ = cacheSingleFlights[SFNUM].Do(sf, func() (r interface{}, e error) {
prom.CacheMiss.Incr("NAME")
r, e = RAWFUNC(c)
return
})
res = rr.(VALUE)
{{else}}
prom.CacheMiss.Incr("NAME")
res, err = RAWFUNC(c)
{{end}}
if err != nil {
return
}
var miss = res
{{if .EnableNullCache}}
{{if .GoValue}}
if len(miss) == 0 {
{{else}}
if miss == {{.ZeroValue}} {
{{end}}
miss = {{.NullCache}}
}
{{end}}
if !addCache {
return
}
{{if .Sync}}
ADDCACHEFUNC(c, miss)
{{else}}
d.cache.Do(c, func(c context.Context) {
ADDCACHEFUNC(c, miss)
})
{{end}}
return
}
`

86
app/tool/cache/single_template.go vendored Normal file
View File

@@ -0,0 +1,86 @@
package main
var _singleTemplate = `
// NAME {{or .Comment "get data from cache if miss will call source method, then add to cache."}}
func (d *Dao) NAME(c context.Context, id KEY{{.ExtraArgsType}}) (res VALUE, err error) {
addCache := true
res, err = CACHEFUNC(c, id {{.ExtraCacheArgs}})
if err != nil {
addCache = false
err = nil
}
{{if .EnableNullCache}}
defer func() {
{{if .SimpleValue}} if res == {{.NullCache}} { {{else}} if {{.CheckNullCode}} { {{end}}
res = {{.ZeroValue}}
}
}()
{{end}}
{{if .GoValue}}
if len(res) != 0 {
{{else}}
if res != {{.ZeroValue}} {
{{end}}
prom.CacheHit.Incr("NAME")
return
}
{{if .EnablePaging}}
var miss VALUE
{{end}}
{{if .EnableSingleFlight}}
var rr interface{}
sf := d.cacheSFNAME(id {{.ExtraArgs}})
rr, err, _ = cacheSingleFlights[SFNUM].Do(sf, func() (r interface{}, e error) {
prom.CacheMiss.Incr("NAME")
{{if .EnablePaging}}
var rrs [2]interface{}
rrs[0], rrs[1], e = RAWFUNC(c, id {{.ExtraRawArgs}})
r = rrs
{{else}}
r, e = RAWFUNC(c, id {{.ExtraRawArgs}})
{{end}}
return
})
{{if .EnablePaging}}
res = rr.([2]interface{})[0].(VALUE)
miss = rr.([2]interface{})[1].(VALUE)
{{else}}
res = rr.(VALUE)
{{end}}
{{else}}
prom.CacheMiss.Incr("NAME")
{{if .EnablePaging}}
res, miss, err = RAWFUNC(c, id {{.ExtraRawArgs}})
{{else}}
res, err = RAWFUNC(c, id {{.ExtraRawArgs}})
{{end}}
{{end}}
if err != nil {
return
}
{{if .EnablePaging}}
{{else}}
miss := res
{{end}}
{{if .EnableNullCache}}
{{if .GoValue}}
if len(miss) == 0 {
{{else}}
if miss == {{.ZeroValue}} {
{{end}}
miss = {{.NullCache}}
}
{{end}}
if !addCache {
return
}
{{if .Sync}}
ADDCACHEFUNC(c, id, miss {{.ExtraAddCacheArgs}})
{{else}}
d.cache.Do(c, func(c context.Context) {
ADDCACHEFUNC(c, id, miss {{.ExtraAddCacheArgs}})
})
{{end}}
return
}
`

50
app/tool/cache/testdata/BUILD vendored Normal file
View File

@@ -0,0 +1,50 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"dao.cache.go",
"dao.go",
"multi.go",
"none.go",
"single.go",
],
importpath = "go-common/app/tool/cache/testdata",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/stat/prom:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/sync/pipeline/fanout:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"multi_test.go",
"none_test.go",
"single_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

202
app/tool/cache/testdata/dao.cache.go vendored Normal file
View File

@@ -0,0 +1,202 @@
// Code generated by $GOPATH/src/go-common/app/tool/cache/gen. DO NOT EDIT.
/*
Package testdata is a generated cache proxy package.
It is generated from:
type _cache interface {
// cache: -batch=10 -max_group=10 -batch_err=break -nullcache=&Article{ID:-1} -check_null_code=$.ID==-1
Articles(c context.Context, keys []int64) (map[int64]*Article, error)
// cache: -sync=true -nullcache=&Article{ID:-1} -check_null_code=$.ID==-1
Article(c context.Context, key int64) (*Article, error)
// cache: -paging=true
Article1(c context.Context, key int64, pn, ps int) (*Article, error)
// cache: -nullcache=&Article{ID:-1} -check_null_code=$.ID==-1
None(c context.Context) (*Article, error)
}
*/
package testdata
import (
"context"
"sync"
"go-common/library/stat/prom"
"go-common/library/sync/errgroup"
)
var _ _cache
// Articles get data from cache if miss will call source method, then add to cache.
func (d *Dao) Articles(c context.Context, keys []int64) (res map[int64]*Article, err error) {
if len(keys) == 0 {
return
}
addCache := true
if res, err = d.CacheArticles(c, keys); err != nil {
addCache = false
res = nil
err = nil
}
var miss []int64
for _, key := range keys {
if (res == nil) || (res[key] == nil) {
miss = append(miss, key)
}
}
prom.CacheHit.Add("Articles", int64(len(keys)-len(miss)))
for k, v := range res {
if v.ID == -1 {
delete(res, k)
}
}
missLen := len(miss)
if missLen == 0 {
return
}
missData := make(map[int64]*Article, missLen)
prom.CacheMiss.Add("Articles", int64(missLen))
var mutex sync.Mutex
group, ctx := errgroup.WithContext(c)
if missLen > 10 {
group.GOMAXPROCS(10)
}
var run = func(ms []int64) {
group.Go(func() (err error) {
data, err := d.RawArticles(ctx, ms)
mutex.Lock()
for k, v := range data {
missData[k] = v
}
mutex.Unlock()
return
})
}
var (
i int
n = missLen / 10
)
for i = 0; i < n; i++ {
run(miss[i*n : (i+1)*n])
}
if len(miss[i*n:]) > 0 {
run(miss[i*n:])
}
err = group.Wait()
if res == nil {
res = make(map[int64]*Article, len(keys))
}
for k, v := range missData {
res[k] = v
}
if err != nil {
return
}
for _, key := range miss {
if res[key] == nil {
missData[key] = &Article{ID: -1}
}
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCacheArticles(c, missData)
})
return
}
// Article get data from cache if miss will call source method, then add to cache.
func (d *Dao) Article(c context.Context, id int64) (res *Article, err error) {
addCache := true
res, err = d.CacheArticle(c, id)
if err != nil {
addCache = false
err = nil
}
defer func() {
if res.ID == -1 {
res = nil
}
}()
if res != nil {
prom.CacheHit.Incr("Article")
return
}
prom.CacheMiss.Incr("Article")
res, err = d.RawArticle(c, id)
if err != nil {
return
}
miss := res
if miss == nil {
miss = &Article{ID: -1}
}
if !addCache {
return
}
d.AddCacheArticle(c, id, miss)
return
}
// Article1 get data from cache if miss will call source method, then add to cache.
func (d *Dao) Article1(c context.Context, id int64, pn, ps int) (res *Article, err error) {
addCache := true
res, err = d.CacheArticle1(c, id, pn, ps)
if err != nil {
addCache = false
err = nil
}
if res != nil {
prom.CacheHit.Incr("Article1")
return
}
var miss *Article
prom.CacheMiss.Incr("Article1")
res, miss, err = d.RawArticle1(c, id, pn, ps)
if err != nil {
return
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCacheArticle1(c, id, miss, pn, ps)
})
return
}
// None get data from cache if miss will call source method, then add to cache.
func (d *Dao) None(c context.Context) (res *Article, err error) {
addCache := true
res, err = d.CacheNone(c)
if err != nil {
addCache = false
err = nil
}
defer func() {
if res.ID == -1 {
res = nil
}
}()
if res != nil {
prom.CacheHit.Incr("None")
return
}
prom.CacheMiss.Incr("None")
res, err = d.RawNone(c)
if err != nil {
return
}
var miss = res
if miss == nil {
miss = &Article{ID: -1}
}
if !addCache {
return
}
d.cache.Do(c, func(c context.Context) {
d.AddCacheNone(c, miss)
})
return
}

35
app/tool/cache/testdata/dao.go vendored Normal file
View File

@@ -0,0 +1,35 @@
package testdata
import (
"context"
"go-common/library/sync/pipeline/fanout"
)
// Article test struct
type Article struct {
ID int64
Title string
}
// Dao .
type Dao struct {
cache *fanout.Fanout
}
// New .
func New() *Dao {
return &Dao{cache: fanout.New("cache")}
}
//go:generate $GOPATH/src/go-common/app/tool/cache/gen
type _cache interface {
// cache: -batch=10 -max_group=10 -batch_err=break -nullcache=&Article{ID:-1} -check_null_code=$.ID==-1
Articles(c context.Context, keys []int64) (map[int64]*Article, error)
// cache: -sync=true -nullcache=&Article{ID:-1} -check_null_code=$.ID==-1
Article(c context.Context, key int64) (*Article, error)
// cache: -paging=true
Article1(c context.Context, key int64, pn, ps int) (*Article, error)
// cache: -nullcache=&Article{ID:-1} -check_null_code=$.ID==-1
None(c context.Context) (*Article, error)
}

30
app/tool/cache/testdata/multi.go vendored Normal file
View File

@@ -0,0 +1,30 @@
package testdata
import (
"context"
)
// mock test
var (
_multiCacheFunc func(c context.Context, keys []int64) (map[int64]*Article, error)
_multiRawFunc func(c context.Context, keys []int64) (map[int64]*Article, error)
_multiAddCacheFunc func(c context.Context, values map[int64]*Article) error
)
// CacheArticles .
func (d *Dao) CacheArticles(c context.Context, keys []int64) (map[int64]*Article, error) {
// get data from cache
return _multiCacheFunc(c, keys)
}
// RawArticles .
func (d *Dao) RawArticles(c context.Context, keys []int64) (map[int64]*Article, error) {
// get data from db
return _multiRawFunc(c, keys)
}
// AddCacheArticles .
func (d *Dao) AddCacheArticles(c context.Context, values map[int64]*Article) error {
// add to cache
return _multiAddCacheFunc(c, values)
}

67
app/tool/cache/testdata/multi_test.go vendored Normal file
View File

@@ -0,0 +1,67 @@
package testdata
import (
"context"
"errors"
"testing"
)
func TestMultiCache(t *testing.T) {
id := int64(1)
d := New()
meta := map[int64]*Article{id: {ID: id}}
getsFromCache := func(c context.Context, keys []int64) (map[int64]*Article, error) { return meta, nil }
notGetsFromCache := func(c context.Context, keys []int64) (map[int64]*Article, error) { return nil, errors.New("err") }
// 缓存返回了部分数据
partFromCache := func(c context.Context, keys []int64) (map[int64]*Article, error) { return meta, errors.New("err") }
getsFromSource := func(c context.Context, keys []int64) (map[int64]*Article, error) { return meta, nil }
notGetsFromSource := func(c context.Context, keys []int64) (map[int64]*Article, error) {
return meta, errors.New("err")
}
addToCache := func(c context.Context, values map[int64]*Article) error { return nil }
// gets from cache
_multiCacheFunc = getsFromCache
_multiRawFunc = notGetsFromSource
_multiAddCacheFunc = addToCache
res, err := d.Articles(context.TODO(), []int64{id})
if err != nil {
t.Fatalf("err should be nil, get: %v", err)
}
if res[1].ID != 1 {
t.Fatalf("id should be 1")
}
// get from source
_multiCacheFunc = notGetsFromCache
_multiRawFunc = getsFromSource
res, err = d.Articles(context.TODO(), []int64{id})
if err != nil {
t.Fatalf("err should be nil, get: %v", err)
}
if res[1].ID != 1 {
t.Fatalf("id should be 1")
}
// 缓存失败 返回部分数据 回源也失败的情况
_multiCacheFunc = partFromCache
_multiRawFunc = notGetsFromSource
res, err = d.Articles(context.TODO(), []int64{id})
if err == nil {
t.Fatalf("err should be nil, get: %v", err)
}
if res[1].ID != 1 {
t.Fatalf("id should be 1")
}
// with null cache
nullCache := &Article{ID: -1}
getNullFromCache := func(c context.Context, keys []int64) (map[int64]*Article, error) {
return map[int64]*Article{id: nullCache}, nil
}
_multiCacheFunc = getNullFromCache
_multiRawFunc = notGetsFromSource
res, err = d.Articles(context.TODO(), []int64{id})
if err != nil {
t.Fatalf("err should be nil, get: %v", err)
}
if res[id] != nil {
t.Fatalf("res should be nil")
}
}

30
app/tool/cache/testdata/none.go vendored Normal file
View File

@@ -0,0 +1,30 @@
package testdata
import (
"context"
)
// mock test
var (
_noneCacheFunc func(c context.Context) (*Article, error)
_noneRawFunc func(c context.Context) (*Article, error)
_noneAddCacheFunc func(c context.Context, value *Article) error
)
// CacheNone .
func (d *Dao) CacheNone(c context.Context) (*Article, error) {
// get data from cache
return _noneCacheFunc(c)
}
// RawNone .
func (d *Dao) RawNone(c context.Context) (*Article, error) {
// get data from db
return _noneRawFunc(c)
}
// AddCacheNone .
func (d *Dao) AddCacheNone(c context.Context, value *Article) error {
// add to cache
return _noneAddCacheFunc(c, value)
}

50
app/tool/cache/testdata/none_test.go vendored Normal file
View File

@@ -0,0 +1,50 @@
package testdata
import (
"context"
"errors"
"testing"
)
func TestNoneCache(t *testing.T) {
d := New()
meta := &Article{ID: 1}
getFromCache := func(c context.Context) (*Article, error) { return meta, nil }
notGetFromCache := func(c context.Context) (*Article, error) { return nil, errors.New("err") }
getFromSource := func(c context.Context) (*Article, error) { return meta, nil }
notGetFromSource := func(c context.Context) (*Article, error) { return meta, errors.New("err") }
addToCache := func(c context.Context, values *Article) error { return nil }
// get from cache
_noneCacheFunc = getFromCache
_noneRawFunc = notGetFromSource
_noneAddCacheFunc = addToCache
res, err := d.None(context.TODO())
if err != nil {
t.Fatalf("err should be nil, get: %v", err)
}
if res.ID != 1 {
t.Fatalf("id should be 1")
}
// get from source
_noneCacheFunc = notGetFromCache
_noneRawFunc = getFromSource
res, err = d.None(context.TODO())
if err != nil {
t.Fatalf("err should be nil, get: %v", err)
}
if res.ID != 1 {
t.Fatalf("id should be 1")
}
// with null cache
nullCache := &Article{ID: -1}
getNullFromCache := func(c context.Context) (*Article, error) { return nullCache, nil }
_noneCacheFunc = getNullFromCache
_noneRawFunc = notGetFromSource
res, err = d.None(context.TODO())
if err != nil {
t.Fatalf("err should be nil, get: %v", err)
}
if res != nil {
t.Fatalf("res should be nil")
}
}

48
app/tool/cache/testdata/single.go vendored Normal file
View File

@@ -0,0 +1,48 @@
package testdata
import (
"context"
)
// mock test
var (
_singleCacheFunc func(c context.Context, key int64) (*Article, error)
_singleRawFunc func(c context.Context, key int64) (*Article, error)
_singleAddCacheFunc func(c context.Context, key int64, value *Article) error
)
// CacheArticle .
func (d *Dao) CacheArticle(c context.Context, key int64) (*Article, error) {
// get data from cache
return _singleCacheFunc(c, key)
}
// RawArticle .
func (d *Dao) RawArticle(c context.Context, key int64) (*Article, error) {
// get data from db
return _singleRawFunc(c, key)
}
// AddCacheArticle .
func (d *Dao) AddCacheArticle(c context.Context, key int64, value *Article) error {
// add to cache
return _singleAddCacheFunc(c, key, value)
}
// CacheArticle1 .
func (d *Dao) CacheArticle1(c context.Context, key int64, pn, ps int) (*Article, error) {
// get data from cache
return nil, nil
}
// RawArticle1 .
func (d *Dao) RawArticle1(c context.Context, key int64, pn, ps int) (*Article, *Article, error) {
// get data from db
return nil, nil, nil
}
// AddCacheArticle1 .
func (d *Dao) AddCacheArticle1(c context.Context, key int64, value *Article, pn, ps int) error {
// add to cache
return nil
}

50
app/tool/cache/testdata/single_test.go vendored Normal file
View File

@@ -0,0 +1,50 @@
package testdata
import (
"context"
"errors"
"testing"
)
func TestSingleCache(t *testing.T) {
d := New()
meta := &Article{ID: 1}
getFromCache := func(c context.Context, id int64) (*Article, error) { return meta, nil }
notGetFromCache := func(c context.Context, id int64) (*Article, error) { return nil, errors.New("err") }
getFromSource := func(c context.Context, id int64) (*Article, error) { return meta, nil }
notGetFromSource := func(c context.Context, id int64) (*Article, error) { return meta, errors.New("err") }
addToCache := func(c context.Context, id int64, values *Article) error { return nil }
// get from cache
_singleCacheFunc = getFromCache
_singleRawFunc = notGetFromSource
_singleAddCacheFunc = addToCache
res, err := d.Article(context.TODO(), 1)
if err != nil {
t.Fatalf("err should be nil, get: %v", err)
}
if res.ID != 1 {
t.Fatalf("id should be 1")
}
// get from source
_singleCacheFunc = notGetFromCache
_singleRawFunc = getFromSource
res, err = d.Article(context.TODO(), 1)
if err != nil {
t.Fatalf("err should be nil, get: %v", err)
}
if res.ID != 1 {
t.Fatalf("id should be 1")
}
// with null cache
nullCache := &Article{ID: -1}
getNullFromCache := func(c context.Context, id int64) (*Article, error) { return nullCache, nil }
_singleCacheFunc = getNullFromCache
_singleRawFunc = notGetFromSource
res, err = d.Article(context.TODO(), 1)
if err != nil {
t.Fatalf("err should be nil, get: %v", err)
}
if res != nil {
t.Fatalf("res should be nil")
}
}

21
app/tool/ci/BUILD Normal file
View File

@@ -0,0 +1,21 @@
package(default_visibility = ["//visibility:public"])
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/tool/ci/cmd/mail:all-srcs",
"//app/tool/ci/lib/changes:all-srcs",
"//app/tool/ci/lib/commit:all-srcs",
"//app/tool/ci/lib/lint:all-srcs",
"//app/tool/ci/lib/mail:all-srcs",
],
tags = ["automanaged"],
)

12
app/tool/ci/CHANGELOG.md Normal file
View File

@@ -0,0 +1,12 @@
# tools.rider
# v1.0.1
1. add send mail
2. update log print
# v1.0.1
1. fix rider/changes log dir
2. update vendor
# v1.0.0
1. 初始化项目

View File

@@ -0,0 +1,10 @@
# Owner
fangrongchang
# Author
fangrongchang
zhanglin
# Reviewer
fangrongchang
zhanglin

12
app/tool/ci/OWNERS Normal file
View File

@@ -0,0 +1,12 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- fangrongchang
- zhanglin
labels:
- tool
options:
no_parent_owners: true
reviewers:
- fangrongchang
- zhanglin

View File

@@ -0,0 +1,41 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_binary",
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
importmap = "go-common/app/tool/rider/sendEmail/cmd",
importpath = "go-common/app/tool/ci/cmd/mail",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/tool/ci/lib/mail:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_binary(
name = "mail",
embed = [":go_default_library"],
tags = ["automanaged"],
)

View File

@@ -0,0 +1,92 @@
package main
import (
"flag"
"os"
"strings"
"go-common/app/tool/ci/lib/mail"
"go-common/library/log"
"github.com/BurntSushi/toml"
)
type sendInfo struct {
SenderName string
SendTitle string
SendContent string
ExtraData string
}
type receiverInfo struct {
ReceiverName []string
}
type config struct {
Title string
SendInfo sendInfo
ReceiverInfo receiverInfo
}
func mailToml(cPath string) (conf config, err error) {
if _, err = toml.DecodeFile(cPath, &conf); err != nil {
log.Error("Error(%v)", err)
}
return
}
func main() {
var (
filePath string
ciSendTo string
pipeStatus string
eConf config
sendTo []string
sendContent string
extraData string
err error
ciProjectURL = os.Getenv("CI_PROJECT_URL")
ciPipelineId = os.Getenv("CI_PIPELINE_ID")
ciUserEmail = os.Getenv("GITLAB_USER_EMAIL")
sourceBranch = os.Getenv("CI_COMMIT_REF_NAME")
)
//log init
logConfig := &log.Config{
Stdout: true,
}
log.Init(logConfig)
//pipeline url
if ciProjectURL == "" {
log.Warn("Error: Not CI_PROJECT_URL")
}
pipelineURL := ciProjectURL + "/pipelines/" + ciPipelineId
log.Info("url: %v", pipelineURL)
//send email data from config files
flag.StringVar(&filePath, "configPath", "", "config path, eg: /data/gitlab/email.toml")
flag.StringVar(&ciSendTo, "sendTo", "", "send to email, eg: jiangkai@bilibili.com,tangyongqiang@bilibili.com")
flag.StringVar(&pipeStatus, "pipeStatus", "failed", "pipeStatus, only failed or success")
flag.StringVar(&extraData, "extraData", "", "email contents")
flag.Parse()
if ciSendTo != "" {
matchList := strings.Split(ciSendTo, ",")
sendTo = matchList
} else {
if filePath != "" {
if eConf, err = mailToml(filePath); err != nil {
log.Warn("Warn(%v)", err)
}
sendTo = eConf.ReceiverInfo.ReceiverName
sendContent = eConf.SendInfo.SendContent
extraData = eConf.SendInfo.ExtraData
} else {
sendTo = []string{ciUserEmail}
}
}
// delete saga send mail
if strings.Contains(ciUserEmail, "zzjs") {
log.Info("Saga exc pipeline")
} else {
sendmail.SendMail(sendTo, pipelineURL, sendContent, sourceBranch, extraData, pipeStatus)
}
}

View File

@@ -0,0 +1,21 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,21 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,21 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["sendmail.go"],
importpath = "go-common/app/tool/ci/lib/mail",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/tool/saga/model:go_default_library",
"//app/tool/saga/service/mail:go_default_library",
"//library/log:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = ["sendmail_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = ["//vendor/github.com/smartystreets/goconvey/convey:go_default_library"],
)

View File

@@ -0,0 +1,46 @@
package sendmail
import (
"go-common/app/tool/saga/model"
"go-common/app/tool/saga/service/mail"
"go-common/library/log"
)
/*
mail model:
【Saga 提醒】+mailTitle
Saga 事件通知
执行状态 : 成功
Pipeline信息: http://gitlab.bilibili.co/platform/go-common/pipelines/1551
来源分支 : ci-commit/test
修改说明 :
额外信息: 你真是棒棒的,合并成功了
*/
func SendMail(sendTo []string, url string, data string, sourceBranch string, extraData string, pipeStatus string) {
var (
mAddress model.Mail
mDada model.MailData
)
for _, to := range sendTo {
singleMail := &model.MailAddress{Address: to}
mAddress.ToAddress = append(mAddress.ToAddress, singleMail)
}
if pipeStatus == "failed" {
mAddress.Subject = "【Saga 提醒】Pipeline 执行失败 "
mDada.PipeStatus = "失败"
} else if pipeStatus == "success" {
mAddress.Subject = "【Saga 提醒】Pipeline 执行成功 "
mDada.PipeStatus = "成功"
} else {
mAddress.Subject = "【Saga 提醒】 " + pipeStatus
}
mDada.Info = extraData
mDada.Description = data
mDada.SourceBranch = sourceBranch
mDada.URL = url
mDada.PipelineStatus = pipeStatus
if err := mail.SendMail3("saga@bilibili.com", "SAGA", "Lexgm8AAQrF7CcNA", &mAddress, &mDada); err != nil {
log.Error("Error(%v)", err)
}
}

View File

@@ -0,0 +1,12 @@
package sendmail
import (
. "github.com/smartystreets/goconvey/convey"
"testing"
)
func TestSendMail(t *testing.T) {
Convey("TODO", t, func() {
})
}

47
app/tool/creator/BUILD Normal file
View File

@@ -0,0 +1,47 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_binary",
)
go_library(
name = "go_default_library",
srcs = [
"gen.go",
"main.go",
"parser.go",
"templete.go",
"upgrade.go",
"utils.go",
],
importpath = "go-common/app/tool/creator",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/otokaze/mock/mockgen:go_default_library",
"//vendor/github.com/otokaze/mock/mockgen/model:go_default_library",
"//vendor/golang.org/x/tools/imports:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_binary(
name = "creator",
embed = [":go_default_library"],
tags = ["automanaged"],
)

View File

@@ -0,0 +1,79 @@
## Creater 代码生成器
### Version 1.2.3
> 1.优化生成library单测代码逻辑
> 2.修正部分bug
### Version 1.2.2
> 1.重构生成monkey代码为独立mock文件
### Version 1.2.1
> 1.生成monkey代码排除返回为空的方法
### Version 1.2.0
> 1.增加生成monkey代码
### Version 1.1.10
> 1.修复生成测试用例格式错位问题
> 2.修复service层TestMain模板问题
### Version 1.1.9
> 1.修复 goimport 失败文件为空的问题.
> 2.修复自定义 chan 类型无法 parser 的问题.
### Version 1.1.8
> 1.gen方法兼容windows路径
> 2.测试方法追加bug修复
### Version 1.1.7
> 1.增加自动生成Reset方法
> 2.create everything...
### Version 1.1.6
> 1.支持 service 层 ut 生成.
> 2.生成的 mock 代码迁移至 mock 文件夹.
> 3.摘除 gock 相关代码.
### Version 1.1.5
> 1.摘除 genmock 代码 这波优化很清真 音風真的很严格.
> 2.魔改 genmock 工具 fork 为 github.com/otokaze/mock/gomock.
### Version 1.1.4
> 1.修改模板context.TODO()为context.Background()
> 2.优化*ast.FuncType的处理逻辑
> 3.修改tpTestFunc模板增加根convey方便用例扩展
### Version 1.1.3
> 1.新增生成mock代码方法
> 2.修改TestMain模板中发布版本号为"docker-1"
> 3.修改genInterface中多包生成对应Interface问题
> 4.修复genMock.go中pkgName冲突问题
### Version 1.1.2
> 1.新增解析Dao层结构体方法
> 2.新增动态增加httpMock方法
> 3.修复Goimport方法
### Version 1.1.1
> 1.优化convey.So
### Version 1.1.0
> 1.增加生成interface功能
> 2.改进类型解析功能
> 3.改进生成imports功能
> 4.修改Dao层测试模板至更加规范化
### Version 1.0.2
> 1.删除 TestMain 无用 flag.
### Version 1.0.1
> 1.添加 context.Context 类型支持.
### Version 1.0.0
> 1.无差别传参. 支持同时传入目录和文件, 生成自如!
> 2.--func 指定 func 生成测试用例. (当前存在 *_test.go 会以 append 方式追加)
> 3.--m 支持选择工作模式. (目前支持的有 test 测试用例...等)
> 4.支持生成 dao_test.go 测试入口文件, 初始化 Dao 一把梭
### Version 0.0.1
> 1.初始化项目.

View File

@@ -0,0 +1,11 @@
# Owner
chenjianrong
# Author
chenjianrong
zhaobingqing
fengshanshan
hedan
# Reviewer
chenjianrong

Some files were not shown because too many files have changed in this diff Show More