You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
212 lines
4.5 KiB
212 lines
4.5 KiB
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"go/build"
|
|
"os"
|
|
"os/exec"
|
|
"path"
|
|
"path/filepath"
|
|
"runtime"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/fatih/color"
|
|
"github.com/urfave/cli"
|
|
)
|
|
|
|
const (
|
|
toolDoc = "https://github.com/bilibili/kratos/blob/master/doc/wiki-cn/kratos-tool.md"
|
|
)
|
|
|
|
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 Author(%s) [%s]\n", color.HiMagentaString(t.Name), getNotice(t), color.HiCyanString(t.Summary), t.Author, updateTime)
|
|
}
|
|
fmt.Println("\n安装工具: kratos tool install demo")
|
|
fmt.Println("执行工具: kratos tool demo")
|
|
fmt.Println("安装全部工具: kratos tool install all")
|
|
fmt.Println("\n详细文档:", toolDoc)
|
|
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, "运行 %s 出错: %v\n", name, err)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// Tool .
|
|
type Tool struct {
|
|
Name string `json:"name"`
|
|
Alias string `json:"alias"`
|
|
BuildTime time.Time `json:"build_time"`
|
|
Install string `json:"install"`
|
|
Summary string `json:"summary"`
|
|
Platform []string `json:"platform"`
|
|
Author string `json:"author"`
|
|
}
|
|
|
|
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, toolDoc))
|
|
return
|
|
}
|
|
fmt.Println(t.Install)
|
|
cmds := strings.Split(t.Install, " ")
|
|
if len(cmds) > 0 {
|
|
if err := runTool(t.Name, path.Dir(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 {
|
|
if gobin := os.Getenv("GOBIN");len(gobin) > 0 {
|
|
return filepath.Join(gobin, t.Alias)
|
|
}else{
|
|
return filepath.Join(gopath(), "bin", t.Alias)
|
|
}
|
|
}
|
|
|
|
func (t Tool) installed() bool {
|
|
_, err := os.Stat(t.toolPath())
|
|
return err == nil
|
|
}
|
|
|
|
func gopath() (gp string) {
|
|
gopaths := strings.Split(os.Getenv("GOPATH"), ":")
|
|
if len(gopaths) == 1 {
|
|
return gopaths[0]
|
|
}
|
|
pwd, err := os.Getwd()
|
|
if err != nil {
|
|
return
|
|
}
|
|
abspwd, err := filepath.Abs(pwd)
|
|
if err != nil {
|
|
return
|
|
}
|
|
for _, gopath := range gopaths {
|
|
absgp, err := filepath.Abs(gopath)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if strings.HasPrefix(abspwd, absgp) {
|
|
return absgp
|
|
}
|
|
}
|
|
return build.Default.GOPATH
|
|
}
|
|
|