mirror of
https://github.com/go-kratos/kratos.git
synced 2025-03-17 21:07:54 +02:00
add kratos tool (#4)
This commit is contained in:
parent
d0b98db00c
commit
7fc7de272c
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
go.sum
|
4
go.mod
4
go.mod
@ -1,15 +1,19 @@
|
||||
module github.com/bilibili/Kratos
|
||||
|
||||
require (
|
||||
github.com/fatih/color v1.7.0
|
||||
github.com/go-playground/locales v0.12.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.16.0 // indirect
|
||||
github.com/gogo/protobuf v1.2.0
|
||||
github.com/golang/protobuf v1.2.0
|
||||
github.com/kr/pty v1.1.4
|
||||
github.com/leodido/go-urn v1.1.0 // indirect
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/prometheus/client_golang v0.9.2
|
||||
github.com/stretchr/testify v1.3.0
|
||||
github.com/urfave/cli v1.20.0
|
||||
google.golang.org/grpc v1.18.0
|
||||
gopkg.in/AlecAivazis/survey.v1 v1.8.2
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
|
||||
gopkg.in/go-playground/validator.v9 v9.26.0
|
||||
)
|
||||
|
55
go.sum
55
go.sum
@ -1,55 +0,0 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
|
||||
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
|
||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740=
|
||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8=
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE=
|
||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.18.0 h1:IZl7mfBGfbhYx2p2rKRtYgDFw6SBz+kclmxYrCksPPA=
|
||||
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v9 v9.26.0 h1:2NPPsBpD0ZoxshmLWewQru8rWmbT5JqSzz9D1ZrAjYQ=
|
||||
gopkg.in/go-playground/validator.v9 v9.26.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
14
tool/kratos/README.MD
Normal file
14
tool/kratos/README.MD
Normal file
@ -0,0 +1,14 @@
|
||||
# kratos
|
||||
|
||||
## 项目简介
|
||||
Kratos 工具
|
||||
|
||||
## 安装
|
||||
|
||||
`go get -u github.com/bilibili/Kratos/tool/kratos`
|
||||
|
||||
## 使用说明
|
||||
|
||||
### 参数
|
||||
|
||||
kratos -h
|
22
tool/kratos/build.go
Normal file
22
tool/kratos/build.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/kr/pty"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func buildAction(c *cli.Context) error {
|
||||
args := append([]string{"build"}, c.Args()...)
|
||||
// fmt.Println(args)
|
||||
cmd := exec.Command("go", args...)
|
||||
f, err := pty.Start(cmd)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
io.Copy(os.Stdout, f)
|
||||
return nil
|
||||
}
|
27
tool/kratos/doc.go
Normal file
27
tool/kratos/doc.go
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
kratos 是Kratos的工具链,提供新项目创建,代码生成等功能
|
||||
|
||||
kartos build 本目录之下局部编译,根目录全量编译
|
||||
NAME:
|
||||
kratos 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:
|
||||
-n value 项目名
|
||||
-o value 维护人
|
||||
--grpc 是否是GRPC
|
||||
|
||||
EXAMPLE:
|
||||
kratos init -n demo -o kratos
|
||||
*/
|
||||
package main
|
155
tool/kratos/init.go
Normal file
155
tool/kratos/init.go
Normal file
@ -0,0 +1,155 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
"gopkg.in/AlecAivazis/survey.v1"
|
||||
)
|
||||
|
||||
const (
|
||||
_textModeFastInit = "一键初始化项目"
|
||||
_textModeInteraction = "自定义项目参数"
|
||||
_textYes = "是"
|
||||
_textNo = "否"
|
||||
)
|
||||
|
||||
func runInit(ctx *cli.Context) (err error) {
|
||||
if ctx.NumFlags() == 0 {
|
||||
if err = interact(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if !validate() {
|
||||
return nil
|
||||
}
|
||||
if err = create(); err != nil {
|
||||
fmt.Println("项目初始化失败: ", err.Error())
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("项目[%s]初始化成功!\n", p.Path)
|
||||
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 < 1 {
|
||||
// 至少要有一个目录层级:项目名
|
||||
return
|
||||
}
|
||||
name := ps[plen-1]
|
||||
if name == "" {
|
||||
return
|
||||
}
|
||||
p.Name = name
|
||||
p.Path = pwd
|
||||
return true
|
||||
}
|
||||
|
||||
func goPath() (gp string) {
|
||||
gopaths := strings.Split(os.Getenv("GOPATH"), ":")
|
||||
if len(gopaths) == 1 {
|
||||
return gopaths[0]
|
||||
}
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
abspwd, err := filepath.Abs(pwd)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, gopath := range gopaths {
|
||||
absgp, err := filepath.Abs(gopath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if strings.HasPrefix(abspwd, absgp) {
|
||||
return absgp
|
||||
}
|
||||
}
|
||||
return build.Default.GOPATH
|
||||
}
|
||||
|
||||
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 {
|
||||
fmt.Println("快速初始化失败!")
|
||||
}
|
||||
return
|
||||
case _textModeInteraction:
|
||||
// go on
|
||||
default:
|
||||
return
|
||||
}
|
||||
qs := []*survey.Question{
|
||||
{
|
||||
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,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "here",
|
||||
Prompt: &survey.Select{
|
||||
Message: "是否当前目录?默认为GOPATH下",
|
||||
Options: []string{_textYes, _textNo},
|
||||
Default: _textYes,
|
||||
},
|
||||
},
|
||||
}
|
||||
ans := struct {
|
||||
Name string
|
||||
Owner string
|
||||
UseGRPC string
|
||||
Here string
|
||||
}{}
|
||||
if err = survey.Ask(qs, &ans); err != nil {
|
||||
return
|
||||
}
|
||||
p.Name = ans.Name
|
||||
p.Owner = ans.Owner
|
||||
if ans.UseGRPC == _textYes {
|
||||
p.WithGRPC = true
|
||||
}
|
||||
if ans.UseGRPC == _textYes {
|
||||
p.WithGRPC = true
|
||||
}
|
||||
if ans.Here == _textYes {
|
||||
p.Here = true
|
||||
}
|
||||
return
|
||||
}
|
72
tool/kratos/main.go
Normal file
72
tool/kratos/main.go
Normal file
@ -0,0 +1,72 @@
|
||||
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: "kratos build",
|
||||
Action: buildAction,
|
||||
},
|
||||
{
|
||||
Name: "init",
|
||||
Aliases: []string{"i"},
|
||||
Usage: "create new project",
|
||||
Flags: []cli.Flag{
|
||||
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: "tool",
|
||||
Aliases: []string{"t"},
|
||||
Usage: "kratos tool",
|
||||
Action: toolAction,
|
||||
},
|
||||
{
|
||||
Name: "version",
|
||||
Aliases: []string{"v"},
|
||||
Usage: "kratos version",
|
||||
Action: func(c *cli.Context) error {
|
||||
fmt.Println(getVersion())
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "self-upgrade",
|
||||
Usage: "kratos self-upgrade",
|
||||
Action: upgradeAction,
|
||||
},
|
||||
}
|
||||
err := app.Run(os.Args)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
174
tool/kratos/project.go
Normal file
174
tool/kratos/project.go
Normal file
@ -0,0 +1,174 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// project project config
|
||||
type project struct {
|
||||
Name string
|
||||
Owner string
|
||||
Path string
|
||||
WithGRPC bool
|
||||
Here 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 p.Name == "" {
|
||||
fmt.Println("[-n] Invalid project name.")
|
||||
return
|
||||
}
|
||||
if p.Path == "" {
|
||||
if p.Here {
|
||||
pwd, _ := os.Getwd()
|
||||
p.Path = path.Join(pwd, p.Name)
|
||||
} else {
|
||||
p.Path = path.Join(goPath(), "src", p.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
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
451
tool/kratos/template.go
Normal file
451
tool/kratos/template.go
Normal file
@ -0,0 +1,451 @@
|
||||
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 = `## {{.Name}}
|
||||
|
||||
### v1.0.0
|
||||
1. 上线功能xxx
|
||||
`
|
||||
_tplMain = `package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"{{.Name}}/internal/server/grpc"
|
||||
"{{.Name}}/internal/server/http"
|
||||
"{{.Name}}/internal/service"
|
||||
"github.com/bilibili/Kratos/pkg/conf/paladin"
|
||||
"github.com/bilibili/Kratos/pkg/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}} start")
|
||||
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, cancel := context.WithTimeout(context.Background(), 35*time.Second)
|
||||
defer cancel()
|
||||
grpcSrv.Shutdown(ctx)
|
||||
httpSrv.Shutdown(ctx)
|
||||
log.Info("{{.Name}} exit")
|
||||
svc.Close()
|
||||
time.Sleep(time.Second)
|
||||
return
|
||||
case syscall.SIGHUP:
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
_tplContributors = `# Owner
|
||||
{{.Owner}}
|
||||
|
||||
# Author
|
||||
|
||||
# Reviewer
|
||||
`
|
||||
_tplDao = `package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/bilibili/Kratos/pkg/cache/memcache"
|
||||
"github.com/bilibili/Kratos/pkg/cache/redis"
|
||||
"github.com/bilibili/Kratos/pkg/conf/paladin"
|
||||
"github.com/bilibili/Kratos/pkg/database/sql"
|
||||
"github.com/bilibili/Kratos/pkg/log"
|
||||
xtime "github.com/bilibili/Kratos/pkg/time"
|
||||
)
|
||||
|
||||
// Dao dao.
|
||||
type Dao struct {
|
||||
db *sql.DB
|
||||
redis *redis.Pool
|
||||
redisExpire int32
|
||||
mc *memcache.Memcache
|
||||
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.New(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) {
|
||||
if err = d.mc.Set(ctx, &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}}
|
||||
|
||||
## 项目简介
|
||||
1.
|
||||
|
||||
## 编译环境
|
||||
|
||||
|
||||
## 依赖包
|
||||
|
||||
|
||||
## 编译执行
|
||||
`
|
||||
_tplService = `package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"{{.Name}}/internal/dao"
|
||||
"github.com/bilibili/Kratos/pkg/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 "{{.Name}}/api"
|
||||
"{{.Name}}/internal/dao"
|
||||
"github.com/bilibili/Kratos/pkg/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"
|
||||
|
||||
"{{.Name}}/internal/service"
|
||||
"github.com/bilibili/Kratos/pkg/conf/paladin"
|
||||
"github.com/bilibili/Kratos/pkg/log"
|
||||
bm "github.com/bilibili/Kratos/pkg/net/http/blademaster"
|
||||
"github.com/bilibili/Kratos/pkg/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("/{{.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/
|
||||
// - TODO:待补充文档URL
|
||||
// protobuf 生成 HTTP 工具:
|
||||
// - TODO:待补充文档URL
|
||||
// gRPC Golang Model:
|
||||
// - TODO:待补充文档URL
|
||||
// gRPC Golang Warden Gen:
|
||||
// - TODO:待补充文档URL
|
||||
// gRPC http 调试工具(无需pb文件):
|
||||
// - TODO:待补充文档URL
|
||||
// grpc 命令行调试工具(无需pb文件):
|
||||
// - TODO:待补充文档URL
|
||||
syntax = "proto3";
|
||||
|
||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
// package 命名使用 {appid}.{version} 的方式, version 形如 v1, v2 ..
|
||||
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 TODO:待完善工具protoc.sh
|
||||
`
|
||||
_tplModel = `package model
|
||||
`
|
||||
_tplGRPCServer = `package grpc
|
||||
|
||||
import (
|
||||
pb "{{.Name}}/api"
|
||||
"{{.Name}}/internal/service"
|
||||
"github.com/bilibili/Kratos/pkg/conf/paladin"
|
||||
"github.com/bilibili/Kratos/pkg/net/rpc/warden"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
`
|
||||
)
|
175
tool/kratos/tool.go
Normal file
175
tool/kratos/tool.go
Normal file
@ -0,0 +1,175 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func toolAction(c *cli.Context) (err error) {
|
||||
if c.NArg() == 0 {
|
||||
sort.Slice(toolIndexs, func(i, j int) bool { return toolIndexs[i].BuildTime.After(toolIndexs[j].BuildTime) })
|
||||
for _, t := range toolIndexs {
|
||||
updateTime := t.BuildTime.Format("2006/01/02")
|
||||
fmt.Printf("%s%s: %s %s (%s) [%s]\n", color.HiMagentaString(t.Name), getNotice(t), color.HiCyanString(t.Summary), t.URL, t.Author, updateTime)
|
||||
}
|
||||
fmt.Println("\n执行 install 安装程序 如: kratos tool install demo")
|
||||
fmt.Println("执行 工具名称 运行程序 如: kratos tool demo")
|
||||
fmt.Println("\n安装全部工具: kratos tool install all")
|
||||
return
|
||||
}
|
||||
if c.Args().First() == "install" {
|
||||
name := c.Args().Get(1)
|
||||
if name == "all" {
|
||||
installAll()
|
||||
} else {
|
||||
install(name)
|
||||
}
|
||||
return
|
||||
}
|
||||
name := c.Args().First()
|
||||
for _, t := range toolIndexs {
|
||||
if name == t.Name {
|
||||
if !t.installed() || t.updated() {
|
||||
install(name)
|
||||
}
|
||||
pwd, _ := os.Getwd()
|
||||
var args []string
|
||||
if c.NArg() > 1 {
|
||||
args = []string(c.Args())[1:]
|
||||
}
|
||||
runTool(t.Name, pwd, t.toolPath(), args)
|
||||
return
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "还未安装 %s\n", name)
|
||||
return
|
||||
}
|
||||
|
||||
func upgradeAction(c *cli.Context) error {
|
||||
install("kratos")
|
||||
return nil
|
||||
}
|
||||
|
||||
func install(name string) {
|
||||
if name == "" {
|
||||
fmt.Fprintf(os.Stderr, color.HiRedString("请填写要安装的工具名称\n"))
|
||||
return
|
||||
}
|
||||
for _, t := range toolIndexs {
|
||||
if name == t.Name {
|
||||
t.install()
|
||||
return
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, color.HiRedString("安装失败 找不到 %s\n", name))
|
||||
return
|
||||
}
|
||||
|
||||
func installAll() {
|
||||
for _, t := range toolIndexs {
|
||||
if t.Install != "" {
|
||||
t.install()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getNotice(t *Tool) (notice string) {
|
||||
if !t.supportOS() || t.Install == "" {
|
||||
return
|
||||
}
|
||||
notice = color.HiGreenString("(未安装)")
|
||||
if f, err := os.Stat(t.toolPath()); err == nil {
|
||||
notice = color.HiBlueString("(已安装)")
|
||||
if t.BuildTime.After(f.ModTime()) {
|
||||
notice = color.RedString("(有更新)")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func runTool(name, dir, cmd string, args []string) (err error) {
|
||||
toolCmd := &exec.Cmd{
|
||||
Path: cmd,
|
||||
Args: append([]string{cmd}, args...),
|
||||
Dir: dir,
|
||||
Stdin: os.Stdin,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
Env: os.Environ(),
|
||||
}
|
||||
if filepath.Base(cmd) == cmd {
|
||||
var lp string
|
||||
if lp, err = exec.LookPath(cmd); err == nil {
|
||||
toolCmd.Path = lp
|
||||
}
|
||||
}
|
||||
if err = toolCmd.Run(); err != nil {
|
||||
if e, ok := err.(*exec.ExitError); !ok || !e.Exited() {
|
||||
fmt.Fprintf(os.Stderr, "install %s: %v\n", name, err)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Tool .
|
||||
type Tool struct {
|
||||
Name string `json:"name"`
|
||||
BuildTime time.Time `json:"build_time"`
|
||||
Install string `json:"install"`
|
||||
Summary string `json:"summary"`
|
||||
Platform []string `json:"platform"`
|
||||
Author string `json:"author"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
func (t Tool) supportOS() bool {
|
||||
for _, p := range t.Platform {
|
||||
if strings.ToLower(p) == runtime.GOOS {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t Tool) install() {
|
||||
if t.Install == "" {
|
||||
fmt.Fprintf(os.Stderr, color.RedString("%s: 自动安装失败 详情请查看文档 %s\n", t.Name, t.URL))
|
||||
return
|
||||
}
|
||||
cmds := strings.Split(t.Install, " ")
|
||||
if len(cmds) > 0 {
|
||||
if err := runTool(t.Name, t.toolPath(), cmds[0], cmds[1:]); err == nil {
|
||||
color.Green("%s: 安装成功!", t.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t Tool) updated() bool {
|
||||
if !t.supportOS() || t.Install == "" {
|
||||
return false
|
||||
}
|
||||
if f, err := os.Stat(t.toolPath()); err == nil {
|
||||
if t.BuildTime.After(f.ModTime()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t Tool) toolPath() string {
|
||||
return filepath.Join(goPath(), "bin", t.Name)
|
||||
}
|
||||
|
||||
func (t Tool) installed() bool {
|
||||
_, err := os.Stat(t.toolPath())
|
||||
return err == nil
|
||||
}
|
15
tool/kratos/tool_index.go
Normal file
15
tool/kratos/tool_index.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
var toolIndexs = []*Tool{
|
||||
&Tool{
|
||||
Name: "kratos",
|
||||
BuildTime: time.Date(2019, 4, 2, 0, 0, 0, 0, time.Local),
|
||||
Install: "go get -u github.com/bilibili/Kratos/tool/kratos",
|
||||
Summary: "Kratos工具集本体",
|
||||
Platform: []string{"darwin", "linux", "windows"},
|
||||
Author: "kratos",
|
||||
URL: "wiki",
|
||||
},
|
||||
}
|
44
tool/kratos/version.go
Normal file
44
tool/kratos/version.go
Normal file
@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"runtime"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var (
|
||||
// Version is version
|
||||
Version = "0.0.1"
|
||||
// BuildTime is BuildTime
|
||||
BuildTime = "2019/04/03"
|
||||
)
|
||||
|
||||
// VersionOptions include version
|
||||
type VersionOptions struct {
|
||||
GitCommit string
|
||||
Version string
|
||||
BuildTime string
|
||||
GoVersion string
|
||||
Os string
|
||||
Arch string
|
||||
}
|
||||
|
||||
var versionTemplate = ` Version: {{.Version}}
|
||||
Go version: {{.GoVersion}}
|
||||
Built: {{.BuildTime}}
|
||||
OS/Arch: {{.Os}}/{{.Arch}}
|
||||
`
|
||||
|
||||
func getVersion() string {
|
||||
var doc bytes.Buffer
|
||||
vo := VersionOptions{
|
||||
Version: Version,
|
||||
BuildTime: BuildTime,
|
||||
GoVersion: runtime.Version(),
|
||||
Os: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
}
|
||||
tmpl, _ := template.New("version").Parse(versionTemplate)
|
||||
tmpl.Execute(&doc, vo)
|
||||
return doc.String()
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user