Initial commit

This commit is contained in:
Donny
2019-04-22 20:46:32 +08:00
commit 49ab8aadd1
25441 changed files with 4055000 additions and 0 deletions

57
app/tool/kratos/BUILD Normal file
View File

@@ -0,0 +1,57 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_binary",
)
go_library(
name = "go_default_library",
srcs = [
"build.go",
"doc.go",
"init.go",
"main.go",
"project.go",
"template.go",
"update.go",
"upgrade.go",
"verification.go",
"version.go",
],
importpath = "go-common/app/tool/kratos",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/AlecAivazis/survey:go_default_library",
"//vendor/github.com/kr/pty: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"],
)
go_binary(
name = "kratos",
embed = [":go_default_library"],
tags = ["automanaged"],
x_defs = {
"main.Version": "3",
"main.GitCommit": "{STABLE_BUILD_GIT_COMMIT}",
"main.BuildTime": "{STABLE_BUILD_TIME}",
"main.Channel": "release",
},
)

View File

@@ -0,0 +1,43 @@
#### Version 0.4.5
1. 初始化项目时运行 prow-update
#### Version 0.4.4
1. 修复paladin配置模块化
2. 修复comment细节
#### Version 0.4.3
1. 初始化项目时自动运行 kratos update
2. 构建非grpc项目不创建/api目录
#### Version 0.4.2
1. 创建本地配置文件
#### Version 0.4.1
1. 修复模板
#### Version 0.4.0
1. 对接paladin
#### Version 0.3.0
1. add grpc demo
#### Version 0.2.0
1. 支持命令行交互模式
#### Version 0.1.1
1. 调整api目录下的api.proto位置
#### Version 0.1.0
1. support internal directory
#### Version 0.0.4
1. 添加云技术部门 video
#### Version 0.0.3
1. 去除对library/conf的包变量引用
#### Version 0.0.2
1. 增加version和selfupdate
#### Version 0.0.1
1. 初始化增加bbq

View File

@@ -0,0 +1,10 @@
# Owner
zhapuyu
zhuangzhewei
wangweizhen
# Author
wangweizhen
zhuangzhewei
# Reviewer

6
app/tool/kratos/OWNERS Normal file
View File

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

16
app/tool/kratos/README.MD Normal file
View File

@@ -0,0 +1,16 @@
# kratos
## 项目简介
go-common 工具
## 使用说明
### 参数
kratos -h
### 示例
```
./kratos init -d main -t interface -n testproject -o ownername
```

62
app/tool/kratos/build.go Normal file
View File

@@ -0,0 +1,62 @@
package main
import (
"fmt"
"io"
"os"
"os/exec"
"path"
"strings"
"github.com/kr/pty"
"github.com/urfave/cli"
)
func runbazel(param ...string) {
command := append([]string{"build", "--watchfs"}, param...)
fmt.Println(command)
cmd := exec.Command("bazel", command...)
f, err := pty.Start(cmd)
if err != nil {
panic(err)
}
io.Copy(os.Stdout, f)
}
func bazelAction(c *cli.Context) error {
pwd, err := os.Getwd()
if err != nil {
return err
}
index := strings.Index(pwd, "go-common")
if index == -1 {
fmt.Println("not in go-common")
os.Exit(1)
}
result := strings.Split(pwd[index:], "/")
runPath := strings.Join(result[1:], "/")
if c.NArg() > 0 {
param := []string{}
for index := 0; index < c.NArg(); index++ {
name := path.Join(runPath, path.Clean(c.Args().Get(index)))
if name == "." {
continue
}
if strings.HasSuffix(name, "/...") {
param = append(param, "//"+name)
} else {
param = append(param, "//"+name+"/...")
}
}
runbazel(param...)
} else {
if len(runPath) == 0 {
runbazel("//app/...", "//library/...", "//vendor/...")
} else {
runbazel("//" + strings.Join(result[1:], "/") + "/...")
}
}
return nil
}

29
app/tool/kratos/doc.go Normal file
View File

@@ -0,0 +1,29 @@
/*
kratos 是go-common的工具链提供新项目创建bazel编译功能
kartos build 本目录之下局部编译,根目录全量编译
NAME:
kratos build - bazel build
USAGE:
kratos build [arguments...]
EXAMPLE:
cd app && kratos build ./service/.. admin interface/.. tool/cache/...
kratos build
kartos init 新建新项目
USAGE:
kratos init [command options] [arguments...]
OPTIONS:
-d value 部门名
-t value 项目类型(service,interface,admin,job,common)
-n value 项目名
-o value 维护人
--grpc 是否是GRPC
EXAMPLE:
kratos init -d main -t service -n test -o wangweizhen
*/
package main

215
app/tool/kratos/init.go Normal file
View File

@@ -0,0 +1,215 @@
package main
import (
"fmt"
"log"
"os"
"path"
"path/filepath"
"strings"
"github.com/AlecAivazis/survey"
"github.com/urfave/cli"
)
var (
// 允许建立项目的部门
depts = map[string]bool{
"main": true,
"live": true,
"openplatform": true,
"search": true,
"ep": true,
"bbq": true,
"video": true,
"bplus": true,
"ops": true,
}
// 允许建立的项目类型
types = map[string]bool{
"interface": true,
"admin": true,
"job": true,
"service": true,
}
)
const (
_textModeFastInit = "一键初始化项目"
_textModeInteraction = "自定义项目参数"
_textYes = "是"
_textNo = "否"
)
func runInit(ctx *cli.Context) (err error) {
if ctx.NumFlags() == 0 {
if err = interact(); err != nil {
return
}
}
if ok := check(); !ok {
return nil
}
if err = create(); err != nil {
println("项目初始化失败: ", err.Error())
return nil
}
fmt.Printf(`项目初始化成功!
注意请先创建rider、服务树节点、在配置中心创建uat环境配置文件否则提交mr后无法运行单元测试
相关帮助信息见 http://info.bilibili.co/pages/viewpage.action?pageId=7567510
`)
return nil
}
func initPwd() (ok bool) {
pwd, err := os.Getwd()
if err != nil {
return
}
ps := strings.Split(pwd, string(os.PathSeparator))
plen := len(ps)
if plen < 3 {
// 至少要有三个目录层级:部门、项目类型、项目名
return
}
name := ps[plen-1]
dept := ps[plen-2]
typ := ps[plen-3]
if !depts[dept] {
return
}
if !types[typ] {
return
}
if name == "" {
return
}
p.Name = name
p.Department = dept
p.Type = typ
p.Path = pwd
return true
}
func check() (ok bool) {
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")
}
if !validate() {
return
}
p.Path = fmt.Sprintf("%s/src/go-common/app/%s/%s/%s", strings.TrimRight(root, "/"), p.Type, p.Department, p.Name)
return true
}
func goPath() (string, error) {
gopaths := strings.Split(os.Getenv("GOPATH"), ":")
if len(gopaths) == 1 {
return gopaths[0], nil
}
pwd, err := os.Getwd()
if err != nil {
return "", err
}
abspwd, err := filepath.Abs(pwd)
if err != nil {
return "", err
}
for _, gp := range gopaths {
absgp, err := filepath.Abs(gp)
if err != nil {
return "", err
}
if strings.HasPrefix(abspwd, absgp) {
return absgp, nil
}
}
return "", fmt.Errorf("can't found current gopath")
}
func interact() (err error) {
qs1 := &survey.Select{
Message: "你想怎么玩?",
Options: []string{_textModeFastInit, _textModeInteraction},
}
var ans1 string
if err = survey.AskOne(qs1, &ans1, nil); err != nil {
return
}
switch ans1 {
case _textModeFastInit:
if ok := initPwd(); !ok {
println("Notice: Not in project directory. Skipped fast init.")
}
return
case _textModeInteraction:
// go on
default:
return
}
var ds, ts []string
for d := range depts {
ds = append(ds, d)
}
for t := range types {
ts = append(ts, t)
}
qs := []*survey.Question{
{
Name: "department",
Prompt: &survey.Select{
Message: "请选择选择部门:",
Options: ds,
Default: "main",
},
},
{
Name: "type",
Prompt: &survey.Select{
Message: "请选择项目类型:",
Options: ts,
},
},
{
Name: "name",
Prompt: &survey.Input{
Message: "请输入项目名称:",
},
Validate: survey.Required,
},
{
Name: "owner",
Prompt: &survey.Input{
Message: "请输入项目负责人:",
},
},
{
Name: "useGRPC",
Prompt: &survey.Select{
Message: "是否使用 gRPC ",
Options: []string{_textYes, _textNo},
Default: _textNo,
},
},
}
ans := struct {
Department string
Type string
Name string
Owner string
UseGRPC string
}{}
if err = survey.Ask(qs, &ans); err != nil {
return
}
p.Name = ans.Name
p.Department = ans.Department
p.Type = ans.Type
p.Owner = ans.Owner
if ans.UseGRPC == _textYes {
p.WithGRPC = true
}
return
}

84
app/tool/kratos/main.go Normal file
View File

@@ -0,0 +1,84 @@
package main
import (
"fmt"
"os"
"github.com/urfave/cli"
)
func main() {
app := cli.NewApp()
app.Name = "kratos"
app.Usage = "kratos tool"
app.Version = Version
app.Commands = []cli.Command{
{
Name: "build",
Aliases: []string{"b"},
Usage: "bazel build",
Action: bazelAction,
},
{
Name: "init",
Aliases: []string{"i"},
Usage: "create new project",
Flags: []cli.Flag{
cli.StringFlag{
Name: "d",
Value: "",
Usage: "department name for create project",
Destination: &p.Department,
},
cli.StringFlag{
Name: "t",
Value: "",
Usage: "project type name for create project",
Destination: &p.Type,
},
cli.StringFlag{
Name: "n",
Value: "",
Usage: "project name for create project",
Destination: &p.Name,
},
cli.StringFlag{
Name: "o",
Value: "",
Usage: "project owner for create project",
Destination: &p.Owner,
},
cli.BoolFlag{
Name: "grpc",
Usage: "whether to use grpc for create project",
Destination: &p.WithGRPC,
},
},
Action: runInit,
},
{
Name: "update",
Aliases: []string{"u"},
Usage: "update bazel building configure",
Action: updateAction,
},
{
Name: "version",
Aliases: []string{"v"},
Usage: "kratos version",
Action: func(c *cli.Context) error {
fmt.Println(getVersion())
return nil
},
},
{
Name: "upgrade",
Usage: "kratos self-upgrade",
Action: upgradeAction,
},
}
err := app.Run(os.Args)
if err != nil {
panic(err)
}
}

175
app/tool/kratos/project.go Normal file
View File

@@ -0,0 +1,175 @@
package main
import (
"bytes"
"io/ioutil"
"os"
"os/exec"
"strings"
"text/template"
)
// project project config
type project struct {
Department string
Type string
Name string
Owner string
Path string
WithGRPC bool
}
const (
_tplTypeDao = iota
_tplTypeHTTPServer
_tplTypeAPIProto
_tplTypeService
_tplTypeMain
_tplTypeChangeLog
_tplTypeContributors
_tplTypeReadme
_tplTypeAppToml
_tplTypeMySQLToml
_tplTypeMCToml
_tplTypeRedisToml
_tplTypeHTTPToml
_tplTypeGRPCToml
_tplTypeModel
_tplTypeGRPCServer
_tplTypeAPIGenerate
)
var (
p project
// files type => path
files = map[int]string{
// init doc
_tplTypeChangeLog: "/CHANGELOG.md",
_tplTypeContributors: "/CONTRIBUTORS.md",
_tplTypeReadme: "/README.md",
// init project
_tplTypeMain: "/cmd/main.go",
_tplTypeDao: "/internal/dao/dao.go",
_tplTypeHTTPServer: "/internal/server/http/http.go",
_tplTypeService: "/internal/service/service.go",
_tplTypeModel: "/internal/model/model.go",
// init config
_tplTypeAppToml: "/configs/application.toml",
_tplTypeMySQLToml: "/configs/mysql.toml",
_tplTypeMCToml: "/configs/memcache.toml",
_tplTypeRedisToml: "/configs/redis.toml",
_tplTypeHTTPToml: "/configs/http.toml",
_tplTypeGRPCToml: "/configs/grpc.toml",
}
// tpls type => content
tpls = map[int]string{
_tplTypeDao: _tplDao,
_tplTypeHTTPServer: _tplHTTPServer,
_tplTypeAPIProto: _tplAPIProto,
_tplTypeAPIGenerate: _tplAPIGenerate,
_tplTypeMain: _tplMain,
_tplTypeChangeLog: _tplChangeLog,
_tplTypeContributors: _tplContributors,
_tplTypeReadme: _tplReadme,
_tplTypeMySQLToml: _tplMySQLToml,
_tplTypeMCToml: _tplMCToml,
_tplTypeRedisToml: _tplRedisToml,
_tplTypeAppToml: _tplAppToml,
_tplTypeHTTPToml: _tplHTTPToml,
_tplTypeModel: _tplModel,
}
)
func validate() (ok bool) {
if !depts[p.Department] {
println("[-d] Invalid department name.")
return
}
if !types[p.Type] {
println("[-t] Invalid project type.")
return
}
if p.Name == "" {
println("[-n] Invalid project name.")
return
}
// TODO: check project name
return true
}
func create() (err error) {
if p.WithGRPC {
files[_tplTypeGRPCServer] = "/internal/server/grpc/server.go"
files[_tplTypeAPIProto] = "/api/api.proto"
files[_tplTypeAPIGenerate] = "/api/generate.go"
tpls[_tplTypeGRPCServer] = _tplGRPCServer
tpls[_tplTypeGRPCToml] = _tplGRPCToml
tpls[_tplTypeService] = _tplGPRCService
} else {
tpls[_tplTypeService] = _tplService
tpls[_tplTypeMain] = delgrpc(_tplMain)
}
if err = os.MkdirAll(p.Path, 0755); err != nil {
return
}
for t, v := range files {
i := strings.LastIndex(v, "/")
if i > 0 {
dir := v[:i]
if err = os.MkdirAll(p.Path+dir, 0755); err != nil {
return
}
}
if err = write(p.Path+v, tpls[t]); err != nil {
return
}
}
if p.WithGRPC {
if err = genpb(); err != nil {
return
}
}
err = updateProwAction()
return
}
func genpb() error {
cmd := exec.Command("go", "generate", p.Path+"/api/generate.go")
return cmd.Run()
}
func delgrpc(tpl string) string {
var buf bytes.Buffer
lines := strings.Split(tpl, "\n")
for _, l := range lines {
if strings.Contains(l, "grpc") {
continue
}
if strings.Contains(l, "warden") {
continue
}
buf.WriteString(l)
buf.WriteString("\n")
}
return buf.String()
}
func write(name, tpl string) (err error) {
data, err := parse(tpl)
if err != nil {
return
}
return ioutil.WriteFile(name, data, 0644)
}
func parse(s string) ([]byte, error) {
t, err := template.New("").Parse(s)
if err != nil {
return nil, err
}
var buf bytes.Buffer
if err = t.Execute(&buf, p); err != nil {
return nil, err
}
return buf.Bytes(), nil
}

455
app/tool/kratos/template.go Normal file
View File

@@ -0,0 +1,455 @@
package main
const (
_tplAppToml = `
# This is a TOML document. Boom
`
_tplMySQLToml = `
[demo]
addr = "127.0.0.1:3306"
dsn = "{user}:{password}@tcp(127.0.0.1:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8"
readDSN = ["{user}:{password}@tcp(127.0.0.2:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8","{user}:{password}@tcp(127.0.0.3:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8,utf8mb4"]
active = 20
idle = 10
idleTimeout ="4h"
queryTimeout = "200ms"
execTimeout = "300ms"
tranTimeout = "400ms"
`
_tplMCToml = `
demoExpire = "24h"
[demo]
name = "{{.Name}}"
proto = "tcp"
addr = "127.0.0.1:11211"
active = 50
idle = 10
dialTimeout = "100ms"
readTimeout = "200ms"
writeTimeout = "300ms"
idleTimeout = "80s"
`
_tplRedisToml = `
demoExpire = "24h"
[demo]
name = "{{.Name}}"
proto = "tcp"
addr = "127.0.0.1:6389"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
`
_tplHTTPToml = `
[server]
addr = "0.0.0.0:8000"
timeout = "1s"
`
_tplGRPCToml = `
[server]
addr = "0.0.0.0:9000"
timeout = "1s"
`
_tplChangeLog = `### v1.0.0
1. 上线功能xxx
`
_tplMain = `package main
import (
"context"
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/{{.Type}}/{{.Department}}/{{.Name}}/internal/server/grpc"
"go-common/app/{{.Type}}/{{.Department}}/{{.Name}}/internal/server/http"
"go-common/app/{{.Type}}/{{.Department}}/{{.Name}}/internal/service"
"go-common/library/conf/paladin"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
)
func main() {
flag.Parse()
if err := paladin.Init(); err != nil {
panic(err)
}
log.Init(nil) // debug flag: log.dir={path}
defer log.Close()
log.Info("{{.Name}}-{{.Type}} start")
ecode.Init(nil)
svc := service.New()
grpcSrv := grpc.New(svc)
httpSrv := http.New(svc)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
ctx, _ := context.WithTimeout(context.Background(), 35*time.Second)
grpcSrv.Shutdown(ctx)
httpSrv.Shutdown(ctx)
log.Info("{{.Name}}-{{.Type}} exit")
svc.Close()
time.Sleep(time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}
`
_tplContributors = `# Owner
{{.Owner}}
# Author
# Reviewer
`
_tplDao = `package dao
import (
"context"
"time"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/conf/paladin"
"go-common/library/database/sql"
"go-common/library/log"
xtime "go-common/library/time"
)
// Dao dao.
type Dao struct {
db *sql.DB
redis *redis.Pool
redisExpire int32
mc *memcache.Pool
mcExpire int32
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}
// New new a dao and return.
func New() (dao *Dao) {
var (
dc struct {
Demo *sql.Config
}
rc struct {
Demo *redis.Config
DemoExpire xtime.Duration
}
mc struct {
Demo *memcache.Config
DemoExpire xtime.Duration
}
)
checkErr(paladin.Get("mysql.toml").UnmarshalTOML(&dc))
checkErr(paladin.Get("redis.toml").UnmarshalTOML(&rc))
checkErr(paladin.Get("memcache.toml").UnmarshalTOML(&mc))
dao = &Dao{
// mysql
db: sql.NewMySQL(dc.Demo),
// redis
redis: redis.NewPool(rc.Demo),
redisExpire: int32(time.Duration(rc.DemoExpire) / time.Second),
// memcache
mc: memcache.NewPool(mc.Demo),
mcExpire: int32(time.Duration(mc.DemoExpire) / time.Second),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
d.mc.Close()
d.redis.Close()
d.db.Close()
}
// Ping ping the resource.
func (d *Dao) Ping(ctx context.Context) (err error) {
if err = d.pingMC(ctx); err != nil {
return
}
if err = d.pingRedis(ctx); err != nil {
return
}
return d.db.Ping(ctx)
}
func (d *Dao) pingMC(ctx context.Context) (err error) {
conn := d.mc.Get(ctx)
defer conn.Close()
if err = conn.Set(&memcache.Item{Key: "ping", Value: []byte("pong"), Expiration: 0}); err != nil {
log.Error("conn.Set(PING) error(%v)", err)
}
return
}
func (d *Dao) pingRedis(ctx context.Context) (err error) {
conn := d.redis.Get(ctx)
defer conn.Close()
if _, err = conn.Do("SET", "ping", "pong"); err != nil {
log.Error("conn.Set(PING) error(%v)", err)
}
return
}
`
_tplReadme = `# {{.Name}}-{{.Type}}
## 项目简介
1.
## 编译环境
## 依赖包
## 编译执行
`
_tplService = `package service
import (
"context"
"go-common/app/{{.Type}}/{{.Department}}/{{.Name}}/internal/dao"
"go-common/library/conf/paladin"
)
// Service service.
type Service struct {
ac *paladin.Map
dao *dao.Dao
}
// New new a service and return.
func New() (s *Service) {
var ac = new(paladin.TOML)
if err := paladin.Watch("application.toml", ac); err != nil {
panic(err)
}
s = &Service{
ac: ac,
dao: dao.New(),
}
return s
}
// Ping ping the resource.
func (s *Service) Ping(ctx context.Context) (err error) {
return s.dao.Ping(ctx)
}
// Close close the resource.
func (s *Service) Close() {
s.dao.Close()
}
`
_tplGPRCService = `package service
import (
"context"
"fmt"
pb "go-common/app/{{.Type}}/{{.Department}}/{{.Name}}/api"
"go-common/app/{{.Type}}/{{.Department}}/{{.Name}}/internal/dao"
"go-common/library/conf/paladin"
"github.com/golang/protobuf/ptypes/empty"
)
// Service service.
type Service struct {
ac *paladin.Map
dao *dao.Dao
}
// New new a service and return.
func New() (s *Service) {
var ac = new(paladin.TOML)
if err := paladin.Watch("application.toml", ac); err != nil {
panic(err)
}
s = &Service{
ac: ac,
dao: dao.New(),
}
return s
}
// SayHello grpc demo func.
func (s *Service) SayHello(ctx context.Context, req *pb.HelloReq) (reply *empty.Empty, err error) {
reply = new(empty.Empty)
fmt.Printf("hello %s", req.Name)
return
}
// Ping ping the resource.
func (s *Service) Ping(ctx context.Context) (err error) {
return s.dao.Ping(ctx)
}
// Close close the resource.
func (s *Service) Close() {
s.dao.Close()
}
`
_tplHTTPServer = `package http
import (
"net/http"
"go-common/app/{{.Type}}/{{.Department}}/{{.Name}}/internal/service"
"go-common/library/conf/paladin"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
svc *service.Service
)
// New new a bm server.
func New(s *service.Service) (engine *bm.Engine) {
var(
hc struct {
Server *bm.ServerConfig
}
)
if err := paladin.Get("http.toml").UnmarshalTOML(&hc); err != nil {
if err != paladin.ErrNotExist {
panic(err)
}
}
svc = s
engine = bm.DefaultServer(hc.Server)
initRouter(engine, verify.New(nil))
if err := engine.Start(); err != nil {
panic(err)
}
return
}
func initRouter(e *bm.Engine, v *verify.Verify) {
e.Ping(ping)
e.Register(register)
g := e.Group("/x/{{.Name}}")
{
g.GET("/start", v.Verify, howToStart)
}
}
func ping(ctx *bm.Context) {
if err := svc.Ping(ctx); err != nil {
log.Error("ping error(%v)", err)
ctx.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}
// example for http request handler.
func howToStart(c *bm.Context) {
c.String(0, "Golang 大法好 !!!")
}
`
_tplAPIProto = `// 定义项目 API 的 proto 文件 可以同时描述 gRPC 和 HTTP API
// protobuf 文件参考:
// - https://developers.google.com/protocol-buffers/
// - http://info.bilibili.co/display/documentation/gRPC+Proto
// protobuf 生成 HTTP 工具:
// - http://git.bilibili.co/platform/go-common/tree/master/app/tool/protoc-gen-bm
// gRPC Golang Model:
// - http://info.bilibili.co/display/documentation/gRPC+Golang+Model
// gRPC Golang Warden Gen:
// - http://info.bilibili.co/display/documentation/gRPC+Golang+Warden+Gen
// gRPC http 调试工具(无需pb文件):
// - http://info.bilibili.co/pages/viewpage.action?pageId=12877366
// grpc 命令行调试工具(无需pb文件):
// - http://info.bilibili.co/pages/viewpage.action?pageId=11869411
syntax = "proto3";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "google/protobuf/empty.proto";
// package 命名使用 {discovery_id}.{version} 的方式, version 形如 v1, v2, v1beta ..
// NOTE: 不知道的 discovery_id 请询问大佬, 新项目找大佬申请 discovery_id先到先得抢注
// e.g. account.service.v1
package demo.service.v1;
// NOTE: 最后请删除这些无用的注释 (゜-゜)つロ
option go_package = "api";
// do not generate getXXX() method
option (gogoproto.goproto_getters_all) = false;
service Demo {
rpc SayHello (HelloReq) returns (.google.protobuf.Empty);
}
message HelloReq {
string name = 1 [(gogoproto.moretags)='form:"name" validate:"required"'];
}
`
_tplAPIGenerate = `package api
// 生成 gRPC 代码
//go:generate $GOPATH/src/go-common/app/tool/warden/protoc.sh
`
_tplModel = `package model
`
_tplGRPCServer = `package grpc
import (
pb "go-common/app/{{.Type}}/{{.Department}}/{{.Name}}/api"
"go-common/app/{{.Type}}/{{.Department}}/{{.Name}}/internal/service"
"go-common/library/net/rpc/warden"
"go-common/library/conf/paladin"
)
// New new a grpc server.
func New(svc *service.Service) *warden.Server {
var rc struct {
Server *warden.ServerConfig
}
if err := paladin.Get("grpc.toml").UnmarshalTOML(&rc); err != nil {
if err != paladin.ErrNotExist {
panic(err)
}
}
ws := warden.NewServer(rc.Server)
pb.RegisterDemoServer(ws.Server(), svc)
ws, err := ws.Start()
if err != nil {
panic(err)
}
return ws
}
`
)

72
app/tool/kratos/update.go Normal file
View File

@@ -0,0 +1,72 @@
package main
import (
"fmt"
"io"
"os"
"os/exec"
"strings"
"github.com/kr/pty"
"github.com/urfave/cli"
)
func runUpdate(root, param string) {
cmd := exec.Command("make", "bazel-update")
cmd.Dir = param
cmd.Env = append(cmd.Env, "KRATOS_ROOT="+root, "GOPATH="+root, "PATH="+os.Getenv("PATH"))
f, err := pty.Start(cmd)
if err != nil {
panic(err)
}
io.Copy(os.Stdout, f)
}
func runProwUpdate(root, param string) {
cmd := exec.Command("make", "prow-update")
cmd.Dir = param
cmd.Env = append(cmd.Env, "KRATOS_ROOT="+root, "GOPATH="+root, "PATH="+os.Getenv("PATH"))
f, err := pty.Start(cmd)
if err != nil {
panic(err)
}
io.Copy(os.Stdout, f)
}
func updateAction(c *cli.Context) error {
pwd, err := os.Getwd()
if err != nil {
return err
}
index := strings.Index(pwd, "go-common")
if index == -1 {
fmt.Println("not in go-common")
os.Exit(1)
}
path := strings.Split(pwd[:index-1], "/")
result := strings.Split(pwd[index:], "/")
path = append(path, result[0])
runPath := strings.Join(path, "/")
runUpdate(strings.Join(path[:len(path)-2], "/"), runPath)
return nil
}
func updateProwAction() error {
pwd, err := os.Getwd()
if err != nil {
return err
}
index := strings.Index(pwd, "go-common")
if index == -1 {
fmt.Println("not in go-common")
os.Exit(1)
}
path := strings.Split(pwd[:index-1], "/")
result := strings.Split(pwd[index:], "/")
path = append(path, result[0])
runPath := strings.Join(path, "/")
runProwUpdate(strings.Join(path[:len(path)-2], "/"), runPath)
return nil
}

152
app/tool/kratos/upgrade.go Normal file
View File

@@ -0,0 +1,152 @@
package main
import (
"crypto/sha256"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"path/filepath"
"runtime"
"strconv"
"time"
"github.com/urfave/cli"
)
type archs struct {
LinuxAmd64 string `json:"linux-amd64"`
DarwinAmd64 string `json:"darwin_amd64"`
}
type internalInfo struct {
version int
maxVersion int
up map[string]archs
}
func upgradeAction(c *cli.Context) error {
upgrade()
return nil
}
func copyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
if err != nil {
return err
}
out.Chmod(0755)
return out.Close()
}
func updateFile(sha, url string) {
ex, err := os.Executable()
if err != nil {
fmt.Printf("fail to get download path")
return
}
fpath := filepath.Dir(ex)
tmpFilepath := fpath + "/kratos.tmp"
// Get the data
resp, err := http.Get(url)
if err != nil {
fmt.Printf("fail to download file: %v", err)
return
}
out, err := os.OpenFile(tmpFilepath, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666)
if err != nil {
log.Fatal(err)
}
_, err = io.Copy(out, resp.Body)
if err != nil {
fmt.Println("fail to write download file")
return
}
out.Close()
resp.Body.Close()
f, err := os.Open(tmpFilepath)
if err != nil {
fmt.Println("sha256 fail to open download file")
return
}
h := sha256.New()
_, err = io.Copy(h, f)
if err != nil {
fmt.Println("sha256 fail to init")
return
}
getsha := fmt.Sprintf("%x", h.Sum(nil))
if getsha != sha {
fmt.Printf("sha256 wrong. expect %s get %s", sha, getsha)
return
}
f.Close()
err = copyFile(tmpFilepath, fpath+"/kratos")
if err != nil {
fmt.Println("fail to install kratos")
return
}
err = os.Remove(tmpFilepath)
if err != nil {
fmt.Println("fail to remove tmp kratos")
return
}
fmt.Println("Download successfully!")
}
func upgrade() error {
target := make(map[string]archs)
client := &http.Client{Timeout: 10 * time.Second}
r, err := client.Get("http://bazel-cabin.bilibili.co/kratos/" + Channel + "/package.json")
if err != nil {
return err
}
defer r.Body.Close()
json.NewDecoder(r.Body).Decode(&target)
info := internalInfo{}
info.up = target
if info.version, err = strconv.Atoi(Version); err != nil {
return err
}
for k := range target {
ver, err := strconv.Atoi(k)
if err != nil {
return err
}
if info.maxVersion < ver {
info.maxVersion = ver
}
}
if info.maxVersion > info.version {
fmt.Printf("kratos %d -> %d\n", info.version, info.maxVersion)
switch runtime.GOOS + "-" + runtime.GOARCH {
case "linux-amd64":
updateFile(info.up[strconv.Itoa(info.maxVersion)].LinuxAmd64, "http://bazel-cabin.bilibili.co/kratos/"+Channel+"/"+strconv.Itoa(info.maxVersion)+"/linux-amd64/kratos")
case "darwin-amd64":
updateFile(info.up[strconv.Itoa(info.maxVersion)].DarwinAmd64, "http://bazel-cabin.bilibili.co/kratos/"+Channel+"/"+strconv.Itoa(info.maxVersion)+"/darwin-amd64/kratos")
default:
fmt.Println("not support this operate system")
}
} else {
fmt.Println("Already up to the newest.")
}
return nil
}

View File

@@ -0,0 +1 @@
package main

View File

@@ -0,0 +1,56 @@
package main
import (
"bytes"
"runtime"
"text/template"
)
var (
// GitCommit is git commit
GitCommit = "library-import"
// Version is version
Version = "library-import"
// BuildTime is BuildTime
BuildTime = "library-import"
// Channel is Channel
Channel = "library-import"
)
// VersionOptions include version
type VersionOptions struct {
GitCommit string
Version string
BuildTime string
GoVersion string
Os string
Arch string
Channel string
}
var versionTemplate = ` Version: {{.Version}}
Go version: {{.GoVersion}}
Git commit: {{.GitCommit}}
Built: {{.BuildTime}}
OS/Arch: {{.Os}}/{{.Arch}}
Channel: {{.Channel}}
`
func getVersion() string {
var doc bytes.Buffer
vo := VersionOptions{
GitCommit: GitCommit,
Version: Version,
BuildTime: BuildTime,
GoVersion: runtime.Version(),
Os: runtime.GOOS,
Arch: runtime.GOARCH,
Channel: Channel,
}
tmpl, _ := template.New("version").Parse(versionTemplate)
tmpl.Execute(&doc, vo)
return doc.String()
}